psi-0.14/0000755000175000017500000000000011321133207010324 5ustar janjanpsi-0.14/iconsets/0000755000175000017500000000000011305557613012170 5ustar janjanpsi-0.14/iconsets/system/0000755000175000017500000000000011305557613013514 5ustar janjanpsi-0.14/iconsets/system/default/0000755000175000017500000000000011305557613015140 5ustar janjanpsi-0.14/iconsets/system/default/download.png0000644000175000017500000000102411305557613017452 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% XpI0v2?#6ur:fQgP0D S-@t) {Ani럿hb?~1< H #r,-2x vLSBL;]@ PbDF!b3"bW@[w~H,AM9֨ F\ d='؄;Lĸ!.7y@C׼)?,O6Ċgc\vÁm Crystal - System (default) 1.0 Crystal System Iconset 2005-11-23 http://psi.affinix.com Jason Kim (Logo and misc. icons) Everaldo Coelho (Crystal icons) psi/appearance appearance.png psi/account account.png psi/statusmsg info.png psi/addContact add.png psi/arrowUp arrow_up.png psi/arrowDown arrow_down.png psi/arrowLeft arrow_left.png psi/arrowRight arrow_right.png psi/profile changeacc.png psi/clearChat chatclear.png psi/compact ok.png psi/disco disco.png psi/events events.png psi/groupChat groupchat.png psi/help help.png psi/history history.png psi/shortcuts shortcuts.png psi/vCard vcard.png psi/jabber jabber.png psi/options options.png psi/toolbars configure_toolbars.png psi/configure-room configure-room.png psi/pgp pgp.png psi/gpg-yes key.png psi/gpg-no key.png psi/keyBad key_bad.png psi/keyUnknown key_unknown.png psi/playSounds play_sounds.png psi/voice play_sounds.png psi/main psimain.png psi/quit quit.png psi/register register.png psi/reload reload.png psi/stop stop.png psi/remove remove.png psi/search search.png psi/status status.png psi/sendMessage send.png psi/start-chat start-chat.png psi/cryptoYes ssl_yes.png psi/cryptoNo ssl_no.png psi/time time.png psi/www url.png psi/xml xml.png psi/logo_16 logo_16.png psi/logo_32 logo_32.png psi/logo_48 logo_48.png psi/logo_64 logo_64.png psi/logo_128 logo_128.png psi/psiLogo psilogo.png psi/gst_logo gstreamer-logo-50.png psi/smile smile.png psi/email send.png psi/ok ok.png psi/done close.png psi/closetab closetab.png psi/cancel cancel.png psi/close close.png psi/apply ok.png psi/info info.png psi/tip tip.png psi/browse browse.png psi/play play.png psi/eye eye_blue.png psi/upload upload.png psi/download download.png psi/filemanager filemanager.png psi/command command.png psi/roster url.png psi/advanced advanced.png psi/show_self self.png psi/show_offline show_offline.png psi/show_away show_away.png psi/show_hidden show_hidden.png psi/publishTune publish_tune.png psi/save filemanager.png psi/whiteboard whiteboarding/whiteboard.png psi/saveBoard whiteboarding/save.png psi/select whiteboarding/select.png psi/translate whiteboarding/translate.png psi/rotate whiteboarding/rotate.png psi/scale whiteboarding/scale.png psi/scroll whiteboarding/scroll.png psi/erase whiteboarding/erase.png psi/drawPaths whiteboarding/draw_paths.png psi/drawLines whiteboarding/draw_lines.png psi/drawEllipses whiteboarding/draw_ellipses.png psi/drawCircles whiteboarding/draw_circles.png psi/drawRectangles whiteboarding/draw_rectangles.png psi/addText whiteboarding/add_text.png psi/addImage whiteboarding/add_image.png psi/bringForwards whiteboarding/bring_forwards.png psi/bringToFront whiteboarding/bring_to_front.png psi/sendBackwards whiteboarding/send_backwards.png psi/sendToBack whiteboarding/send_to_back.png psi/group whiteboarding/group.png psi/ungroup whiteboarding/ungroup.png psi-0.14/iconsets/system/default/reload.png0000644000175000017500000000150011305557613017110 0ustar janjanPNG  IHDRa pHYs ,tIME AbKGDCIDAT8mSKQ/"(Aoك|..BL(ɗQcGA!(fb~hzXNE$tfiMMۜkΝ8{ι~(0JS3 c0˖Se2Qakd|J.p n_Ɠ e¤'yBow ÿGE0lCH9KJJϦ1i[+0Vw͏]:fupAL$kr``j&+OX1= 'Hm,8bMvpoL=IMJ!kbȸIkq-D-d/WU=II}0Bhmwrkk+ᐐd\B(GM0Ӆ_IDATxڅ_HSqǿ۽s.ݝ;r$h. ՞k>CHЋK"ɇcX {t>$8)2 4tKt89G}f2n|>aDBdt:=L]ܬ~Qw +++zAp{S Tjp,+hQ{mmml.naaw040{3 ^G,v6?/Ib6.55Xm PT`/Ʊ[>#(a9V}=Ib[J܁DT谞$0<4.\^߀(#"ܭTdߏ pP4bXR2\bY Ȭ<##`ffFpݵͽGa>M&JEfhny @ʔh4J#1͏tT-9VWBv:-@zzAb1DA544J\[UomltrBTeD #@Oj zoIENDB`psi-0.14/iconsets/system/default/arrow_left.png0000644000175000017500000000130311305557613020007 0ustar janjanPNG  IHDRa pHYs ,tIME  f_bKGDPIDAT8RkQޓ)74bC4œPAHȮ5[AF"m*5*9" C FTTzJID55ZClRt|og潙a V\laŨuXlg6[Yq˺ޖ $7\sR3;r˝7 /|!isy⎱ĒXYR!?iNT`pp})8z 2N TR ;d׿ H|DCv3hMZFGpMxX\+WhlA'6:2Jz]#qNp""y^ Ir5ɬO*Eck8q.u>h>P$#79=^sO'S>+!a3Egow[A2`6x(w:}e׈[[@X'+ܧ\?ܼIENDB`psi-0.14/iconsets/system/default/cancel.png0000644000175000017500000000123111305557613017070 0ustar janjanPNG  IHDRa pHYs  ~tIME )2bKGD&IDAT8uOka'ZU[AQR=x"b.Wѻ*JTh]Ѥ qdSCܼ0733#[+CAh >cL~tV]}l~2_7rhΡt&S]?`^&g gKŴ,z'ȫ  M.EEm`A _>gҹ~IzTn v̰ e|R_fOi;\<S#R-1y'jfm(YpA֧Nmnse0뫪| ^y?-T(lu:3 3T$W*}V8L9ۡA|g Me<#Ց;)_xem;cXfm(8߹4g(nx"awo0P[HjD(Vx"amwƶ- PZ߉"Z6@O$,Θ 5QIaguvO7Θ9 e;@703l*BiIENDB`psi-0.14/iconsets/system/default/ssl_yes.png0000644000175000017500000000135511305557613017333 0ustar janjanPNG  IHDRabKGD pHYs  tIME :)6zIDATxڭkQƿɤi0Lj[\ѸrНWE7 u bB( R}$՘L'$$wf=.4Z9w=?;̳H$O&NRd"`bRkoLa,.RW1$Rlvp\ǑRcʓz|(bz$odқ[nGGeTU)o;splq-N&t.|aUd,C-ue҉dd2]P_X5W4GzP(ҏaOfZ+6*n~iU?|Ʒ̨ vZyveI2̨{5j5r-g}q6&OcQ~\mf@B 6 h!Q.09FG_u!pX *(#{C(p5hZ` ݦ-B6CIK \B@씜y2jTΠ\e=Ց hٞH . p.aS p` oC#%`` $y@C+Ag`ۻ,|n@[G@)3՝^MӇP:IENDB`psi-0.14/iconsets/system/default/smile.png0000644000175000017500000000154511305557613016764 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% xX@K& ݿ?Ղ $@ߟ]o44$l_#@]*cK{tᆀxG=85J?āb-? 2D <1oӢ5k,u  1`?C 6~hH>H/@ xsUߠMk!?{w^Hy%` X`Hl?:97k}o) `@`SOg3>A~%  `(<(#oJKe?g$kR`G#@(q L4e!D#XXP@$e _Ug?_˄#3(g|qf&b4;Y\}rIENDB`psi-0.14/iconsets/system/default/account.png0000644000175000017500000000171111305557613017302 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_F?IDATxb?% ("meP`UHg0Mz  ry ~bp"T ÷[9 >3?B.oA ڈUf[  AT!eߩ- 4     Ͽǻ ^׽ " @'e2} l L L 9YׇC _5c:÷ et ?ʝd*!8.a򟙇 X¯e >?e` >3Z&/@G] t /į>|``k&+o84!o& \* ,\ ,v@81|9GoA!~AKKG, 3)A ~kkk }yyyW111w>|8u }O """ ^x>b1^ 3ɓ' 'Od3ׯ?$epرF}}}w2\~ϟ o;]EE${u5 >|p 58s ={. FJ3@Ωi{IENDB`psi-0.14/iconsets/system/default/stop.png0000644000175000017500000000134511305557613016636 0ustar janjanPNG  IHDRa pHYs  @AtIME ",ᢂbKGDrIDAT8uRKSa?W!AwuA·Vє^DE4$"ԅC "B>*Эe6Cٚhv\Я9:==s8nI|ϋU!^b+pF[>ؤyq^˘>]vN5ػ」;v<:̗7XSڠkg|p?0x.ory #ӟd}k@E@xp,#˲m00aP|#%"+Օs΃* ,I Iw:琷Ղv+m(r8 㯼IkFؽ{k놮ZVmQg5 ,# /#&|#!Я'aa%% 4M:ólc V_)Fara-р: TIO4/!g iXvj#wPE x:Tx3x$wh6h߱R^DM_ 8ňKvRPZ0}@Ű&WU.2p}Ʉ-Jsf+7QW?תd~')Ü wl 55Y1{X0+WVU!ѐS,-޸Wj'WڣU<_o|w__sl}5ځ?MKFIENDB`psi-0.14/iconsets/system/default/whiteboarding/whiteboard.png0000644000175000017500000000127711305557613022633 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<QIDATkqw~X0$֢Q"BJ1I-QJqA;jv\x(yQvlVc%f]X&kq3@SũPS9 sʄX#uDfEͩhQ+/b,⿲pe3?<挆msݍ=|3%/8 05bNW0\>%2*;|' &yC3׉>j;Y=䭦SGL"*jD ro[A]1S2ɕ !fx#?\o3B$Y\Su!" Br&1g-C/"ѯDK[+,"!/y쇛$n`(u/Ia;Sj88gN ED ~([&"1#70Tl:OQL!@W[3)Tz_fRYt=KR4BjFOuԟ 9)Km>H6UV/ō5fC|{{{V`wwsssV{jK۶_]XF)Ear!? >AQkukkKe;;;PJYD:ϿYYYYZ\\4,cRb4!fC|{{{V`wwsssV{jK۶_]XF)Ear!? >AQkukkKe;;;PJYD:ϿYYYYZ\\4,cRb4!|(>|IHHD}##bI jΣ30111aʕ NZ#@14谔Ԏ/_ 9sϟ? TҢ@r@Afv]@[]rΝ;7?}kUWA@?  _~Y0l9M۷lݲe úu@3 zAh9@1ukaƍ~Аsn :tгwjRFjп fc3WϚ5Ц%@ hx455)(w@z@?~,Gyɒ%a@S \zd3(w?)ȋ Y@:13`2F?H]r٧i:0<zPȀL@_ YLݻwF`L^y+Pm`4  xTկ{p1# (d3L3zPˆIENDB`psi-0.14/iconsets/system/default/whiteboarding/add_image.png0000644000175000017500000000121511305557613022365 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥OhAn RK%JzQAP4 KOyd^*DQT4"RKmNZIcgotד ?v7aZ`|j8q\yR И}>9[TbۢY3CG:1AN0]efB8pA'/h|GWMa:h(⋐R.{!2I{ =p?q4Ot\"M'gS m9?hubָnlÁ1ҫ Rb=`g\9niܦ5ZFͦ7~ynHt*s)^d+Gt?`_A`Sw37Sk#`ƿ#Sk؅逅%Q~9Nf X Y5ͳASdhhJ ܻPjbKq[myzkd@lhZpwIΚbX(d>_M2hYVhrЂIENDB`psi-0.14/iconsets/system/default/whiteboarding/send_backwards.png0000644000175000017500000000112511305557613023445 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥?kTQ}{/!vZ:ISX;M&_AA l33X4[̜vIϿݏ02RF48 ]٧gQFo 2!&dd$X#9?[>I^4Bi<ׂtf8]; _it&8M8U*J$DMӉ~xQ`p4ٝ_U"\Җ9/F(KX(޺#0YD-Ս*m5tLRx,/\ڎ454cZz B p]ۋs+.Ƅk#*}hfvxX lJ] 48+΀-Iy֞$8j{ g53~ '{;ᅵ3A QOz5/HeW@޷J4v 'P0IENDB`psi-0.14/iconsets/system/default/whiteboarding/group.png0000644000175000017500000000052711305557613021634 0ustar janjanPNG  IHDR7gAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT(cπ2IwViykHܝ]V7TO/C7>]Fl`~'S{ضaC? ]M'sC59QXnfi%A;BvN+I V{O_Hm{뚚`j^Sd){j IJ=UIENDB`psi-0.14/iconsets/system/default/whiteboarding/scale.png0000644000175000017500000000056311305557613021567 0ustar janjanPNG  IHDRabKGD pHYsHHFk>IDAT8폱jPFO lImu8RpP0Qp"8R%H&B??@@qNTp8X, V =ϻFݎ(n8e4Z,#IVv:>z=&mQy4 ibY~۶nK0 +qނ `<3L(˒(8>@4RTUmH)H)QJ!`0>B/fp80t:H)rUnIENDB`psi-0.14/iconsets/system/default/whiteboarding/draw_lines.png0000644000175000017500000000070211305557613022622 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<TIDAT8˭?Hq][ p@\hZr0+ʐܲHlHH*$:2,S *A = _B\x7ÖZc<oozڈBЊ" 9!B!>gvڀ,;SRNXjD|D62 ( 8`~vPOoCvs 8 ]|aɄ[ z/Nİ*tuXİ*QT.;kDbՀ̱ <ݏy#~=庠q]}fĝZtlT3R%~>#w -;06m7wU\&IENDB`psi-0.14/iconsets/system/default/whiteboarding/draw_rectangles.png0000644000175000017500000000067311305557613023646 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDAT8˥1j0E,U) . {{ _`N#R)vY-r"1yD}*K\_, r 9JoRo J/GIq/湩+RBn$DşdPR.ʳ]ڸA׿u!@ &8b9\˅04 I^4Bi<ׂtf8]; _it&8M8U*J$DMӉ~xQ`p4ٝ_U"\Җ9/F(KX(޺#0YD-Ս*m5tLRx,/\ڎ454cZz B p]ۋs+.Ƅk#*}hfvxX lJ] 48+΀-Iy֞$8j{ g53~ '{;ᅵ3A QOz5/HeW@޷J4v 'P0IENDB`psi-0.14/iconsets/system/default/whiteboarding/draw_paths.png0000644000175000017500000000070211305557613022627 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<TIDAT8˭?Hq][ p@\hZr0+ʐܲHlHH*$:2,S *A = _B\x7ÖZc<oozڈBЊ" 9!B!>gvڀ,;SRNXjD|D62 ( 8`~vPOoCvs 8 ]|aɄ[ z/Nİ*tuXİ*QT.;kDbՀ̱ <ݏy#~=庠q]}fĝZtlT3R%~>#w -;06m7wU\&IENDB`psi-0.14/iconsets/system/default/whiteboarding/ungroup.png0000644000175000017500000000113011305557613022166 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8RAha6~ bBz]4S0R;t 4DN sy#;Yx7)Ҡ52wY/<(`0x<'xD:>,ehG/ZD*Bۅ,˨jFpn5 t@ jNb\.iB!L B9 Lm٦FjfzRhGҒgj~6}p8M&)g8ڑ`Gd_,er9~x^ӧ/L6&coCI^DŻ ~.0$+Yx}vzQP[ocfFZV/s ( YPo8fAKǣ{3 cOވWI}^×dzTYx5n<Ԉ$rE5IENDB`psi-0.14/iconsets/system/default/whiteboarding/translate.png0000644000175000017500000000123111305557613022466 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% qv@;'QxSd" I uGlωZl6 ӦMC1 P_@C\\]={h#@1%?@>@ \ Ȇɀ @45m߱͛ ˖-8_?0@p`^}oF@  ؀?B4ի`[~2+*l2 p 7e˖1|a _~j} Y ==(PĐ T;ʊ z>2tuu3꿿0&>kD_?_xO aQbjofK= ~a2u*`hj{ %YhΘ> 5HjDC1 L6`ǎMHiv0v)IENDB`psi-0.14/iconsets/system/default/whiteboarding/add_text.png0000644000175000017500000000106711305557613022274 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8c?%f8ppwks~[n̲*etW/$#^욯,to➗w=߽%~;]ۦs kɄMxO+~-\]9MewZ\wmAӺ'r$* , /*%Ͼ(nڝCfV944SUY7I;{8LG岇]^R:Ć1s u0^q- 궟FgD&~Uo8յOK.< J`'X[v+as =.KF'-L~auO_~o6&,2έ/ajUv+dGK" 0^Ym t3%Oc|gIENDB`psi-0.14/iconsets/system/default/whiteboarding/bring_to_front.png0000644000175000017500000000112511305557613023506 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥?kTQ}{/!vZ:ISX;M&_AA l33X4[̜vIϿݏ02RF48 ]٧gQFo 2!&dd$X#9?[>I^4Bi<ׂtf8]; _it&8M8U*J$DMӉ~xQ`p4ٝ_U"\Җ9/F(KX(޺#0YD-Ս*m5tLRx,/\ڎ454cZz B p]ۋs+.Ƅk#*}hfvxX lJ] 48+΀-Iy֞$8j{ g53~ '{;ᅵ3A QOz5/HeW@޷J4v 'P0IENDB`psi-0.14/iconsets/system/default/whiteboarding/send_to_back.png0000644000175000017500000000112511305557613023106 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥?kTQ}{/!vZ:ISX;M&_AA l33X4[̜vIϿݏ02RF48 ]٧gQFo 2!&dd$X#9?[>I^4Bi<ׂtf8]; _it&8M8U*J$DMӉ~xQ`p4ٝ_U"\Җ9/F(KX(޺#0YD-Ս*m5tLRx,/\ڎ454cZz B p]ۋs+.Ƅk#*}hfvxX lJ] 48+΀-Iy֞$8j{ g53~ '{;ᅵ3A QOz5/HeW@޷J4v 'P0IENDB`psi-0.14/iconsets/system/default/whiteboarding/scroll.png0000644000175000017500000000135611305557613021777 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8SKOQt:}L!-,@pcTFcT6,L4#\ 66ntF+DDn}Qܹ3z[!q“|{/߹"QBC=_t}R2|ۀ#S<~/~RWeB`B>۲qu:Fashl]?䷮Ҁ&LDmDX[tģ+ڈfl h*a`9ee;iՐ{DOx' 06m`yV&8nC >LɶU[nER*Ѡt 8 )Z,znq-r9EQY|PK V욃~p)ZmhE3&Q(6lc al0%l2$'ZM6}b h1\SUPa!Fp&۔)A>Zcbfrܟ;S D#фzT/_lsX0i#`>{nm%FȮ{O=ۏsu#R^j$Są69|Lw< tH.8iNK<#|fUoml`eAIENDB`psi-0.14/iconsets/system/default/whiteboarding/erase.png0000644000175000017500000000021511305557613021571 0ustar janjanPNG  IHDR7 pHYs  ~?IDAT(cxǀ2TaeEU9.tӰ؋b}A @DސFd"kIENDB`psi-0.14/iconsets/system/default/help.png0000644000175000017500000000127211305557613016600 0ustar janjanPNG  IHDRa pHYs  #utIME 1q,(bKGDGIDAT8ˍKQ](*B73i.]!Ii+e"]di)$0C5I 3#b3יF/<̼gyϱٖgI^c[%-vqr|o 鳹mi3Α"ɁWM&f:#:c_<e},9p٠w4)c`Ф% :/|*/ d{ V,jf }<ʷ3f+TV<:͝%'oQ~3 *g(ȹ r<.c*Τ$\ )&LEDŽÖ^#-SO&>đ^)H2u Pςkl0SG#9zC'Pfb/2bt-I}ņ߂uӠ?țewH#V]aL};C AHR%Ra9CxEhx ^Z=~yESR uo}C?fTg{O{ 47rIENDB`psi-0.14/iconsets/system/default/ssl_no.png0000644000175000017500000000071411305557613017145 0ustar janjanPNG  IHDR7bKGD̿ pHYs  tIME " ]IDATxڅ?/Ca[WThJ$|b X ߁YB b40$? A,*{{=[ML3<99`EmX>^ J~;L2tڿnSkNOD&ϖo ^o IENDB`psi-0.14/iconsets/system/default/xml.png0000644000175000017500000000143411305557613016450 0ustar janjanPNG  IHDRagAMA7IDATx}K\Wܯ3w;S""Eq-utHRiB@p׮\EVm"!$"?ULLa&s=tx)$ٽ_|/Ye1c<>99鮮~+nSP ˶,d4M β*(Jotnc6B`Y˗|;wC2R'eJ0 IRJj?z'~ !mcvAA$xp8v8} G^{8mx4%MSz#۲,q" C$AkMDQDE!ZmjJX}Q#R0p]qZ.iR"< R  2$0 s![Ri"r"DkM$ap8\.S1`Yn*ۤiJ$q֚,y,p]uvv(> uw Q!Q$ ^O_n7lnn @%l6i4B`???~ |fyKtL5t:c1A 緼k599yVRSzGecchkk;ŧ_OMM}o1׃Vu~ppW[¿(s>"и9IENDB`psi-0.14/iconsets/system/default/shortcuts.png0000644000175000017500000000122511305557613017704 0ustar janjanPNG  IHDRagAMA7LIDATxK\Aǿ3ַ;x(I9!.oH?#ؤ 9+}ʽ?R$'B̗ AceyymQ!)%v:b~~Mef-˲LMk]BԲ,w:rT{dY "8P%yO1MS\^^bRJBsJZkdY"B )%/Rf0==8 XXX3#MS֏6qV1F(RJc(sYnll|Z___19k-BB(13^޾nZPJU2-BxaEYBCs$D8??0ƼbfGGG8<<bւF) "jWWW888Ϗ!3C)c 1 vR C_EDӁsT*$I955U#I$IFZku!ߍ1)mnn~kpay$"NT#5|||YhIENDB`psi-0.14/iconsets/system/default/quit.png0000644000175000017500000000153711305557613016636 0ustar janjanPNG  IHDRagAMA a pHYs )ItIME 4<;bKGDIDAT8]SYHQ# ,"l! K ڋ40DDA+1LQIq)qMRA1& 5ʅ(8sm|o9|"B4l v6d jĩ ބIG W{*n0AraN< KJ7IMtjv'(!}D +>A4yDZ"w5:=™hO8c9%=%I(RAۻ]T GmxƸCk˜v95 p8.r/oQˊA}&F s?gѕkF$yQaƙٶ\͍0ObDMt@ ΏCE@M¬N<!ۦ/c+W݃ \ gZS-LB9 PSmr_e6F55PU\ zhL6 .Cr{H9*.M{a4 uTdqfbY $:aIENDB`psi-0.14/iconsets/system/default/start-chat.png0000644000175000017500000000102511305557613017716 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbt-@ `bـ8 -X 9> ^ˀfNF Z  r pO>6@t >g"P,Su9~Nu)Cߪ YĹ+ n :b f <j!Btպ ')!/ k ~|~r{ x;7ۇg0ͷ j7܀^L~c ˀAmw2,}/ o I-ϯrym`bamifXz \P" 4PFL^XBE+Cϊ+ kp%e8 >V "Qw63+bd&d<R̈́ UsKIENDB`psi-0.14/iconsets/system/default/key_bad.png0000644000175000017500000000154711305557613017253 0ustar janjanPNG  IHDRagAMA7bKGD pHYsHHFk>IDATxڅ[HSƿs[tʜD+h7H`,ˇ^,=dH"(!|(e:KJS6u9$#ZʳE% k>'\tHVTuuul||JJJSRR.E)N1+ZM|>nVXvttU,/... l^kZMݿR[j./a I>$#&=D\^lq^e,rIc2tNpWO4=UҭHݲ +IKvޚTE`m |y=9U{`jx^tG60ָdjkx[ۡ넆ԐӅbN-ež9+'2D#-U8()젗1l ֞&2˲-+@Kx Q4AV&tikll].) ;@ 3T&j11b[Alar4M444\H$9K]&/''dpb*uQiY@NjC)3lXae@M*߽d~)ʪ~mY30r3A!0`MĪP"=fb ?LLL @>رrOpe'$3^!s10Jӟ?A~=Ǐ&O|(!O,yk\s"Ϡ`llϟ?>|``WAK] ^10п@N*f8u   @yUVfX}x"Q@-fv533#Ó'O>} Hϟ32*KJJ?$&}C21Lax~ uuu>}$ommpm_~ ''2QFFVxU 90\s6FĬ%/7P0ܻwǏ 3hkkcd0\}a)D_z@sdd߿ cprrbpXkh=t_ @1|6]NNm630ܸqw8J"KLS^0]xu_kkS5P+ @ YMIENDB`psi-0.14/iconsets/system/default/vcard.png0000644000175000017500000000072411305557613016750 0ustar janjanPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FJIDATxb?% X@zGMmP']@`0800ʀ Ze'2!8d3A!20lބ @ T"1]4In@ - iͫ[AacؼYn@ <ͦh$v #CT<#P abGCl,Yn@! j[,RhpbP hY>B`FFA8˗n RQqQQ60||pn@1R%I )L@! 0!~ܼIENDB`psi-0.14/iconsets/system/default/filemanager.png0000644000175000017500000000150611305557613020122 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% X@ĒGqr }? _~g ×/~w Ow0\x @.XO?iˎɞG`>:z̟?oN+{ _a셯_1|:?>6V~c߿b7?116 s QTŘ!߽RĘ=*rǎ5C!Z @C!;++#3#';!^.W@O?  @; 4Xr`G(a= .]@@^ tf`|i ' Y_?>'v?A O80‚ hׯ ?;Û7؁3 LL@W`@~@Ac0?Pd 4ϟpb/^axSEׯO@ Z`F_??#Çׯ} @_7778l (Iׯ3 `2  IENDB`psi-0.14/iconsets/system/default/history.png0000644000175000017500000000212711305557613017351 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbe;_ L  VV|İ_o~002 cP95WG]\ϟ 2" &~.& )~m 䳀ˑ嬨c+&Xci +l*&ҕl @1kK112|pW32Y@L?疠/ -$x e@ ""),#k %bdצ㷿 _4dy%DExAWd`raz ׭xAS]D _ b *B "Pf  K=z;߿޼ ?2|AH \ z ~;3|@Le`ӗV}gs=Ý4А <@WAEVAAEǛ_&b~ƛ>ū@@?w?89X$E9dxT% @/VGO>3 r2<}_@W}AA}).+  3#'Ý$>o8, @,j $ OGNM^>v``22|ș /dx× Wog FC tTtěfax o1po[~ܺv?- F&M/`?C~E'3 ~39痟6wL`%JgXؙT4EsEݓm d}L; KK|UjIENDB`psi-0.14/iconsets/system/default/self.png0000644000175000017500000000140011305557613016572 0ustar janjanPNG  IHDRagAMA7IDATx}Kq?SwpfnPW5,:be..O.""0(C(ҁ,ZiI95}ܻ_Wz}Xr,SenϪμx۩JKGݽ_#B,G <w\/KކN"$$HclƋ^-ag; 2 #ֈMưYϾ˽=hJPlf֙"4mYWXʖ@޺:08N{ ~}hݺ!3XpKta4@C@P@&9u>WN:^ҳ,d4tzxJh_g?={ES!_ 1RG\c[b{Sj_%yLErWhQ(+[|p|4*DxB)!"Q!_xkF^Ϝzeoof&6UYl>oُ1wDR]iϾ]Z2YH `|dT 29vX:`OBX@SJ uz>Gzh|; J7حA& 1;&جPj*LNLΪekLk9MM5mDw·o]LƾHKpfϿ媨())*Q% B?D#ooq<%]IENDB`psi-0.14/iconsets/system/default/logo_32.png0000644000175000017500000000466511305557613017125 0ustar janjanPNG  IHDR szzgAMAOX2tEXtSoftwareAdobe ImageReadyqe< GIDATxڤW pS.Ylyo`{ݤ!@K8JZZ$ʹC&Ia2RpKNISapmWY.[lK>˴Ÿ\-y{ !nk%F!T uCp  @Ht4aP=pfW쨯m-D pHnl ,<~Ch<(uG2mؾXVDaTv}VΩS7,&DN >"|Z U!t kvբ_0Xv @ S&BVDˌG@`%oz 2Զ;# |vNv-tUH#B@`Y㑰%̞ YiȜO/%WܴG?}]wtߞc68o5+o%}0uH9{ 9lքQQ t[}@_1%=Zsµ:T[-GYO?a0hxA9r# ׺z,Xq]>9Uߖ_{#4tmK1(4 ~w79I,Q mC=~p.}MM|mkLyloM} F+$@ |.9tEr:T c+pY c2 L3K@5ȌuJ0 ;x@4!*A,6tQgͦYK69RU*'K_^>]LΌ|{66jѳwwLYFoQ^f;sе`-WƛH \ur_k$^~Iىv]k`4vlMJH&G `m삧Ɣ{ǘ B}׹֦faه'F@jfB #hmFN;/Rz{8E sdE FwkmbH͕]':i9gPdDw~Q5uQar AܽW[ZC-ȿ10!\AQ0Q_ t~r^qH獹kJV8;jk½@ ̸{ 5< :XR YIT I $26"=wagazNPuh^գP'H`8Φ7cQ>ԀY$8)zD$ iZ_3U=Fn} =[UrL9DŽ\`N_2[bZweM x+/^xCo"ApPwWqJ6$GD*O04F |WTE3[gvѝn<b'(ODe@cZub0x;*uN]R{f\6.}s7uT!}y^O`XZiYsKձ {~g < 0-ҮQw~T, ^; p"[##=9ˬ;/SfH|4PUnD.?P>aq~ )u2_9ִTZlpUW6u\?Ye{Մ$,"{NO* (T BWkMC1\D2Lؾ҅K)z0b9bi ?~Ypc`1 oGD=M*zX eNjl0Ѹ ve  ZEPRoø됅ܾu%? c%/oV7)X;}1Xo?|L`;G5~uwNn7W;zs b*a>L3GO*z.xԛ",ZS2;+cB6Nq;vw\M6\e7@ e=otI=``Azަ<EH)~6"j{а<*~*w/&:N[{H>cW])iɛޝP@eIc<_P:Q2ڋ x c2y%#E`dɢdK2q2C'o^;Y14woGqI)IENDB`psi-0.14/iconsets/system/default/logo_16.png0000644000175000017500000000166611305557613017125 0ustar janjanPNG  IHDRagAMAOX2tEXtSoftwareAdobe ImageReadyqe<HIDATx|mLSW-m+HPq_x1 n(f-Yof#~1i 1.6~B,PPZֶ\gK%9yyd7c)A#(Z$^2@ 8h 3\_V\z(%YţHϠ;ɞ_g21sT|[v~!̻bs&P%eNh}V&QP/kx*cF;Dsby9Iڲ)g[f^;= pIRʦgRH"We%49ZQ6 7i.'?rB\K b^[XS/!BkƼJwABZ GHAٹ6ǹ;ŗRC ٸu( 8#d; j g޺!@vP Ζ 07QYSkCU:S0*ξ`l?iQy248tJ]FV G T8V&":Gd9<> ,϶-_H h4>$LݙKj챕߾ͽ_f=aH'?Y77XhbBPsYDQgwܩ7zV5j i!Z\7ŶWt56۱Lϗ셟Rӏwx$R˔:Cbiipm{$y^5a'j{A>GIENDB`psi-0.14/iconsets/system/default/arrow_right.png0000644000175000017500000000130611305557613020175 0ustar janjanPNG  IHDRa pHYs ,tIME &0NQbKGDSIDAT8RkQޓ)74bJP$Tkv V6J =T%#zZPDz165h~%1FӚ:y4[|0kX1bd6)Ygxw+lZͬ8a]o \O%'\O B3c+Jw,A*[2[X1/!q*kF ůYi&A4§2句ʧrpVEr&u/v~jU( Ļ"t^Nwl 7$G*D(46 y4[؆q -BH sΥc 7ם]`' ج>7@ZOg l dHփ6@y=hF DGoR^=WhGm7A-xVi ڱ!m-ta>;µUx+8xs3'qpzejQ0'* |pNxߣ 1tb8᳒ML#О0Swx)t2v : M{Uq`f͵ ~F_uIENDB`psi-0.14/iconsets/system/default/tip.png0000644000175000017500000000111411305557613016437 0ustar janjanPNG  IHDRaIDATxjSQszI\`MQP-XT| s'Od$NPP "REKKPkI4MOrrĶɁ׿ֿ>ȿJFcce>4ߥ})_)HQ7bn'-󴑸 ͊Fj3nƆ<OMEcx뀻IPuDsXMN5ǐ x߀JKXj~j88 ZwT}R}*1+-V Ooo@~t\*|JJQ-dbYr^τEHA?"ݑE_@ϫ`̬R 4npNH Tx,Vv@}y,Bx-s6{piSz!zRP@>lA)E&2~vW (6QlVy;~\.wܶqh49G IENDB`psi-0.14/iconsets/system/default/status.png0000644000175000017500000000123511305557613017172 0ustar janjanPNG  IHDRa pHYs  d_gAMA|Q cHRMz%u0`:o_FIDATxb?###:x?T;GՀ/Wϯ}pW}zB6Ĉ`qAnY"H\_q.  g?/7KDi| nH/@1/~ߛaMmZ߁D<9Ht@Ǘ~xp7C^f~ a@`3P-Yh/30ſ~_ ?@gKn~-kLM_?5|hiNq  h| lç@[B4@/z X^k9_?|`.HB\@hdfbhb3 s  `oኡ 6 \W.z b@A\ůs@A{;f10b7Ih4+X+@\֟IENDB`psi-0.14/iconsets/system/default/configure-room.png0000644000175000017500000000203711305557613020603 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbY --_턦}ųg&~}222LMǏ_ ~adQ 7WW[E`xAggLuu50{υ̻_Z͛XYky{j~NKEE@bfx=×o=93}gx |54DD}``exÇ/ w$O1r 1& A((9: I 14˗/@ ?999yy4~BHL0AD$D}dexm_L/@ʲ[?}ؿ/ܦQ _ L?Xra@1kk[ǿ^`GC_>*gkƗ€g`diʑ3 l322  ¿ r7NQL[}0G_f`} ȸ ^`6i9[03gx#KDpzZh-N{/ 0{~ax`a&IENDB`psi-0.14/iconsets/system/default/logo_64.png0000644000175000017500000001444211305557613017124 0ustar janjanPNG  IHDR@@iqgAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATx[xffgI+jWKn{7pABB rG/&]rI!%!sB 1`l-܋$kWeWSgVc [_nj(-ZAs2r\:6 KH bt&~N:X֍wg R6Uʊ` /q9N_d"^M/9/y_(ï^lܱ=3?Jp F$LqɊ5~5+]W²,OXI(<Z]  oSw}W37xgF˟]O暻"2q' ި)o[_ϱ:`:zlc}Yw]{>p3-2GIMC/ѿ}Cλ^< bcƧĴ7sOPBQ)x:$Oi6c+fe$`e`0"æMAHz6^u^33_O7A7Py8ZߋK4M2cLuE@aIx:J0Yx$$/L!K]۲? oxo~QtgQ<~vc\F%31>z򒀠0pqB(9FKՖWa / >oO a@Y ?:N۔ /=⩯`+z0`[aoY@KYt ?s8shkTeY8=C :N J:Sg&_}<Y}- +%EIuw?+{H<#T.Fg9[fCKYDGWv,Ր$fmo6U%Qf>s= G{H"Hz xCX,s?/y_g6TׯZnqn՗#$Ϙ1](1)*": ⯇U-ؠLϢYqd$b~Y>E& hxMO^a@Æ#h?й}j:N!!l*"ILj&nϨn/1@a?wWQ"8a@1̨h3~>Vڳ]O>m`xjZT1_v Q1U69xPK%a! 2u)vA[:U(kÕuކN&A1,Xf(e\yeeдn }Oq tJ1L·'$G&Á6fKR ɒ& Ƹrhi9?S߲!ONɝD<rRlٸ_& 9{:qc"16sR̽7^82MbXSҵM2V}AE ߸Ѡ:;@~2d2ғ=ARCEl̒u*/+<H P28& )ǎ?w3r!.E&|ɩ&eA%}JB۰fhY2 DZ$010E=HLeR$Hj$'ks=#\h+*˭嘦JV2) /I:d7lE )kP~CF0OX[Z9D=hf.*<Yyi >ʘ*pSOv,P$ *@; wCt7J%{ vʬ&e("Bo_ |{Yq>3|pY2 P \RRmӵVjć>1 Qbߨ'%BYN4=#0֮JQմQ0? |? 7Gܵ <%m` 2P)ņʣY88-e 'j~K[+e=]#It ' ]+k˅LV-AV}n;+KC^Y-zFղ3[tVSq$$_GO`|ۺ5p2)2hD>i*Ő)K{HݻX3uG-jV(zqLdz*r/xY/cXO!> `ȱcn$P^hZ,Q5Kmv45, '4Zac"o!Aא*D*dp% BV! `,,l԰!.+ ֏!?fNZgx upCȷ$^Tٕlv 7 {w!d_YS7ݙq٫/5 D.xA,;J+b0C5b4"UTQSGrDɣgh8uztm Z(Ȫ+%@o.[" |~DpiFSsYc W^Q^́X|S5=Hr!g@LQ=Lj65M jT<@!91&\?ٔoO0Rr%jY8OB@WۇeEW ˗e5 9mWwflÅ`vs1vi)JKN.! ud*@NgqfZyK-`"sr]r%,gtTOE<f=x3ɣ6̨ʎoE0:}̉iAJ#E#;1Ѕx( WVY h-'bQBjdhsqM/U5eZqfWB l@wAWDF3;L%z.DTV"tPeJ4`ńGU/]bx) ćP~2HJ 2dD(_as@ʔxJA"C9E/l-T|Ki/nl7&5muܨ=D(.!j8y@&r .T5ͶY5AN{'(#"GENRn>1?UZKf`k}WŔ+0 N_e:iWتK z\zۈZD#.2I6ֵ[f_Ȼ;q>Xzxڝ1ߌa-3[JdXQ `ŕ˓SX.ӓa`XU$n 9W'7q|_Z kV۫L ]nnZD2LbǜWa+MXl[}Mq>_ll@41L{.0\2Қ%U*z̀ oQ*$+g-q8d5W)u~ZLGGRMPh_/ Zg BuRLϫ9F. 4euVY-dZ;k}ʛ gq B`,`),!pqCyN}%sF0Me7#@^g :'Pًes^́޾*EhwTJ>:ҷS``X^SmДg   gz ?jWYoi\wtn,T Q@3~G$)|urxx dąg(SĔ,˫˵OW^>9֯dbq9*Bk[Zܡ'q=l`Wg~T2Sm F ":\,5bG&+jcL--A7P.H;1wi˚,>g6k/YBV֚%1r*_7D?j06Ӓ0Ҟ%(ψkAz=E;]ԃbuӠ@K# ci{ =Ո++PSU v{UeZdG8>3ܻyۋuz֔JD0K#5/jR"Ona L .$KhG, 2Kueg(/V3V[[\R]#PD%(vwa|ĠxիpZbF#Dvڶx{K<}XHy\S /^ЌP^ҙx~˷WГZZϒVj^7$uL0T\צ.5ͳABSp3Ib4p?޴ >}CM-3qIbV4U/\gΦ݁PFlj4X0ј Io̙ͨUߵ^cSJ^@֭t~zSaƶM-7޺{5(|ty`&*f+i+%[BTwut-`y:!~7ֵg|HAqC &ˆkŘ43"vM9<hO R6St4~p;5/R_K:v7=%$npEo_s;^}O hm7;k5ڭe;lS<)/]PB19 {vIЌښo d29r mGQwȞI˿^@WyzJQ`}O0G-m7\2K'`6\_$yЉ1dp|2“`*^?{f ٟ׺Bno,$$؎RAł!%8&MQ7BI ׯZc2GG| @Q+c!IENDB`psi-0.14/iconsets/system/default/show_hidden.png0000644000175000017500000000175211305557613020146 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_F`IDATxb?:d`) ߑ`nh436Ā k%zόc5wgtdabddP@\RJ Ϯ0H늱hHp1Y hPdbb`RTs63g)'3˅Wf{MX߾z{^A4 6%?  ,sA@=2l;~k!4 !1 ͷ1(G99~10|'D#.`t';w`x@1{ 1yAV@E߁1 x˿ '3xa͏ ysO?>?b{LN\0{!47;w/1> {7>d|@h6~|򒁁 fml@/p020p10ps20qa?k*f@,6b&#🕉@7#?N_ <_YXhO'$gyf&9. Ml \$,  \ L" d9@ , (;ß?ozu٤W.| e` <ˈ_9s/W};~nlan @f02CAE@9g<  @1 L`>@IENDB`psi-0.14/iconsets/system/default/info.png0000644000175000017500000000152711305557613016606 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbd@*q_Ll @G~Ⅿ'/@V@0Z~ei-l, Qî#֮ɋ @C?\{ j) ΋((120s0010|73ؠ?j'b8~yP @@*Ô f`Y +0uqا_ f v~~^R @̪{~re$203Bla&  K7gx,%, SВe8_F` r ߀?~ ( 4}b`6expQ<@ׁCT~0h-Ug2d;" ߿70^bed@9 ф/=p-981 Ͽ00*gl ۏBE!ԧH M; (|7 b2v$u XUV% Dl16ﬨ|ЎNsϳjp%x.33 6| ^_y Tz张>p.g[vhg&I ^%"d mi }gxv >?zvT@ArĈnd[0 sg//߂ 5dgb&IENDB`psi-0.14/iconsets/system/default/options.png0000644000175000017500000000160411305557613017342 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8KO\uΙs@nZ@ U &Ʀ2qg\G5q Z/""a\wѴO]'VW?cx8пHVqV|%s݀(sxXm{819yk~G~2!@Q+%ǍVlo( 燇( 3;;y!AlZd2iFPA̶Zz s2]U}v˭,*xZRhqfټ3ݫԷb\8O__7ǒ 8:*Qoyst@ܽq8Gё&fPԉ~=Z^J4v)8nv>-z喭''w])4S7ޥn8ފi&_N:&,+/|{f\`(8G"eHh-˹lf,?e\#2:0Z$͵mݠNMq#%Hf׳?ֻۭg*g HlĊ8xB)ol٫ mD({=<PU"־ wmH%@-@:(#DJ ˵żbHj'u@,(nrp⾟8U]axjoIENDB`psi-0.14/iconsets/system/default/logo_128.png0000644000175000017500000003715411305557613017212 0ustar janjanPNG  IHDR>a pHYs  gAMA cHRMmsNn=3.ѽ=IDATx}w$WuJ'I]iW s@HgƘg0N<c cG Q*6<=+{tM]Y[W_vU;K8G#!L}N}hB3 Ye,$g ($ǻ?-pdJJD) xM ׾~~FǝcBApczߝ>}w0LSU~]h 5}~"@p&85z fm@6]_}3kZy~o57]F7_26|[`?ˑ7x>=VX, Pܵ{ =c3M3-c^y]5k9W]mTKO^P"Qg܏,!g2!B=,0nfZźBCTpx :@itdA|"{@7`%O@P-][n vثpZz x<1[= ׅ8C[/ ~[c'?,l} &X~,@$ul7\Eϱ Ȍs00sp/sm姍B]ڌd{Ҝ_^“,? !Z7p߻uasdhS L|񟜩?JJ{^*͙| ړۯq`4O\ꑟ@(7$^iUX7|2Y-DcJt2+ TcQpg0O1GtHGqOm|>']m8'o]7Qe~tS׎~n{)@ `E/Nze3=ՙ`ǓDx 9!]MT=m:|OZ?@~@?Z?=Wzd$95dqr` q3w!yN&?!gxX󿿚=@t7nVoJBԵ 3DRVpA2Itux?B{UP 8v qs`!fOdb§`jm4rIrd w.>?XvE^q BgT;16S.dC|tv.bz.| :Mz \!krD_Cwp%C2{x`<~P`c,VSw0\oȤEr%ɷX0] VSj6L@=4"Km=sml\ ZMa!I au7E%rLL}ڃ T~ߏ2Uq߱x/޳TfgiU[|g|f\{ MumoLuoIvI+pjIj"`q"SA!5S1c$Py!lxB U'9G?/}k%sOyX_u'Tj&A[鞫ީY̼ə=p].^y }v+GY}1+@hZM&l^mB AςI0x!㠀<(xqFQVWASn{o<0~Niyfsu$W]yI߹4:G` :P$؞={/ 5Y=B I!Ryd ( )ax#C^Ui}/+ә[zj *_-o_-&j, :gn>T+cy@g:Darg,,C7D na* BKc"d>1`jA=016!Q̘k~;۾̲\mQ?g>` *?c'~@j:/൙}oT`&AKV# &ZV b"`^ @[zZLa$2 @p?W󙐁P{f gP'Ay۶ g7]Ϸo 5Fˇr'xxMV(Jb6`12VGw0(З4HAL!1\il\!i9hh>BHzjB8#۹[nfYW_{ޚC.ko:0΃pu be4AHuP=̝ ;h_f; K/s @r!2زHXBi;Sc%b*#*9b&l), W&QΧz[׽rj=3^u3l|g)$:3@. $6wiB])>MDS` Z"_ t %hIbeW#h0uQ'O A@yh{QK: S6PvVtР^tf2z@uOAE,a{3N%Z?'sdSO4LLDŽO磆_` 3JbjdP9>g~ R }<U (!0C0?= | $ !W (#Q꣝ثXS=X}!PQSV"rA$v-'FqZBUgs ߟņ`7x Ӳ"01`k^P遦/EL+H;`7Ƭ@XHUSeֳ /6C <" ]U7_NГ_B p͟g'G(0RJ6Zyqc0"+`73a:1XǛÕ#ax)+zN(l|" C!ĵDj(!:%Lҹ  C !_^؊ukОz[eZ71W(`r1b>5bt!!bˆ^ Bh x0 FhI<ߏl>Pm~\@ീBde ,0@h&&hD&MA,!ME9\{UW hÚ֯3ww D<ӿVP\Ɏ K/bx' Dp=h .W';>xBB@b`b2 z/pm})?XQ+h 8C/O@\B@ně ԁL~" ?B= ZS@gNS!&)e7p܆C!>K@ԗh${m}Cu8ԑlǹf5"QC2gamd>W` \3.01}0^dP)fɭ4{5%d΢IS~_i~@;|!c;r9 ފ Mܵ6/VK.+)k( "I/FgiO Gs0jέ~W5!8B@B2ˢ5M]> AqC`pLC^gD te/\# Ǥ$hr511yȯL{է4l! U@ˡyk YtflT`\Ūk"Ralv{x>:: ^o:~IzߧXw$Z-o%ѵB/t.]@2Y7fk$=k`+…@#$oZ9}1PXs?r0|!`bp  "}^| 圩9AW`뀭@ƒݪ@&JG5c dKdYЇ4J?:Ć=uL4Wわ QN 3 z:9œ=> ?V-pǸqpBs*{ !XBABsn_I`ZJӘG4V@a{҅\kehL[/zW)+z t3&aY<6z ްLUnМ~0rVG.W ju`/BST@` D.x1*4 :Oɛf{Y>b>pV/@.CY-z@Ir,`(5#?Akx)F$l-Q G(G?ׁr].FH Clы>#ȃ3sLtcU9bnA2s]Ty4<rmˀL[ YF5xjw MaC|?) } P[2!jaJ4@VlseDR ?^)D`N6 Ӏ-)Fcc vDlȁ@"AA&(I@Dy ux$c}t1"|myJU}p6Q86i(_8pٵ3G\CcBHkI.@kn} ">Gyh5qZ5fN4X7Ǣ)ؒ  %U 4ҊL"C6nT/8o90A8{9GcyH!~o1#J)N|@lΝ}w Pn/IbZܔ 1osa>7= IA!XBEk!H<>{D"SDz~<DJ%: 4c<*JNABP0NIqlft`Rǿz< SXNX>nUM1J-n@A?nc>T"M4ZDKS&6T}k`gx5L(moۉ .:7$t +2(B @`gBwqWr0Z1"FkJPQAO=2iPҤ"L"КmOӄL@GF~~D)px^ bTl+ @1uP~9q@@-("CS($r R(]GU:'s8hb]RE`t2DuF6s]C__7o%me 4"r!(.3((d T' z<עVvP҂e=:rƒoA%|D:02o*>yt-%0kx̌bTR!5'F/߿6*8<&B83:ˁ Q։}itd`ʰ$f+#ms p j'E"_[H*\KF*:Ą `ޑhg [ !{>N#x3'7x?{q<8b©1Tg6X=|֞Cd.1[4j.MfXUFCJ@P0*Xnz(B.#t>ltcfK`|<1" RSGp ǔ:!,y˅xg*lױgf3ΌTY}a}_̞ۑz%D1 ^)\Dp+. $ufϮfbQttX($P9RIk!Iۙ~4@?|Iittf1U7{Kwy_Qf륝 ֤\q~Sik!G$͔T wGxPc H_Ԓ˶AhN+ x~5Հ0Sデ^h~wgSo>VTROfPѰx7TrjlyW<sf DXs;a{t.3+:T,EgNrK~⍪>鰾w2V]՝ {WR]R\73;9^"n V,4uf$- 6j"u_reGҸ>E @b?Qq ڒhn6[zj-НB֒6qgqC%(\p/D>Ú+{_dM炸ȴc~e),$p&?X 4谒UO [ҵB8ai26A`@XV7FfYe aʁIH[25E%G5% ^wg0RliVapͶŃ@U`/ Ȟ ~üA X99,@ WHcL+ja(X`G%.IC N[J!X݇`_0Dק d=-Ҭ=fݟ?y j#-Y-x!u4 ]yչ+6'cv@"BY-"oABJx(yLF"t.*14kG-nxb, م3+z@w5.R;H'a%^i[0j&FۿܦtSC*k@ׁquP"Q^!XON(lzN/-U3$35$S:t5s)mDvP p&8ܱb8e#m 8/#oG”kZq&M8`lqZݼHjȶ YSh`BBg(ZHu]q'TatH!t0kF8 D2$v|2MM.c@ šϜ_go?k4Eݜe]Cy}Ӑ#|Gyz}Xe FAF^ȷu aɽw8fۜ|!pgs(e0O4dVlB:ɇ/5<&P)sDLw [=#k&)nR |å]BioϵZd4hT=̭tk}pÝo0 13Yּ-4iU8,C`3A`հWzhgY[al5jh<] !i^)yAmX_x}_e=lV0Kh?rIi>T3_?Ƥ,w2&AJuH%Kͣ(Fbi߼Gr#ݵ6rm͚ŃPABgj'4KymKgu.IPqjA`>~ס&([8fW2JbElK4]tѸfՄ -p}}xP+߰Bnt[[JܫMG~P(tVGS`CpAWӁd+^Y}s߲$Zr)""f@=tSy {IX&RI獙 &VA}Z9gXo=ߔHk4AchtiYLwB1{iWno 1^v (0̔DP÷6q'48`at!N:lG_k :05AeAT0w^3+ezklg['@*K-9Y;k/Շs>xX*vUk$dPCT)<Ɨ/݁tTORBEkFe: ]fLL$d>ڑכS?857 \P(<3-q7WkVy 6Z*U@Giחw›/2[V5̫m#Fm礰jklZyȘ23t>*oљ8>ԛS DhKkVChX [8ھn)ӯԵ* w'xP~[(lfhɎ #f*l`PoXv%kjrQL@`녕f\8"56B,W%Q4] wYh͠;Ғ,qz⓷{M !N42Tc\ZCbv*Ww*7 mmy Z%ynVqluÅ}i:[n^:TH֒ D ÓJO|KPkVYxu)t(8rIf;eرdyr} 6:lrB;3=E%|c47XӀsכH)2n~Ua۷a=(] Rr$|DV X_*owvϿɹw:^M ꍹK@[ (B w_/")IOf@CaK^01Cl۸J:ܓnS+?z*e5YvW z:RHYr.]|ѩ0]f:&gP;e7_ n!$`\n>.iDc2t%FON=3]o2G>6r~jZ|'(P Ԅl\sn^/o{5zCΣF1 vStʼ |B%!L p&v&R]\ywߺӳo(8e8\ n69K]ԁެ8O{ߵ-*hlv¹jb+VĮ[&CthIe1f^~L5KknW|m[G?M-u4rD&84RH0ZG';QJv۝𦷧V!cVK.ĺ^y5|85_פ a.=_4[UbP/ jwUn9<³tdLYuK/zrpWl!xI=|O~!bJe-|e'[' J3r @>!ͧ,FNgC.A4u}Vtil@K19,QaBH_CG6Ie@Օ󍫾dBF4&mz;@ǡ`FbD';ʕTO Sef$UJ83XUt ȥ z {(Z3;Ac肧*ZoXAOK d#eyͲX=Hײ,'5?e8w wާЋMU%HQbhIXm]vAѮՑI]YLE{ZxΞUOl}4_$r&Nf_൯4Й'O:2"g"싨񑱦&6:Ui =Kp4X&cܯE ^,ڟ';?P uMCN!yu5vf ڋtBZPm.{"NoHNM*{R.ȁ  LuPT-ޮ_x>c\>(H3 _ D{DaAϯ>ut\MC_ $熲+ "g\xۼRW&͙j6Q+}:ıkaQ`l]J~sguձC m>>@ A@:z}YuSw\+6).LB-ڀ Ix L ҊZAC!"Rxfc`/ Txt/>e<6*xMEm$q{Ѹ jV{f/Vg[M%(Vw lvݭdVxq?=cɤ`u8olWSf82Eu;r^ᓓ;q_>RQ=0w^-&rLc7&1E ^q{Zfzz"a]vѮnXby;'-JԹ>04QӶDY~ac^Ӿ_v'?綃{& 8ipx4ZSqUmh[eXVkr4پeݍm[]z/:6Zӿ ŕgS!0X,??dȤtQ"[o=fx'T+}ԛ9ߓ0>;^1joYũn>?>TF$tܺ.iVdqLT86#pvL 57==̿gp|r'KOś\ZGڭk8vQ.x?'TNȁ"73XY/ǵ?X xgp$3!Ao $&ЙmR? ~Px/[cŜ ĵP]K_ti1M@?oǂP;:2F?^I-7b>`oZ篡CKwFlaBU.RC7@)Ԏϣ7[8838o|0? ${nMCB\6t^'b-_n9y̬$:W%x.xDT<NVqF] ;c擙_;ڡXNΔ ͨ~/[?@Y4}>;@Tup^9/|#l Ңџ_FlGTp-_l$W]I <؋vT>$5M!C^_΃gGsN}y=[ǖzC/'6(Y*Jm{ e~uğ3rk *=IxwJeVJ.|$σ8cٟ[w+jqUzs  P-ւJ(٩s+ ao̜%R {ُkI.̟r@ݡ=ڦmBhonxÔ*I+kA"I@}#5$N!+ ϢkB>  q>gR _Ӟc{,5$e#Ag_DicF(̤v0fj1fįl5f"_=LqJ-~lLB&|ZHyBT>[Ey@T2˷DE$Ѽ[~.kd8BnKY3H}ʆ~.qOŻvCjscH %ƌmew[3v.b?SN@%v-)ж:2-'EiJ!W #sGӈm.'=20V_ $**\d+&FE.tJN!H>Z.[zm]ykwwkEvymsx;ĥ훠Y|%/c 8c]}/5EWR%=u&XE%95C-!ei36\,afc#(I]uDŽxZGoUIiwgSuB0 p)"e>^bHU8bpmnf'˥ Ίsk5 ](SͅxpQS6k ~n55e-ۉ"&N1`TY! NR^CejG|ϖrl#2\$r1j7H2Oiy&[-tE8[T:Ii#Bl(~FvG\4v8̥cB?Y∂OA )t@Pٚ N?Y 3"_ŘmL9I@^!c”"fHb,eMc2Eg3Cm Peɼv\@N`Ts6+ wQj=;2d±.u=1ucx/E7yoJs"5e>TJc" X#Z4WH{ʼDЇp,bπ_zuUf"BY#24$Kڨj )Th(E{ߞpJ ۸;$aTu J-lSw>ȠIwK9D]t&&(`@WV o`B9*PQrOs`$>P\<[jGRsaS) B"\L{[0ӢSrF5]|&)YE;#Jb Õ8Нt}.bekl .Dd[{2 IC%yEhMxqXAE!AH7v[hCvYyvctKa7T aGzE3v+owNe1΁ج#%4 HKBr!՜:5Q8ϖCĚIסj):<&t#_q:{񂡄ɐV&}/.&)Kfuh9|y)cY4--"^.2FC9D8H*-0&\͡QKTC${ -ok?3<^\ kSb$9C!"tvܘ5BQڙLm %I2tEr4BqݗȐ{)y<#B1 H1ʱ_2lj%*n{K?ֿ 5IЈ\[֞[5sAD,u'kUVlA -A| m 9) kJ=̤c'1ܐwp BJ,fLy ɑ#ŭJL?) W0+CACHsU&Bhb %ٟI;i"[Ofz# )mqAXS Gmv)X<ABVbsb3I6iG Tt֌nH2 uoCPbyg4O>~ S =J,k1 Z=IIt _% !yPI< TjBb-v1I] bE6O`TJc"aLrEM ͿAx՘cC*,-t&e-!< R9w,*I㑴g`D((i!e)ڈ{/~Q8 {OCt!p{1 Txy`>0'I;S"P={$C$d%%ZBMY$"x8j)-/P~e^r;*%y h)W[Yj:QO=<}p2ֵdW._峗W/uխ;G~ǟ/;romg$cvm L#;@&Y/!ߠE z2@b] Ia)  sPǚ5~)r cD]2[K9)@ɾRi{2.)TȑCbF cib| dR3oz%N^vH]?oN<8o/[FnB b B `C^0HȐ$12* Y O  +¦^ɓyIX|5B*֐f'}؍CŁ(lr}~R Mq,Ov$f)g>J˔z#K<rH@Lb/*M0w@hi((TÈ)hj1T(Zg_/O66.G}?^oGμ;zƥ䇾t#Cf3{Pf!n/1JZI^E쎮-R&xxkCPxY|+(TZ֐# CQ oaxϮ+-Gc:*q!:2<8EڐcWx~Rsa_ɡ~&q'3w_$fs0C|v(qx̥fED!Q[A> .r>W% |HG $+/bk_v]~դn2??zvWV|g{?1_>{|wOoz3}f棋ʴ4#i^tGZ'EKVADt!./oXa"FPs=(V'FO:<w;tƄL+PHR\f%CO5[32ѾEN.gR&?q"Kªt6 .*F3\49Dz.ԗUeG绔-8N!5Yֹ>{u%vg>J|$_RRP1e24P)/4Ohs92TTt.J5T*zKۦr_Vk^R,}&cӥ* *D+ZՂ[jN$*-d4&>LS`!;ZY_:B]TB={LB1^w sWy0RG+cz3Zb KS|.jh[4PL*gƯL+{ac"BsWTx gg D H!Ag^w[ ,/iɞLh/kZUDCU$3r/Q_"v [TIƜu&7ή\Ǒkj_jmc ޿wgLa:woz5TzZ==s;\]=u:TyQh<Ŵv˅ېuV'zDo]fo{ZR'hwa>n޺#\^U(z錟ݭ^y厺}ihz3 P^YY+xik/yrá}_#]"!F 9ܶ8b'$iJ,վv|i|զ@j r*1J%;9;K}0e_{ay Y/|?yJ{/!}{Q")+.RJgfǟ;_ا3Or3 x.]W 6V/~lV)RϩхGWorΠ[ZaDC*nvR橃.0ӉN?賿{o|ˏ^+$_ߵ'PVxX}dئU)ao>D7!W7B'v-Fݬ̌XS@9Qx[Xģq&3ς(EQ)-RRUnNqD^S>N G֫86&^/IŠLȂvI Л_<ǧo@jR 5.,/j}c ÎczBwfJcADu;ՅMq&,$>襋2VRq1C}ZZP[ɵ@ծ;b^YӼGAOMܠ(TTQq 'k}C0M'YǝU\S$ H%~T|C嗠|2,\p2 O*DK(6B۰ڳ%IB2'sH^ɞBd[{3wa[,PzHכ=K,/l8:^x˃FmQ@ k륑:W?CI(5a8άF]X+wU ʗXlԩ)LR*t:8pzm5Z,̙L{8iBvwRQ+m˭3QAVCT}9 b#,& WʦD oOys% Vzֹ͌3}_G S^(w{k"WhOH|bbAţlK&!p ]T4q &Hrmn@WA&SD350vHObwg6T}鴚)@=}F|hqaFwͥ/;XՓ:9?:E\d11Q,;=5(RL69S[rv46UjHu;,/^0[. +O? Oj̢*c鹅 C:3fDḷP?.YYd@qy\5ȦF`ᒜAG> N!3ux6ʏ$t3+) OBH.OӠ;D*[Q"b)E;t0%mcCe}v ą չ.ݥRz4?#gx\ݞ:wQM/}<_Fڹ pF]=Q*+J/7D=<cjlX?|o땷A[d:}S>̩\pzn~}cI猔|#aO ^mHJզ <~['< 5$V )c͎ƅݓwd]K}t۞*B'u â?k`f_ZRjZ<꩓_)Q?l7{-î{kх.]NIJB$:bBask 'l~k>{jm}}7[t{ɴu+{!MSSh&KTJSS$ɑd:٫;/Ǔ]|5kX,w: Qi = 4Wi[Aզcm  &sQO~aH(Xy6ۜR|8@oǧ <̦|J`$a! r}& 55Mhu^3M 5?Pm5{\_#Þu+c fU2XQϨ3ݥE* b>9(SN<Wtz'?NozysG2mOU]ө.ӌǓ;1L6bLl0qy&;4j%O7蠢9q%I 1pCEBkiX{Bvj-(`QFM [z⁌ړvI]Pic 6D-܉xl(>1o,iTa=j<# gnQuGšz;'om%/Z揥\^xbdu[{y^\!f=աMl us)﷿vtjjLo:|'{{2(H(UTnEmq[|ԩD7rMIbX6o&&: $O+|)H,vL&BC St^,9{\$>l@+ʲq%$rєͅa%M8˃u >p=BY1!sU OsM,&PK.&Tpj~^){eQǞ|p07WnNTbduӭHʃn^;TtG]أjd,8$pD\jpַe?ycVtܯ76uU\[leMQXdQ|Xo$4`ZbOT4m"5DXSJ F`F'DD>PH p_Nvyz/,2Ͷ\k>vX)ldxR4ϒ ֹ &CTLDojL hsUJbĈR$Uv.rlڰ}nqq8P[_3=55fW LFΪ ^֝ :s뗯^]y]zbŬgRϏ<1^9k^*1Xvt̗5Wy y}s_G>y:7vzUn4]^֯^-F;nW$*Σx,;n# Xƙ 7%jG2((!Rܟys] ^ZNCIT^3A(0Ňg2Z 6MZRjwʬ!ĿF9-:XfFuZY|]~K/gNABS<-[D7ed:=wq>q~^8}|q?^Mo}3v"e-%#zD7'5.17@^8x up8Y=  Q቞^5QL60pR@ AزE1Ò`ZxcD`8#)$?*$,/A4$eɷ!tUJ~{]G1; bKS/aQjs_3Zy~ƽSc skæf{Ǟz4:w҅KeK:e/?O?oO>7 34jp/ ?e 0Xq-u7Kh樲)> S\A>Gbtd fh33~ 2|3]RlJy5/SG}SRHAQ3qd)*6V% H @)^ &'GdFTK1,I<~#T-rMϠgӲ2d甍^>J9۳/[zoֹ}Kju>dc7hR5he7V~iA8W# +4nQtJ[eܫ`.>s{-9oس?[]Pvvf?; 3cԲϬ`s&ДKZ z!bF 6`EP4Sp}-+OQ@Cn4l0  Ub54hdd<C7`Pk7rFjp[;YE1ňH ]WR)&hY6 #_S3/ \v^s|}vRUh;#oz+oF]\W< CٍcЁ܂$,L&W;-M7wʀY`:A+عS$uu:Nx#?O><4¯BV$\q=]*é%^rIh!$u 8QhwHzFǝ .-f̀+OTRZh1 lsH8@etԘF?z;^^\+Rko߄ښTҀ5UOژT[Z5 =xO}=WXVZZpiEȔ!uՂgίW?O#7>Wu7脺$D4 \22[18pY`(Xd5eyVKG}8"g'$ țlEu& pGANTK7$a9Lo LJC7-:b"%Odn^~&K hRܒU΢qvޙW_V7Unkujj]j5RT>VjTwήhO̫f+V=~riOgvi`~XFk?"OLz;N]U\.:T:^o0S~ OݿԼG근aNQׇjlN FLe PbTK۔ΓR0RE2^rL<A>`Жb*Tf=bU&Vic` U/ nBdwc_3'۲|r8B ?7VL `jͭ&{~¸ƹ~Hw:UocJ-=pKN*-ۗyY}}/‡ₚ{Ҿ: 2m1턳2NQ<n?O}t2Io0%*bfjȑ"$)>BD}&D "iV*/pЉkn*4F7{ɑFaQ쾃c ^uh;jWZQΫǟ>q ;Iv|0,f(Mw8TsH:41> L'?WmFԩ8Ӻʱ5ݬF[)i$ِ ).NN4n$8V3XĄg[Zݺx{?2o۪)Wϫǻ~l{bzZ2}{ Å3I]aqoJ #F"Aٶj"~wx2}z0E[QmxZD g88(? p,F$P8DA8h`6FB ヅA޺[ĝw *8kg|p'u4QMcKFZҚ nx7֗{K)t*"wp8zG3LMPZ%XI9NOjp%jǑ0&YkntŌ>%"Ux/L9QTcdoخLSQ_17W>r7ڻgn~fP嵏}{/7奪hsB(T4®pиQB*\:d%D NQN{W)F'!Qܖ3Ror"ui&YJ$e_[,M6QELɮu h܅J4PxM_3lD.(4}2i6 (LO[j9\G/ezxk}2N'>[gza 5B:NzӮrNM fdkL/X0R5I<@~"/K vPO@,5(vuM-*[6U2l حBHjbZd̗lq f$ ^K3g0^% K$0eraԕ.ָm+֨)5g+Y&k6;;U%RI[EN-^Vr/;x4Vw$bUSUG~sBF"\痡Nv +AzcwIϣ{KqpaHs]B, 硋.RM|UNmCa'FL'9͔H (hk)!N׍v0S\Īi'm*Rj)ͤgR֓/v M 쎡]Ո5wF>xՂo莞_CԱ{׮MSBӴzqGFy`c&#;.4S QA@kņB(xB^4ab͔lnA' E$( L}&S,Ŕiv៭THd'X>"Z$r`78c%jTҝj('ۡ2k? [ ;M&+Z;hgq5 ޝB´P@*[b9HT(E 6CU=Y»yr߀K)ھGD!b,ب(Ӈ'[읡KJCN|FElk:&kXW}rEr(QdKەi$};됒Tlb¢xQ4NeU }ZMɏZ 5A#Ff1]" F?nf(Ii1g?Ynix RYv}#ï ѩBw2av%k1VC? B_`Q}y ?qdp8m(yP~# 'dg"\7Vh^gZyn x1sS1Uxj,YҎ<}/=WJcvdkv5uWfq'cŗ 3Z%ΆqcMk1Ĩ\yZݭ/CqddS Q-ba42ak`F1]KǿPMUdxqkpi4qûRv&*`cUhVfdzuW=~3eTCi ~ 4]&GhBj1M26QR#H_n\FnZ0zJKmZ5ۀ̵:ԮԒgV)Q*:_f 3.uu#' z^}6rN3 n 碲^RkLޓ#}@Fy'ar]Յ Ma* JAqˊNÃ?U\%R"<X٦(D$&&,띥 ٠ZTM-j Suͤ"d ⩍,2"cQ'++wW`6pޭk5'ۮC8kM)HH'fɊ~APJt(Xj$HGD\ݐy} (!:lQѕ,Fx~*yDZ kjdr;u/{x9ۭ-Q DlgJZ&φ) s|"j|tXwl{_k)#jʌM'1ndԱ:ʧMV Gam[Մ E܌fH[ybhM7-1Q֓+z{8̠g=*G@Ek2:%$+K3qG{ [g0J=&éQ5(9RJ !{ $,m&@T.9X0  R q d61JD>p]X2iS ]MkգnTQTۊ10e:l4E+=E:n~CXYFMu#3jG4BĬVRK6N4m$HZQ+9Pv OŽ"zWJЦDC8DY.{c!$R3!J:謜@ A-b)*ݠg Jڸ 26.Zs9i(onïڑ뤛.%70.Qt$(nhzLb2]2Hs!`-G(1jO !AqZrEp_PycƓVǩmcfsx8) 5RF<(S]Nf$ -MT+n~}O}׳+g_|m)`SIENDB`psi-0.14/iconsets/system/default/disco.png0000644000175000017500000000161711305557613016754 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbܵ[|w.̠RBELy!RÑgGdH1Ff,r/Ѐ`cb8ntgg `b{ d Xg` Qry# v(&@ՃR_! ~\/(]o?3'χ*?v3Ȁo/dnxX;ܯp8 . B @&~{&KÇ 0pp3(XK;+9¢% 3e@cL ]T}fx|O.dUA&?j/3{30A,;1#*,//!6௽@Ǫ,7)#CC3Æ PaK[/a |?Xr''/ <, 3<L_Ff``5S+  d'"VetˉZjj^_d@033|K*~a-``LL pIb+Ù@K >?3ғ>w>5@IENDB`psi-0.14/iconsets/system/default/show_away.png0000644000175000017500000000164011305557613017650 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڍ[hSwsIIIjh+[TV+&D}7acna8|pLXhKzMc19g}O9U1_1*5mteTwNm{FPnž-X~,GЖeDġ}N-7}qx[[zJ| aI/M&i*lT&m_|yk4Ɏ,͛d->W>=0Qڻ$:G򢴯'IѰ06EK`29[d^P 0_\[ ͳUflmiol,ǦQ0#"H1 Dɥ:c+VGC0un03`eA&3y3u%佡dߺ+PRs;<9hgqp@\E*nQzh2 TE_.*0H-mXͯs] =.'4\! M40$EBٹu`#l+VPe׉;6(E5`vSSKs2fytx" ai ompbrRVN]rqn3٧!ǿz1-ɸQ7cOLA` <#r  ߀Ћ\'E1 xSIENDB`psi-0.14/iconsets/system/default/pgp.png0000644000175000017500000000105611305557613016436 0ustar janjanPNG  IHDR(-S&PLTEvIibuABVi͔ÜɉFekzmn{os|B_vhiw⚇kpUm)KhѡxxƢYqq~|oodO؃Ԙ|ǥ}IdftmǮhrĝxyykgIz{JL_Poh֤_SOLHUBCWRqA_yz0Fo܅i/ġD)"k2e-Ȫe{ P|IR"=X=n)4ZhtRNS@fbKGDH pHYs  ɍItIME &2żpIDATcd@P ~!`kWPqc@P o4a<9Fc 9T#=#~'POm `A12@vz$Pz @,#B%0-tcmDVIENDB`psi-0.14/iconsets/system/default/send.png0000644000175000017500000000126011305557613016576 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_F&IDATxb?% (IJrB 15A4f@;;@ 1283 wő~@,w^aЗabfI#2 oc8u@zaKQ#5QKU6VF¿PDu?00|3\ ĸ ǯ`JGA_7H@.ưsU_ Ǯb mlll r ?}r' ؀00g>a_`0 (4Ad?f6u? " 30VFvAX. _@_ l@? L(~"icfg`dab,@o@ rY ̆b FJ3@Qb k>q^IENDB`psi-0.14/iconsets/system/default/groupchat.png0000644000175000017500000000204311305557613017641 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbd RyEc`~̹aO D ;C!Ouu;=ckbO[pg3biV= ح&, SpqN^ۇ,&^veNob1f}8bf#]c;2:A]KE_]8Wex| ' j ~NdwÇO| >  0~L A @f!)$%6155+>b#'`o5Ж`qrs0ZC~p̙E˞G q*gl$(޹p<|⚶ ԞMZV-O P4re(4oQbe+n kͷI&6r/IrbS| @d&B[3c^˰(-T?!C~;_7 [C#?INHDT6J[980ʕ _3m] %|azÊo/O3HavL33')%sk1{_20}.!G)UU?^&g}AKVbq):O @L[ X00$|p Dc~߹( 45EVV vv{.C@ ⎙ ne@ ;b(wr>cvv+? [v0~NڣIENDB`psi-0.14/iconsets/system/default/psimain.png0000644000175000017500000000205311305557613017306 0ustar janjanPNG  IHDR/\ pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?1?X~010030WFb`pR16k^8еCn0@11`F2/ ,EgU4~M^!bj&Z XA@t蜃Lv.B^F( m%ϞJ2|/ |d@ ̡""cuzWz) Ϗ7wvR-[|tG6~N<@ 3KR`d`tuc&[ t}ʥ؀ɤ{Wϟ4a㷟)=c ^9v2~/Ѓ xrjBwO]ypLB|rʆgҾd.% w/]=M_-k}y~氜C4w_~u="UB 4S%U!9/|ꐚ$Η1?ճɖa`n_F7 .fcfߙٕ4$-8^ݽ}9^KtExb8y[ s>恰4 +/^jHq21~|ϬG0@A fSxLgg]W?g?Va ]0Xdc{wq U2 b痍ʉ0`0Fbi`~f=߻_ީe Db???>U||`͝wBrIENDB`psi-0.14/iconsets/system/default/search.png0000644000175000017500000000200111305557613017104 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8e{Lǿ2G5n`TNV X bp$\q.im!&_RWD_8m&Mi&9J97ӪF{cQ\V^ީKi]^~L\򩙜]&[kS]²nKMMw_||ѱԝoөD4[5򩉜6li%jx-@TbWzz#"6*{4'&g6`WY=j#|b{С\&P&SSg4'+䌑\q7ƭpgt.~}}cٮ 6~?ne~ݷ,^*;~dvB*l񍨬̳!y^o ئYߚYq-WHߌ3f8R`;z``bM kSj+C\ m'XiY-xN%& b-Րɢ}T[!ƽp%~>+S],D|6Mڽ8i81`l()c ;絗PPyIДqrY {lR MI){3 .Em[:ᓚNԔqbSE, ;w}xC&W%Sž t/IZBȌ%%M񅜛[""R r*b%l8*ej(!!)FX\$ J 7! H$;qTlt% %5jtIENDB`psi-0.14/iconsets/system/default/url.png0000644000175000017500000000205511305557613016452 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbTO݃ /1usg%x N~&6n2kIJAI iCRlP? ܀~2?P/ï_$Udcc`x??Y dbdRf??>7o߀le hNj 7^abb ׺8-Bp̭"P70? JQV`x mW]cyw/@1)2ʊ>d(igdbe`Rb#ïTaÖ7>][ :@z.pg`J20s*IF`}WΒP`x[gy};PWboj?dXN1YQf]-_@ / TsRb|879:uzOV>#8E mڎ~]2 XY>xd)u`4~wд3 1|f7P9p(@,`dgggdf͗_O102013)3b l{nbqҿmr#ߟ~~mέg0_^{Tq L`,ECEMVEi~XaBF FvlY3mENvCsjPs$@,gJ~030i2%(,\_ _Gmbz}d_x~p%}__: "EXrw 4pږWp_z":sBֆoHa4D<t("9 Pb椱R^#Sr?Yg`bՖW}lZ`%|{g=QGrXNQ N46M#W|X(J򆎛\@$4Ϻޣ^@k.3F Q[0 VEӦћf"[JB >IENDB`psi-0.14/iconsets/system/default/gstreamer-logo-50.png0000644000175000017500000001301111305557613021013 0ustar janjanPNG  IHDR%B @bKGDC pHYs  IDATx[lיs&%bYl(8Nc6E({Ahh/Cn.t\gkiXmYIԅ";93}s$ĉ7n(9g?s$i | ȷuiB.ˠi B8 ^/8׻4\>j>La|"iZĉDvݻaV@@ַiŋp,>"ٳA) go02by"AXOӴ>;w u}fΝ!H&RHoX2$2 ^j՚pQ]d&ay$TipsA pmO'45AK \V(1H$,}T]kyAX%Y0Wp}[|t8LeH ԟ W Xlqn@Ǟ=:EHY+S7xdgkAjSN199IXw,7HMCC%._.33SCUM"Nb^6ovIىi :CC%|s+28G?ڂ- K2͞f=ٖa$}t+++SVMp\wD3352zdREot$8qqv㢥Ł5LLTyR,\"qWSC($I8N ~G^GdY&k#ZY5MUSui(^בdvC#{]]4v> àEm_iMӤV!;dkJ0-pL_2Xjfn |mmNQ.B!\"dRIEgiG0 ͙3g(Ȳ!;BȲ<ӉimK| ŕ+W) ȲD{[1:::E\%bvvIcK".#LNNDx'lϥ q &IRD"`nnL&C]#I0XDqu1-..266alݺ J(=ѳZ$8BIhqܼ޳e8DB&~z200wV(\xJiDQ9o{υrŋj*;Ρ G!N[o1==$It:`rbd2~?E k.J`}c|>o}JpWIՙqB qn&Q0LB!p&{⢵huVZJ HZcl'-GGG1MO399ȑ#iF cOn( Νc||4)kkk_k%Vz»*L*j*H@8,s}-AUvI@'NDVktvvSiZ[[$ɩi* nCtcnn Spܱu\*{ӦMmZ" 2::lq}aLLD,y8w$9b$:L&il۾'?"effja'(K=ADutݒCCH%E@l&zSS(b&x{J.uj{vFf9C0zcUܬU 6ش725U3djmttż{^~*9Gb;w^t|~r],ATPo#;d >|&\>gDY ^w-_S.0KO}P0i躉bKK ---v؞K)9D$u-:yJnZ ޽{W5ٵ;vok `Ƶ1Zx<\. <¸J&P( e*>b[E`Q9p$mzH@gN?DM*M-rv Qoktt .q݈HS(dJ?7{e׮]5]AӴkڲzn%g_eݻw Z[ G`."؞P((J:櫢(,//f(el] )BX'fxn7mQ*̲}o$rs9kUu+4d2hnnf׮]v]|bEW=ʿ133,Nž}N2iyh4WU;$l߱qR 9u+++ D8}@^/Mixs ^6U՚DQn}=IQZ:purl?t:$ 뺝x<r9x-U-..rit]矧8p[>{zz8vgϞ%FX_`` PT(J!"Ⱥ*(dWlG"u$kp@%ץCu._L>I"IiIn&$kJo.Hz6BHaKR[n% Z[5m_435akqa^{5j+++;uAb:tbH*b~~P(D?irj7of@Á(uR@^k%~??qx<ܹCXdjjZZZp8DQ[r9Μ9CSScccHȲLZE4KKKj5;(]7L.=^Q@}}}8Nr Vd2D~#7? *oo~C.kWM$NST8v>I]QY\\G}tݖCC 6d2I"Yp=>{禚\4P(PT#3::n'"MMMd2J#YXX@4RpH$0l˅(ر#lK.RX Y"Jp8$;vf/ƖBrrccc'ׇ([PiI t-ʡW^yEQO׿uAT*155K/+a߿W_}H$rHId2iH$BWW׺Eazzt]`q?41MEQXXXTCkuttܐEfggrx<zzzèJ"  󱴴iUmnii糲RD& LS,ϮVcaaL&c F":::lϖrHdmD"?e~(JO?m}t:}=.\0Ѩ Ǐ70 0;w;>saHB{$qСzA# )>Ibdd'\te9y$?f;vǏmm#pW4QX/2 DQ:::V,--!2Ǐ.[l6Gஐ,{yN<իWT*B!v#<¾}>ug9޷etEXtCommentCreated with The GIMPd%nIENDB`psi-0.14/iconsets/system/default/closetab.png0000644000175000017500000000102111305557613017434 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxblhh`01PdU[νR׳(ؼAį#:4( X9;@Aq?B ~ǁV@M}%f@bI4IteIENDB`psi-0.14/iconsets/system/default/browse.png0000644000175000017500000000207011305557613017146 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% XT1X0|/Ьc'^2Xd'_X8X}>v#uo}uh8?b߼_ q_9YQׯ v V_Yt?FEĢʛ/?  ??I d˗@'108:7@  &6V/L  ~`)_GRW[o?@C/ëtD,$0# 0@t oy0X(Á @/T~p)qn}fQUF  @~s2:O f/_ @sGt`e4{sßOXA?++fv1| r< : 21 A{! h4y؅N\g`xà wcxó><|{!#.c3d*Ѐ1ǯ ~gJ8l$.ƿs/by'*?P 3w0 70&_0>y;܀\4$8} 7`}H߿~,3#@U4733 D (yp{S3nv&`S_7d C0gdeamIENDB`psi-0.14/iconsets/system/default/configure_toolbars.png0000644000175000017500000000177111305557613021542 0ustar janjanPNG  IHDRVΎW pHYs  d_gAMA|Q cHRMz%u0`:o_FoIDAT8O\e܀ִtb)^H@#k,_` Fp],LlҒbB"1{1bf̹̙b>o&" ~|JOO'F"zRzg';k'jF׭2*>1lNݼbĉnZZbJxa;z{;/uW*|'uh<ތU4էfr(L" V O/SΜ9IdiBwݶzy<5e#j^<*Z_kkd^!H%=ӮwNĖeV]cp z{vqq(DQp+%'ZFMOO3?ڦ#Af.lq ǎrѵ=K Lf^  x871M&cxӣ:Ǝ fnrc!xmOesҼ @I(],jlB:_Sx NKW{VÄ#0RJ8]Me^F1W}{3\+=%RtTt:|y60{#4B03J)~rM<;GD/ĢQX\ZͧP(ir~o{VSR)/B4M5R lԔR Cܺ~{V5;4iPq7߮ m/ )Ljx_m*IENDB`psi-0.14/iconsets/system/default/jabber.png0000644000175000017500000000134611305557613017077 0ustar janjanPNG  IHDRabKGD pHYs  ~tIME( ֥]sIDATxMMa{sf2#P,|dE,(Ď+ Sj"Y(YHL|l4B4)wf{> w.ϣD[؇Z%.z$E8ٌ,(]9w>'?I$&V(Ӳխg3zH kWXNLa*m;wxIgNRl 5Mʂ(*m3WLs-K\L:F;s ߚO\6˼@?aehmc MR+ۦh)`bATHL:`͡:ddwQmP +]D^[C̝srtzZV !n.FOzX_g3=q{]Y ({6_."e'zV]u}B{ZwhlFN1=/H `^X@JX,w+Wql @-! #Z2!tO_Ξԭ9km_ {sx=sy߇aװ_ŚftɧgMVֲ|Jp3'aǀ=Lי.7{Xs lɻ<E7(uu"&ƪZּ2%!"g t?"I~h&o 9| т7֞(NO8&zGҗxAඇ|jtQ@u\N1ڢpiEwppsX1ȂN Zz p@(c(?r9V* (?;۠"<(dz_(@qƠIdM]%8$#6Ǎ@2 : .^ CD1GD041עVGHb`HQ:gb9*o1@[f-}(M$/+EisdtKI} By;eι7+^?,q7zԒ]L5О0u?{aJg9|ߛg$8gvx6c(]IENDB`psi-0.14/iconsets/system/default/changeacc.png0000644000175000017500000000141611305557613017544 0ustar janjanPNG  IHDRagAMAܲIDATxS[Ha~nӝ?4gL@VJYW"H. « +Ƌn " !$9ԩæsss_7."xy !3`k;*l(YdX ai14fJ|Ib^{{od._5ZkO1*kVnQ&dRB4=w$0@IRw&$*n[q夬 oy<㐋sggΞZCU4_". !/~DŽIÅb/z@ew8 xk}XwU.ԌX/JUG)?zp6 5&fD?3TN-zX|4U--PpU[m>{](Fkժ 9鮀PMJr(MU:ģQDq8YA#rӒ'@@3a/ع e!W@AL/ ƘwvG&/?ef' ̢lknHĤ"9-q|yN|UOC;~r"],@G\oC,a g-ED)3~%rzQqH)@x' ̲tڔBs< 6Xۥ ~=dH6xIENDB`psi-0.14/iconsets/system/default/play_sounds.png0000644000175000017500000000126211305557613020207 0ustar janjanPNG  IHDRasRGBbKGD pHYs  tIME3){tEXtCommentCreated with GIMPW IDAT8ˍkajMR*mn"RpFp#]HEW.tF(@,uSDlUBS+Mm3Wd&3E6|-9sUDE':ҫV}cQ l%ILn7Up i6p3P8tNi5(^IUdL_,eoym;:%,-]l!H0m ybi ۫Whh_Yԭpn [eZ Ƙ3bۖEqD}<|\B[:tgd aD8 tUojق)(?AO"6.U`A?@߮VR[6XJ-B _\͗ tH5`0t[K?%Hb*h'=!Wl(wO@4/-M{ou|@*˂C+E! չ@:w$QIENDB`psi-0.14/iconsets/system/default/logo_48.png0000644000175000017500000001041611305557613017123 0ustar janjanPNG  IHDR00WgAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATxZ t\uyjH#i6oWKc v|pMqMJMJB)i! iSJrRR(9shʡnk^0-˲vih7yOƦ,_w{?4M^i㼠 Ɓ0Ag h xq8Rp|479k LnqK=G5+]pCb(%^:_` |i:8o?ôܪmj"wrL ^=Dom/y;/{|r}9kqw!QAa*ɻL5&%7[fې)0vԄߢi*>;}{}ob" 硦3^B(Lh99Hd6,7zʂtbow~ZWK+Oddt$)S6Կ:+?{G&Ґ=ߝ@@0jASȸu Lr8ܟ] (G420@ z6O^xy~*A6<}n3ݢ CoʨG3'%Ag:Ne+\hgOg mܺz޻BW/9SҨF DiX5jt)`AJ  CD^X;}YM;϶^5'䞝ǛJ 1>K*\ }~<#~`LqES'qP^IEeЧ;8yOhCw vy jV3|PӇB\WV;ѝMr<*x Y.&a"tHzpbDrO MsO, nH^h24UFhq'"6A r2(%o\Z2- Wc;Q6z;/슣S8~s+6#:+` F뛙- :nGyBeNU74;ifjDKC '#1}KVZRD\w "64rѓC0#ɤ0 VpuR5f27̪ʖJ g8pۊd⭲d@E;-w"k27>)xKfLFh>ݸutJ*p8AeoZd媚Y>8A*\FA/qVYh>gʼd:Pc!弴ޠ2>rmG҉U< MVD۵NWz#/~8sQBZ% 1ޡb4{a-qIpfoC `2*+G׊e^jӾu (Pm'6QW > օnIb*0)^Z:?#c)"vRwmK<) ͎jg2`ycs` )zlР5F[Q[U@h Љz ">&Ӣq 9]Eհ`YiuӃ3gZ&Ŭ Dq) *3LSU 2XUVb&:|s(B#R-u0#nR+'\W?Uȑ@gkEF%whs2N&S)6ݰ} %crgRuY?.|ώv$hϢ))Li9KE.3T`}5L!¯gt5!'Iqjr&#%t?WPBl2Zq3ZAM%%%i.g+4ldRUtC%qX\FS@S `]޶9ˀQ|Evr 6;z`[pGQ`+ ټ.oL+HtDKR(TC%y Ĵ amcJqPA94uܖV=WKb59]\܅e83A>" %ջlfMhnci@ب{RGĆO̺:Ju)AJ;d4m) Ol&ɽ Dy&I;75aKb0[yv -'f;NŒp0K)_M)%|HcCݭail<;̫ZQX1 ")!8Ġ5㫼ۍCӂS~N" #N4CJTk|ozP myP/)dO"]+_$L#J/^=oa+[9ȗn]Spx0!_iղOEkt⥾l8v~4ݶ BA PdR?.ŨcD^K!8R4mK gT~,Z9SҨԠ5|/ %4~<(&msjSvNTjz5d4@Bݘi[^z_j({xPf>}g+X5J5=+Z&*|ؕ`G o@ߋE#x]H4NΘWk9L o%"-H螄jmiƺ>>g+([mk}ϘJ 2٤ϭ@ՠ0ꌄ'8aq`MM1ۅJzO0 S?Kb$ʋ-6*Rtpsk85 {KreچFz<|׎Xÿ~;wuNkiӦ?/nʱcKb ZNϺY{͞qI>Ӓp:ǠYJ|"B € 6FYzӿu۩so-$>m԰ih|NtHՅV#_< Eyl0Fq`w0J䨴L Y> Qjx^{?݁t(_ <@⑧雯>$tuOKю[]Fh'y0as3oq_vA}(P#[ص{KQ?[L2ѢԃC#i'\|_eEynڢJWs\΋3HJ`H %Z[keHNۨF%D)04(nZ?ktP^~?{Pm@"wAKD 0ިa X\^:o4ШB§^$L58 ],2wl՜4 IjRjj \]eRr` {P^ V=ngQRC0ߤaT,Ľ{|w_'| ) Ejk KtU#Z.3U -.8NSqqbpqel Uޤ#$;Di)Wx\:> ^nG+nR*WMõ ǹE8}}` (T o=4q%һ Y?Mߙr;#t;<*AlVWpMXcc_ݜMd;dr=>5t*HhZ 7iˬGf]p^:ʅ@01 CJU3O&gwk 򴢨]`:Aj5 `@d NIENDB`psi-0.14/iconsets/system/default/events.png0000644000175000017500000000107311305557613017153 0ustar janjanPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FIDATxb?% qI fRP .@ÕOAbCk'00 j1l  \b .g`APA$ 4+|Vpq6'03"j!2 BR  5 9TqЂ?c?cw0/9@ =ุep30 (@1! U>0p  r8=A@N/ 7=v!B \j8 @.- Ý@| ~π"' PpȀM?H hǷY%]}D.3&(?@ QOffl FJ3@SͶAuIENDB`psi-0.14/iconsets/system/default/ok.png0000644000175000017500000000100611305557613016254 0ustar janjanPNG  IHDRa pHYs  ~tIME '8ribKGDIDAT8Ւ+q_&DAp4'%3J٭ Id 'a f®Erom[d bA2â$9~ÛKE0 c{10>M9OEa5B1,8"H6j_;iCVdJOC8԰,X+ {%Lw|qY9gO1NzԆԙMw}Y\-0r2I袌Nr顖k.'p^C7hUQW \`~Xse)Qj.׊AĹB3餕?H ˜O !%3ig[KG#$#>ecU%ftjh+B (50@.,C]A7'w$FIENDB`psi-0.14/iconsets/system/default/advanced.png0000644000175000017500000000113311305557613017411 0ustar janjanPNG  IHDRabKGD pHYs  ~tIME ⡕IDATx1hqriZZh0-&zUD8tD:P*Ԁ {,lq l% MB5՚\rL,oyumni!HikGxiMMOwEȹGS&5`] 39tDӅ ~[*]8QF45e[z!i)hg/$ẘ HB!H$jLF2: v#e Q'15ebp$}}0vMR&u`|^²,4 P&SjmLV W E*wff<v!:c 5Zc=֏Ձaʤi~!TrM @irytN8_!A` ʳۏ1shh.*KTELcFe T%At|8xd2m3H&NZѝء/Iެ$ߗԌN+e$$zhbmp _%I4J_I&X'K) <- S۵o=83j]wIUI9-=nHP.+9ڳ>StW0y_!#`Bb;B~B XB[? .mmUtV:-70)@^!\hlreHUJNXkHċsh|\|$0˓@ F42RbM]vDhSHMAzqLj·Ia34rQXw]g;z+5K*H 71c%N1ʼ _'o:{J@拦XˆU5b2qR޼E-4;n3lX>3!] tnWqNkз/wꂤOPn ݩQy! g0xJ-5GZI!E<=w+=(G5 `*C7˥Qfz} eK7(<3>;G%x?<6 IR9g/0IENDB`psi-0.14/iconsets/system/default/upload.png0000644000175000017500000000102011305557613017123 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?.,#.52fHl-2 ѽr6 . `x P i?E$ĤŨVee> KoB4[(@1a*T >Ah\@,b?g_!n Ӏ?@}g WB@1nf򟑁)?,vO6Ċ1z c򜡍Oƍ b3~?~Ui@|k{~,W&@MRk>f`b``f`* 0/1 ^@p "ɁiFWDPcPѰHjh$IENDB`psi-0.14/iconsets/system/default/close.png0000644000175000017500000000157311305557613016761 0ustar janjanPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe< IDAT8OmSKQ~/i5;MMYy 8JbhLшzI#R!pJP()B .n.I~--ׯR` ĭ[1?$1 *<!lUD[[?>nY0a2RAkh۹3KXqy88tI"عs^Gɽ Vk"@(Zq^o9o&).<\DG g?*s_X={FǏ_nKLhkͥCC/y7n<@NN5U)P^~<d¸o;Ֆd[+*'܉()q.-zNg՚"#wH;uܕÇJr]nץ:44N8`'!@~~-**."rsBGM?DN;*/dz!"b7O? ?yk\IENDB`psi-0.14/iconsets/system/default/eye_blue.png0000644000175000017500000000130411305557613017435 0ustar janjanPNG  IHDRatIME  pHYs<<:YgAMA aSIDAT8cf3ĀH֨(`pΐA `iP7HIumU  62xyy؄IKKo} //Mqq񽪪ӌ u `466.zUHV_{Ł(((H988*ii LH=I@²s򗏏%Se)S{ΝywKa\򿧧7Ѐ`@t„ o|2s 3kLw ^`!n#!!3&6ypOȸ|yE&uIL_ŋ7o>P E0Q$ YH?c777:'0%pl'$&OX䙔 ]]o߁_<(-#d,--㕔IJJm@@l'2vIdPXXй nnn Mgɑ@i;qJcIENDB`psi-0.14/iconsets/system/default/command.png0000644000175000017500000000143411305557613017266 0ustar janjanPNG  IHDRagAMA7IDATx}K\Wܯ3w;S""Eq-utHRiB@p׮\EVm"!$"?ULLa&s=tx)$ٽ_|/Ye1c<>99鮮~+nSP ˶,d4M β*(Jotnc6B`Y˗|;wC2R'eJ0 IRJj?z'~ !mcvAA$xp8v8} G^{8mx4%MSz#۲,q" C$AkMDQDE!ZmjJX}Q#R0p]qZ.iR"< R  2$0 s![Ri"r"DkM$ap8\.S1`Yn*ۤiJ$q֚,y,p]uvv(> uw Q!Q$ ^O_n7lnn @%l6i4B`???~ |fyKtL5t:c1A 緼k599yVRSzGecchkk;ŧ_OMM}o1׃Vu~ppW[¿(s>"и9IENDB`psi-0.14/iconsets/system/default/add.png0000644000175000017500000000240511305557613016377 0ustar janjanPNG  IHDRa pHYs  /iCCPPhotoshop ICC profilexڭJPGmE!7 .1iKjI5ɥ6\?:>oPq|7A"dp3uncF5Aϗa˙Gi -oE3i]l>L)u ;ڂH[Wk6;V>1axap] =6+7Z"Qrw\Z5*VFf`UTݞJ=%bY դ'[x `npͺ-//P=gAMA cHRMz%%m_l<Xx@IDATxdk\e33gdf2dM $T]UFJ(nD7ʅ1/ BzVmL2ɹ|Y{.6r g[پt2JW>B 4>>}ZiZPǩ62n^q^,%[@Xb7xp$wj]'q1{PI!D#ՑjpW.m UHQMb-e0j vuIx٩b6O?ؑ,/߬T믇Ag7f+鞓", q*3UuQlB #Վ*_02axss;MofyŭBwObPm0FZtp"o dͷV_RU#fO+++JFEvV8UU0F:Nɮ.Růfxh)2$g~d2IMMMeo,--EQ8 Ba_R\n Eggggټj%^]ZY3jH$>ooo7^%A"g tLnłJ\oiIcggr庹zJ qFFF,{]7_>i*2r1(+2MЄ &,@AB!;YD7`so?=H,2e3@Q @X '` Dx0GYzZj? 02{E-@a50~@2;d|x/X ;w6ZjO~ ?h 9ƛ~| p |f`FQ @X 5ϟ@# ^?'T ad ,=WOR:`#/wA!n@ +)!*9B4@RսK_/>qǗaߙ9 "k yy IZZV[YGyN0?$8  %j}D3Ͽ00/p4ٞϰ ~0|`虃H 7*L?wO^2>{[x3܀W׆qBYKW<}pණNiπ#Rv_@́?_{p2l #`CX>IENDB`psi-0.14/iconsets/system/README0000644000175000017500000000520011305557613014371 0ustar janjanSystem iconset README ~~~~~~~~~~~~~~~~~~~~~ For general information about creation of iconsets, see psi/libpsi/iconset/ICONSET-HOWTO. This file contains only required icon names and some details about them. System iconset, is a special iconset, that contains icons that are used in labels, buttons and other widgets in Psi. And a little note about animations: Icons could contain animations, and system Psi animations are a bit special. Their first frame is used only for creation of static images (such as in popup menus, or if Psi's alert style is set to 'blink'). This first frame is not used in animation (since it's stripped out of them). PS: If you would use Psi's .png-style animation don't forget to add animation tag to the icon. psi/account - Used in Modify accounts dialog psi/addContact - Add contact psi/arrowUp - Arrow up psi/arrowDown - Arrow down psi/arrowLeft - Arrow left psi/arrowRight - Arrow right psi/profile - Change account psi/clearChat - Clear chat psi/groupChat - GroupChat psi/help - Help menu psi/history - Chat history psi/vCard - vCard/User info psi/info - Info icon psi/jabber - Jabber icon psi/options - Options psi/toolbars - Configure Toolbars psi/pgp - PGP psi/keySingle - Single (public) PGP key psi/keyBad - Bad PGP key psi/keyDouble - Double (public + private) PGP key psi/keyUnknown - Unknown PGP key psi/playSounds - Play sounds psi/psiMain - Psi logo, used in roster and tray context menu psi/quit - Quit psi/register - Register service psi/reload - Reload button psi/stop - Stop button psi/remove - Remove/Delete item psi/search - Search service psi/sendMessage - New plain message/Send message psi/cryptoYes - Encryption enabled psi/cryptoNo - Encryption disabled psi/time - Time psi/www - URL icon psi/email - Email icon psi/xml - XML icon psi/psi16 - 16x16 Psi icon psi/psi32 - 32x32 Psi icon psi/psi48 - 48x48 Psi icon psi/psiMac - 128x128 Psi MacOS X icon psi/psiLogo - Psi logo. Used in the first dialog. NOTE: the leftmost and the rightmost vertical lines of that icon are used for stretching psi/smile - Used in the profile creation dialog psi/ok - Check icon psi/cancel - Cross icon psi/done - Done icon -- TODO psi/close - Close icon -- TODO: add to default iconset psi/apply - Apply icon -- TODO: add psi/edit/clear - Clear icon psi/edit/copy - Copy icon psi/edit/cut - Cut icon psi/edit/delete - Delete icon psi/edit/paste - Paste icon psi/edit - Edit icon psi/edit/trash - Trash icon psi/tip - Tip of the Day psi/browse - Browse file psi/play - Play sound psi/eye - Used to determine Hidden group visibility psi/upload - Upload icon psi/download - Download icon psi/filemanager - Transfer Manager psi-0.14/iconsets/roster/0000755000175000017500000000000011305557613013506 5ustar janjanpsi-0.14/iconsets/roster/crystal-icq.jisp0000644000175000017500000002622111305557613016633 0ustar janjanPK rZ8 crystal-icq/UT  H/ HUxPK Pb3r//crystal-icq/MakefileUT ^hCUhCUxinclude ../Makefile.crystal all: $(ALL_ICONS) PK Xb3 crystal-icq/ask.pngUT VhCVhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGDC pHYs  ~5IDATxu=O[gQBKX22YP6RXNJ ,R%tJ"S'$*%H͇ؾ;Pg:yrGe2nNa}}Fө7]x<~kzzt:뺹OgffAJ}hnno_p mɹfggj RJ(Xi !DUH&_.BBZH$rY8cccb1Rʄy?r]t]ǡh l"`xx!BlƲ$>88011q/T019MCW!RR)Tz.w;&ǹy-'xc8;;YT@*‡Av =dx?x-p0mEQi H !i~7ap91ׯRevJPMd7ޕ+K~#rlXX INI4?"Oq9`k09oZ~O3G駇 Zn>un>#X  -EL\oﯠи,ձe1DlI]ׂ7"U"ԑP`x}0gpfSZ5cS%f@ҿVO5Nwy$AH5&\\i`.zDGM}ʻ_`k+dP\b2I.λa8t\Hem]$|Sr*ɹN{urzLLH8N+lZHm<% vص?P{{p 0cgQȠ aelnG)O1 nr@)jĂHXʙ6&fmFUi7F?@{73%CԷH?U00hT`3 AvG-DJ|{Taޏ/(p2}> Q2\,[*@5Y,yAA:z@!&geFxc#n%EI.yMG)j9ЯIENDB`PK Xb3:o_XXcrystal-icq/dnd.pngUT VhCVhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxuKh>&6)dۤmFj4{1=I#(^*hPѣ zEA5xCz(JڦUؐwyϮ|73Nq̉RڒW!mӞG>N2\n”+"VS[[G9`:qݩ/'4!d RK;`}t- Ru̎}7a zy=Q l^uͩ(˗E,My{: 5 z#jʡ0Z8:wxI 3}cCꝊt~]O~h薄~iԦ!qI!ڑl~ oH&G숅:yYRk刯 _N:ss稫T*榎04˺>1Ա(ď%W~g}z.2.#%XEXnb;޽2Z^q7 [YZN9JN/˽'O HRD4&!C3l%bNmj%\4-bׂ|nigU**+I&5sg?q)ۍbڢ<+o32x6b]MtW '| -2nV:N߶l IENDB`PKoZ8Yocrystal-icq/icondef.xmlUT  H HUxUn0}NV*Vj7M*MI&[Cсv!]LVpuY3*ͥ:g^̸wd~tvS)2VPatmFVqzvN_a1i48r]xݏJ>{Hw$p^x@5܍oJh1M]G0O\7lC]m. V*dysឝMZ[\*XV]'7fpbX>IH~J5CLz,0VЗXFO^ӥrQ|[| .\` a^<&2KQK!g 6- R[SXzqFSРӤ꘶`*Ir MTvKQp9K^b%s'QX 5;Dfw԰e؊m4*kDfg"kb'\*+[' nȲcEVWyN^UޑpG<$Խ#؄v vZFH u=cV_PyJ%6Ze&Xsb"Kkķ8,D*k]/A:jp)K`CB%OS Np{M"uy`)oePK Xb3@Icrystal-icq/invisible.pngUT VhCVhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxuOu?3,vAj b!&])1$4l(Ń'K#4!5B`*삛PCeŘ;};jDeTT1@޴$yx/8F֥g8bƬr#F7eCWX~m}9m/mt]yAdq+NENwsluuXN@9a XhZihs XmۨJTb||`&F-\>N"%I4%0>?88<|'nBvSan^,?!3:1X;AUUt]GӴ\.w ^=oz#GY3͓_=>miߏ0iq$ ۶i6$EQfs _LNR'r;o~qöm ø@N8)ԢSDe:N5 W,a赾JOr]j_uj/'4$}VvvH8CSɾ{Wg7~&+ Eyz6ͩ&D‡Nqttn i\U.:,e..i]O$K<`=!ł2IENDB`PK Xb3Yݎnncrystal-icq/offline.pngUT VhCVhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxuN"i*XT%A #K6&*~77p 7~1.! `QԂ,nr{ G'}5OOOe7?zT*@^D9iT*毾ΟP*sssmmm19??'Jp{{ hP(h4*yzz:0%r9zBy"p8$LBXqU0foV Zklf<#"bii J),Bk0wvvQ}m>fL&R nROeYNEl4Mz""gggt:t4|vM:&$yJd2;x<FZ0N BX u"l~D"d2""B^Dz,.T+,CgggjLS& 籰m۸ixB<vd28///(X^^< 84 h4`0Va6a"I&Hb6 k7Zkh4:K>XEF#Ri/H ˡ)jA jZZ?* zw.뢵>T*֟R_jy#d5IENDB`PK Ob3eUcrystal-icq/online.pngUT LhCVhCUxPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FcIDATxbd&2J` > +?@1yd?P_ Q Llyp @C&273@&1(ppO4exvag 2 *& 00>p;o]b!AS!|7{ t?~.&k cp;? @3|z1;oyKa@'/FW @$>20]+D#Ë[@b`ЅhO^*pd@1L|#p43 O/30:13\e0`a`81˗~ 0"@1) I5la`Ps``0#`oA{ QW!a=r_E#߯ζ tko2) kv7>oG;@x~vI=e7`}İCAA3ñk< _0ct`o@0fVgcw6~0x p=:0d>l`Fṕ@1M2Qx?>1[2,``d@Ldo L_y>>``PQ0,Di: >  X) wnCq^`e4?@ t90 r 1ra*CC?9(00| -%_`BkvdXp 6@:u0 ?2- *Aa `4IENDB`PK Xb3Nzcrystal-icq/xa.pngUT VhCVhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxuoSu?=v[閵L*0YP%\Hc#b Q/4M5ML ,1. '-[k2F=m~ϩ'⍾WyoN3cq u{9{L*ᎣzL{bl6db< Ca*⤢Oe?] y⃡Se7^+ RB:%`4zHrI;\Y\@yБ56`h'd䓺w/p`=J]Û$G6_P]e D>6gy18ʨ|aE1{'i?tE 4 \xꢳ8o/Ɩi]auDO[ܘЩ ěhBe,p.DpR `H} 4yس@'ꡯ^ Q1M)%"$Iߑr{+AX}TzF]j:LBB  h:V)LO^h(D# NR!M!h6Ah| _XZ䀢(x8Xo/`~ L  k׊mkmoǮ'(JT=gj\opCk XaߙȚu{e;ֽF`ټE~b+)M hpБ"jnss_28N"2_>UT2IENDB`PK rZ8 Acrystal-icq/UT HUxPK Pb3r// ?crystal-icq/MakefileUT^hCUxPK Xb3  crystal-icq/ask.pngUTVhCUxPK Xb3i crystal-icq/away.pngUTVhCUxPK Xb31Y crystal-icq/chatty.pngUTVhCUxPK Xb3:o_XX crystal-icq/dnd.pngUTVhCUxPKoZ8Yo 8crystal-icq/icondef.xmlUT HUxPKOb3aO? crystal-icq/icondef.xml.inUTLhCUxPK Xb3@I }crystal-icq/invisible.pngUTVhCUxPK Xb31TYb hcrystal-icq/noauth.pngUTVhCUxPK Xb3Yݎnn crystal-icq/offline.pngUTVhCUxPK Ob3eU P crystal-icq/online.pngUTLhCUxPK Xb3Nz $crystal-icq/xa.pngUTVhCUxPK m(psi-0.14/iconsets/roster/default/0000755000175000017500000000000011305557613015132 5ustar janjanpsi-0.14/iconsets/roster/default/xa.png0000644000175000017500000000167111305557613016255 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڍOLe²@- BWKĚ` xҘx0^<x3xЄ61^ bcjRb[) +fevof%/=}W>,gIbO͊EΉu?74ؙy8|,zJ'ޟW" j=NDBQGm<X^@4ܙ^w}L]E4Y*#|i+ɵ5f::3u] `2ay:G҆YqՉMFĕ}|!eo3Pr jJ%V ]I˰ŭkRڛjm:rUD{"1ku<AZ8_G6f碧k낹ɛP[/Y3k#_o_'D+@I<XA1=|Ĉ TF4uݷg/rZ_!IENDB`psi-0.14/iconsets/roster/default/icondef.xml0000644000175000017500000000563711305557613017276 0ustar janjan Stellar3 Stellar3 Iconset 0.1 2006-08-30 Jason Kim (Base icon) Remko Tronçon Everaldo Coelho (Base icons) The icons in this iconset are copyright by Remko Tronçon, and are made available under the terms of Lesser General Public License. They are based on the "Crystal project icons", copyright 2006-2007 Everaldo Coelho, under the same license. status/online online.png status/offline offline.png status/away away.png status/xa xa.png status/dnd dnd.png status/invisible invisible.png status/chat chatty.png status/ask ask.png status/noauth noauth.png status/error perr.png psi/chat animation chat.fading.png psi/message animation message.fading.png psi/headline headline.png psi/file animation file.fading.png psi/system system.png psi/call call.png psi/connect animation online.dimming.png psi/groupClosed groupclose.png psi/groupEmpty groupopen.png psi/groupOpen groupopen.png psi-0.14/iconsets/roster/default/dnd.png0000644000175000017500000000157611305557613016416 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڍKhTwdd2!hDM@j 5JQ mSE颮Ju!n\.P0-im &hB3:yޙ;w\b ĮoO S`g>MtMB<8[~dFW.(T_RTTn3 O@a#S)fj*^1>m=_17t Sm$:^"/.AHS?y|&K&OWoSv FF `puu.ڔA1<Y σB$7gyQ\O4Dӊϡ6o^XȔT5| d<l%75,Qd٠4  Ycxv]f$ߓ0IENDB`psi-0.14/iconsets/roster/default/call.png0000644000175000017500000000126211305557613016554 0ustar janjanPNG  IHDRasRGBbKGD pHYs  tIME3){tEXtCommentCreated with GIMPW IDAT8ˍkajMR*mn"RpFp#]HEW.tF(@,uSDlUBS+Mm3Wd&3E6|-9sUDE':ҫV}cQ l%ILn7Up i6p3P8tNi5(^IUdL_,eoym;:%,-]l!H0m ybi ۫Whh_Yԭpn [eZ Ƙ3bۖEqD}<|\B[:tgd aD8 tUojق)(?AO"6.U`A?@߮VR[6XJ-B _\͗ tH5`0t[K?%Hb*h'=!Wl(wO@4/-M{ou|@*˂C+E! չ@:w$QIENDB`psi-0.14/iconsets/roster/default/groupopen.png0000644000175000017500000000053411305557613017660 0ustar janjanPNG  IHDR7 pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbπy" *  t#5@L4   J R`6@%П1$@ Շ1tC!},[ Ő{0KCd!bc zVN3 )~a&# @ADP@-PscIENDB`psi-0.14/iconsets/roster/default/chat.fading.png0000644000175000017500000002213611305557613020012 0ustar janjanPNG  IHDRPWBbKGDC pHYsHHFk>#IDATxw|;}M!e@ P$#("+(W(`5$@IoM^g8yxK<=|D"QXmÆJGgU oO`$@p0P?{{V)Sҋ?\h89Αy}_?㸇{{ߙ1xJ,VfXlҬ)^ضMCTד?+"bG;p͙8Ȝw2-B!]@~b;R^o|D"Π N}DtlxxZZQWCq@ͱ1 Pv;&X 6q ARPWL}C'غU3{nddVVYÆq\vgՐ1cz'[7R\cK-uu/-S1ccߺUUQQ55$ q%ILDȑ]2S__*ՙewR|IU67|8.4ߗ|᤟Ǯtv˖A3s4nPws##:p{LZj[lD"j5H$I/Q>^&(11wGavњgŵz=Ն qUm:ef![VeqC|E"<8CG yW1W i~58Nxֈ]}t4a;dsEY#""iu60n3s[,Cg'Kqܺ}iahhqiguss3+`F#!hXW߽nn?| 4`ҥw,;wN2fLH@\܀ D"l()~hғ';W7KwSSѷY'r?jQ`O`xrHH|lF@_DWbX,_ =As\ʸa6[u=Z8bΟ0+/AJLed܋5GΞ=.9鵱opxHRxJH{DDԷ?0e) gyc8]2(綽kpu\noI:jqξ_Q3:vS˖ů\D?C#cBl!(d;*UKKvtgZmEu/ҥz^|%YR*`rsōXzcfX'MM Ba6`~]{bm]QMMJ7=m&/3[+{%%?˵ ̙VBC?~8sf\fbRpX^ c7zXv} >.,,ik\R]taA"?zvy^+gW0**72%Q|B4bߠ>G@FFŚŝ9/m+)!>(-er#٭v#}8ztXH}ˮ.jY"GfMJ1LUR y8m_死tbB\͛UU1r۷Y;w{^|O;~ 䍯|f&F8Sz[9$/쭚ُ?ڗn~e 4 q8a(e(9՟ɲWQ3tQ)ի53 1-]#ϭ6mE{FOފ~&`P(!0`,ǡct8( 1a҉u.{"cAo⟌мjnԕ#ܠ32Pag#>à,4Mt_0uRTOS P` Bc|}Q^|1\3lˊf}1B1CCvI X YA `(Zu:@$pE[w }wfsiOnݪB7XTE^hM7gIK-[T[B˕ʠ @(8"I$0$tV+@fD*grɉ8n0ud9駟3:z?5~}}G-޿/4T&C|D@ (!`0_m:k2&SE_w]͍,:u_T-6eMK~F"R*"#rzzNp67 MTkiV$[_S;QI{ rX O,4fLR1srD788: @$bY4s8IvNh0VkiiV5%֎kwwwyI?躺gRG;7mٲo_i)+G߼7nx;/6P||ccf͚0CeΜOX`׮++>~?M}`@AB*R #cǪT04 phZZ}=KBk7W`3T*B&;v` l6tr/^jnp|=dŰa<Xj{*L&(ÆEDdnGB\rӴ yV[Å]rdu:?]U*D(q(J$BnXHN4GŲ>*exsw #F S=8;СKYex5xcc||r8^/-hbb1 @^pyK1@(@// [EDZ_]]] \ 0} 4A @#εdNĝP EYsy=GIR)@nqq!|Lr"*^"ft̷'_<M\BiXP9/D7;twE Zݾ7'$4mq~̏f_25'/?%ț::HhD‡a|9ß=Hp1NOEY,p뗊LpYqrO?ylKө#y麏yrX @8MPqY g1uG'\?YԹ ۋ&8~wr8DMx0 }$s@[JF[2.;w~+]QX+@yycgJ76w/uw@s^Q.ÿ?֬.\Ywl{gIk%_z~a+4]C0]ow]nn/.Q ??o9qa */0ޯ O((ڦOA=]ׯWvwگſq[׮|62`idB\/}޽| C| Q@$1fT;+cuuYY_gϝ;㌪T(y a%Hx$)?pL' Pjkh5ȒSLvk#G96oYgө!?M# E~> 0+t}:_+.f ytmH ڳŸʺBK6Iġ ˢlR I@jZ?q7]{1 .O_qϿ:q;;Q<|},c L&Պa~Ȋ$ƫ;Ӳ4YWěG/a5WM)[~9:nomArզ&dI,˲`ĝ۷u:=ۺ$et iw7%rǏz幺 6Ng4";Fws~Om6`!Ylz&ISii}Sk:yrzjF /9dۗl`YVp,@26.tuٻf5/7MOۺ"̙˫W67t:/pwb۟8LY5 rsiK~KYWT^ q^`q7[wcD"E"ȜVb\[=9TJ׸B=v,'h0H6$2X:Ziz\+t8N'8yf_>D]!!BLbuјb**m6QK%)/oo7r__b2BCYiBb:)*g˙u>lPcL  Il(FLD\.W hvO,4.Y"\J}q]|5385:ᨫ3 l80T z9W.w;f3IB-\crF.)}/^(nnGc$G $$)z{+(( Mzd@bMJ&?/S~wǿퟻ/}5\ڵד|y  rM plX~ɒ$n(*/(J;9vNN;=|w-p ~r8DW|͸z'ufNNb"QQ$qr9@r9@o/v1jx㍹s|n'IAwպOp6a{{B'tSZq8ϟ6-0<֭cRR##(ee2Jt:$pm6Kg= heN~cnq)#w{i"T$RY9eΘQ^^Y9b@ffyy(]*b$ 4 a8p̛7eJ\j'zTؓ%)><J{*iZh9_v5!!0Pa$D!!hiK,CHD3f$&42ϕ ݩ܏_7>@BGtA11Hѫ"72v;`XL'βuRiyZga!<"X0r\_j9à7jjވŔ r9Ӊ$5*::(@ 0$}}BǨjR ~0H _liN-@bXђ@ ,A!!>>?RLoGWۋ 20,dy>8 `86t q^^8 dRKI Vĉ66&ww{I\$B/sl`R @jp+e6âçܷoصk.LJP*r୷]pˡ]]Z*kj*d/x-y}M o\B>ٳʞ+'ԕouuXţ =z p =m%%%mj/h 7n ޿?oTzc)z3/=`z٦oYp!>^$R(Г]ǎUUpkk7~h3>V( JN$'+7o)ϼ3y1QSɔFZqMLܹz|dwY8j/=kO7$AHLT*]+42M;ӹy55\mI@|+92C&JqNv@,KT/㣣-ʚ/.H}Ld:g2 ձIVչ$$̩999qWhpb 'hT##Vįmɴ,jyUըu/>|ђgwGP*b /+PttP `_ O|F K(H'\k2oH/&$cF ܘgVDF hQS`2azDWN;ZL+x;$$(((Tld^8M](H~g´<.nn8%՝v;@@Vh `.C }\~wǿퟻX\P pm®q#$HiLb}y֜LK,x*imɣkbps琫ey2gM?5] w~3ҥW'v;8;{=PZ{/v^lʊa-JHe~Db>9҇ҿ>(Zz.Ot$<{/<%dwGޘS5|| Sz^^ɻs~/|XVvafUtef΢د&Ng[ػ`~[ |xn=VEd__),'ϪͭD^>^;dڑ]] 甮G{]./*VE~U|[Nknޔ;T^-Nk& >Es1lXo]GBfc3SX;wja EC=/秧W̏3;v׎;VSI- YM)Lx"SͤRyơƬ+ww{Ww%r%)H$ៈ^EGiN- 7!*JS[MٳW/1&f߇ߏ4C*'NN eח?S ,Rp[/~Rc~U!!niYYEb9q łX IWK-0W7H--E)ʢ(>z"rM*P򞞿nPpX%/ Î4A_ )`'P%&>/㜗JyDx&[}#8Nz=qοoZ,@l 7Xrr.' (:dny'y'y'y'y'1bMO[KIENDB`psi-0.14/iconsets/roster/default/ask.png0000644000175000017500000000167211305557613016424 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGDC pHYs  IDATxm=hg;N:lZeǥ J{1t!СpSȐ-RP8XmP$l’*O}']Py]^_ͭ(3@MQ^T;-Ph,JU*W w7cMx|vllmooX,4  Xu) uO8Q.4 ˲ly^Yu0fEggx

] iA!D}6i<۷ UBu,ˢWJ<4nA2~>|K8|_B#  $~ 7NmͶi눡!hk#aT*Ugkkutz˗]*u~v/ a|Y}[&J&@<Vz)$$D˺RP 4//r3^A *IENDB`psi-0.14/iconsets/roster/default/message.fading.png0000644000175000017500000003105311305557613020515 0ustar janjanPNG  IHDRPWBbKGDC pHYsHHFk>1IDATxixTUΩyd $$!!@2"L"AQFQQDED0$!!!T*CRts/vWc^wΛz$O>gZk:~%H+mɢ%"YQ'Ut{.gm͝y~q> %"SS5>>xEdr}; M9`7ߌ|+**:.)CeL$qɰď?""ӱ3g7 {JIȟ<9fI̒ԇx~GzDwߑWN+Y/ }q>k۷Ca"#o8C]\O-]2de?Gn^|Ξ=p23*OWB6-\`G9{KS488#F݉!2`Z{8k'`[b)) Qp@ЃWz~'|L|>L7kf^Uw'33Fy4k±9cJLTרkt xb5\k}}4oƮ] 'kT}J涌c{5c^7a^J®w;Wùqc7{8NL#pZ875,ՇNV3 )Z{oV+,eX#Y˴RlB['K vy*Uٷ:Ywe0Hywg8n???/? (c}u%9xB44Æf;br\"1Xm K(28N@DF\#F3fϞ:r*) `B127ri*f,+'y愒'"Ijۘ[aG.wƆ%% El,aq;m+w>ׁlU*4:S)M9{ڠ nSԯO˘>:z_f=pڔY9R,, `h(,cǏڥ_.,^W!B ø8K\ehW`##g(tKN*AUO)M'Wzzp$}jO u8[̾[`_S8 uΝz,eiiRX,;D- EuMvsg'}-jS}|.@e5,̂WBC' HMLwfJX <@loHqRkC\k+}0L1?\X}=P@~5 ''l߾`ѪLOH^HtΕ{D)Ii}|m\3 \n2=F#󿚟Ӎ[8*Zm۟tufX6@ԺȱzH6t:E#[c&ov8QH$@A ߽m rS.?~ *zxƧxz'+LyC"#T*J*yV^ (j\嶻\*c~>B;rb褒Wek.=hwo_f\ucխ'[[0,99!!$@T%r3pEd/1S zWWFSFɕ^/wz)*w|<3Ç=a {k4JJ%b(&M&jfljU ~O br Ci˦IHGZg7vƩW^yO >r8ާOx\PTb1Z&~ LVߠ]y ;*;Rz M+)9QK?gdWGΘ;wO٪1k7J?{& }x\ߤq<*J0\tq\^}qޣ(*Aʴ#MyEUW qct?eO?̙:uHر>(,L&cYqU-|bugYz7'#IF|Vmݱ6,w_|T MIlT=n܀#q]|;+_Y9s=C$ d2zI~Ohy.&α p;LR(<'۽Nhv|>.1QPަH6,^99﷿2~ .1:"I,h(J?z܀|tWy׋]rJՑ/z->}d Ҿ<_;4g'7jXoٰ~!Xp:{zbÅAA/}ͼ$=;n.\2B.T~%g???/#!6o~u9ҥC׻wͬ' B!¿zzzz<N0N_= ^/?xLg~}}~ k<=ҥٓ><9{Y,FOWq\Re2 @wtbqjk"F_mf)f[_uk*2Y19;bɒQ2g~B0_dX~>?_Gyjx*+;; .8k3̾6i6ߺ^|݇/,R<Ĕ ݴdIs3u5T)/DJuǑq~G|yY9igoK_L;82VE>o{{t9˖M|xsC?[haI lMڲԽ1 򠠈n(r@CCEEg'D>[4ݼx}<]]&W޽  {H3NudѢ\3''%W sui{(!!J%H$Mux]X! g^y3t>??S铟zq€Ҵe 68oВI"88RbcU*ķX(ʯ,t]]Y@ ^r;gO_4h/kjlg`r%ˠrYFc⎜ϥ'LNNIuǮ 5hp 6"o_@,nD: 1 A ~K ^4'_zkgmKu׽e4?ZUid;=|X7Jx#&}>'g%YRRyRt{[3 Ȥ$;:¯0 En7@kݻ]]AO͆Qy˵:o6a?7id;Á?hh}XNǷ_p"QRRRRx8F '`JJJJZZF1_?!I/jQ$ ,1 -pG}<<@{{{P^^Q!Ǐ߸uف }LwË,zẊvN\&ĠR)` ϲ /`2uu955 Ի7AxpӅwJ>:²+~LMݳfKۢ&^tY2*W/G/n`#.Mq,   fsO d2@rnni)\ΣYv}A>~;w|qjuDDHX d<a$ta~٬V `ho7CB( nܨ gzO,NMSSgcYV L&; 8> |4?p8\.nwhݒzk.cyWNMKK;0EE3PJT*HD"aԹOQ(y?<vpݽ P__U +_bG*~昜Uk o\`J*bG*r\H7$I4<Ɓ) |>zn N,8zۛ'\U}au}7ǛY֟kFܼ7t8t8o48==(DE4MQ>K^/ZP"joe tíD"  iJI&Ʉ?^ 0=EKh9,ܜ$ a[\KL&GJ I"U[[UPYY^n4f3rPaYAz^GaHү`@RRbb}<-wtt`zaMM55F#V+Rx_G:|^/I"q C@%qqQQ7ۓYseY@Q6M{\exs39F#˺&`256xд_Cv&M) jRiX0>:2!6[c#:6[SSS@. ˢ ˢz}>GE$F#T7IS7#  *^YW_[0fsu59r /0,AݎfJe2JnʺU&2 UU4UVGSAގҠ# uq4`r͆6D$)8kʗƴ?hh'I\E6{ԩCUCUq2 ֑$I,@SSSSw7@QQQQK˽qqhu:ND?3 r6E jVWs}}~@ϮyZVsIz(q/DJ%SZHPZZVf0+98Jy;;;:zzPBqZVP LEI'f}(zÉoWnX_.//==ySdgf?!(hJ0hiTU!`dXej 4A0 /7U?{M[\D~j"f@I M3T&61 *L&P___ tdl!2̽\x!{ N.:::;ݹSÕ+φ̌9=qbvPgBP ac6--&ryH)8*.8X&C 0 IupиJ(DH$qEY, O权 /Μq 娫pljۦ6 [;]_Rh@_|(WC OWmiXX͛"#BNaw;}BBPiT(...nn˫D  (3h@,E"o;CΝ[]wt鬬, /B֊D!!'&&:ZPQ/Lyݻ@AAAAM 5C8ĚNZYAؙL z1 SV}t:Mu|bZap^P;1jT$DFVDZ"6ܹsE' :z'BCVCYO}ƢƢ6e-ރnw)%K~ާOhEB"@XXh4%4664tt 9$ 22**( n<ӻ-yMao4-{oad>f#G&o'bG*T*V r `hmB`@ K IJ^Zt^~M{Z}}l6Z,ķ_=Oh;fRESQKZFp^`T*p@W* CGry<AAaaj5I:<pdj=5Iˢw޷FDٳwo=b9 ā+Z^Ri9fb1-n)_ZmpR @6we69W nu>`|65y<]oMKV7o=g^RRFN PBpҳݎ:I@&h$qW|a{3O7eIdwv2׹.xaaes׮j'HՅ AOj{u@?wo|p#ؿ?PO7%ÖP4;=;}zִi))))zcN$BR)@LLLLXJ4{?K$ S X|>C!ͷ+6kQע~۷l|cljB|y„/DMV(pDV,H$P`9PpkmAC\VSS9s vdY˳sv_pzl4p#4xEԠ _~~DDDDPNRDD ePnvv3v\>_!MO8uƾ}O/nr-#c045fDdX E$B\!!aaz=FөT~nF81؞zzo/QVyF#G\U^>EU<#lsJԬ¢Ro DhBBZJU*BCu:奜lii.2Mow7P r9-uӞQ >:*(6v "SSe2t7!>K$㈯g ut M;plKƕ|S/ɗDp84fwOvm'>6/g0}b!`og] ޽vO<%>͞Vi^fI л7*<*`R 777ʝ;z>>wY,g^TFaA e9N$5 "rQlׅa{T)x䌓33555e5e&?;;q[]$J" p^sBLL\\h(@BBRRd$ 2ka/]\So65omzӽcO ϸ߸Q|upy8z98eD;>}#"Pb ("6Xÿj6vm5zrzr*HZE,.6Լqb1P$Hx݇׋z8N&bbbcP6*x0lMak88rQ?HϭsgT)hq>Bp  8)QQ&HVЊŦmm-$\smCF<< g=̧o548s탬T*<BρED/d:D $I,[,[Gwwyy~@Xb4|Z~Ht:5Ir9dr9M.#O G E& H$aD;} =Nb/ɀTG #"<* \P,z=DU*,4Tz}C2D HCңTJL-nj 50xc76Qzz*aPpƯ]z/7 9N'Iޓbޟ8N'A?|O1|򕰽{T86qD++Cvj:~.q:IybQJ%fYE9/ڵjݟ2a^S}a9q}XRZKJuUZx<P(bԣǡ=1 @A ?}}-^v1`ɪUl[F<pNfB=ZCHV(!%ceYTE|18|>bY*[#Ec_ p''j㫯rm\u-8HQj܌Z*:n'@eQ H<o@SWP7t|yTZV{|{Zݹ_c9~bemLaV}gY)_)Y&T.7Z>H˫"x.z<׫~n|(@Qmm Ύ`xfwxuBuCl$յ46$$BY@lHyD}㋋릈Yq]5ڇ0 r,@{Dmc/M7_zȴZcmQz=+^Lhi2zf*$Y^ru"]UpݿIutcfq4AM^de&S!ʧBCU5o' 2端=)"n8WMUp!KeKY2zñzLVl#Ch~Ծ$KKٍB%+=~VnGs^^[+A߄%<Ւdֳmk`g:>}FNޭ"؍< 1 ^7F65R/{V vKg/WZf}պgi+ P<~ԖaϓNQNo`7 _:.2ï\qο{~U '::;0_UMu}l޻w͍O /oÂJ)ij^D#FD}=zm_rٷ^-mm1l.}"#[s~v(*pӔЭ|KB8 ?o~uh,i!J]~m1KVVj???/! V\PN.?6~PX|Je<2dWk516y>gwvO9l >?|S}4i3KZZNŅ+ Wmaًӿn07ϹzjNURR:j3"WM۹3m[ڶ8A,.'ʉ4-T8RfAeeKcXaD4bĘ1usbߋD sv~0*V;Niێӧ|>U 1H|:4o&^6HP22I僖j߽]r0@oc_`_ RKC}>gbqcd2uRjjȃAWM&o'zL80R):wvvzDَ؎U_OzJKpI7&#%%hTШ)Sf%{<>OgS9Yt@sBbbfҍҍ$j&5ֻ\v~>?`D"::::O8mqn|=!N.[:9i8vLGGz~hzo].-h!L&? "ځ/~" 2AzMw `TVþ׃_}f +4 Y% (%n0p  r8=A@N/ 7=v!B \j8 @.- Ý@| ~π"' PpȀM?H hǷY%]}D.3&(?@ QOffl FJ3@SͶAuIENDB`psi-0.14/iconsets/roster/default/invisible.png0000644000175000017500000000164411305557613017631 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڍKLceB)g2PCgA,HbfV`Oi&&&% ]1F7D+Ag8\P2\,-ׅb䜳 эrV ,>/LR7GGGEW^0;@Ӵa=~?DÞjf qyOiMR $x( |>WGwnNM[*οeYH)X3rKpnR"dww^\\'m=S~x56 Vȃ%.r͟#SGWŧ@ZEQ!PtU ^#Z6 bˋki|iA4='m̵zd;=I+@)To)/TP  AqkҒ'st?=RPeRQ*PSLx:|:׀+0 Aw4fz(f`vƔS}xaaM6IENDB`psi-0.14/iconsets/roster/default/offline.png0000644000175000017500000000154211305557613017264 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڕKcg_:KGb$vPP]).\._ۮZ貫.PTB f3727]T2xvw`}}jkZ5 noo1WAj}?jiJ {+j/WWWJb5ko+J4?,c @Jhb"%j.//^./[r] PJ1Q}+fQR"dbyxR$DGGGN`Oڻ‹ IRM캊EU !u IJJ ekM7=.=4ڇfC-'02.EFUTUs5x.\bP8:ՂG Zzl$YBQdTUQB{&n*ҙFUQX[75X4͂[VYQfj6^tQuS. 6R9fl_׮] fGؑC^mg|jO?or0>H`>Bnzg?gf!m,,__]܈ ~H84.$yVhu(&H4!Wm2UX*,#$XxߟһdÍNvp׃n-ͬ=lv`YڊDf~3V\".IENDB`psi-0.14/iconsets/roster/default/online.dimming.png0000644000175000017500000002721511305557613020556 0ustar janjanPNG  IHDR@7zbKGDC pHYsHHFk>.-IDATx{XTmn a`Q*5-*%aVV'ife7CKXKQSV'=WTo*(z3*ObݰL}x_|59l\e|NQOd,]x7Maa""5!~)*i*.Y{Iܹ*b)OAӓqwD5\ G(,'#c7mf?Y;e4=)5>K_*Sfdlwl'O66w^ͥ Ε+a,>_DD$#lz'흴whzqǍ?{ϒed|}+Vlټs'W7~M_6'r% huFƾYzfܾk&tg:M\V:w˾"m?7}xo|\ʕ1,㞐vdd~-}m6v:?μ7h:}Mb_ǟR v*#>-SAiOxeWqlvht:tUT(\~ bz(kҌ7ss; cJ :[,+86{E.]751yuAAWLIV(.KތՋDX2"7W2Oߌb?3N6 YӮQ(x*uU$S58u87W:ut|>3O;|̴ @_@|ӸW "Qz'6OSד<>~ __'_vgڽӆ ҾlnڨB14dh' 6XxY}nqe*OkK\-i7ݘvBaX, @q=/fb3\QJT#t#O/d˯~/5eii 1[[*S?-̚r2+%O\~`j鸻 .Bq}}g7OݤD7uO/͕J,ŦSQ2%6~kA%/\?8-AZZG}iר憐%̟ǧb1<×^;RP֓=vHkj?/5{DοlI2#l3Dc,|JM[&Jz%6VPXZhVo-?tϔȬ i B,09QWn[x|b&*#y.8SU * |E,ſUzbF#WJJؘ *42+k%yiv HaTbZ}fι=+wlTWS,nH(1oN"R )KR4yJ'6VSf*LXؤ)D|cDqԳjO[wvMxn.wFD(p2|~WD7J%R%Q Iߔ.Ugج=PXnVOR Ra I8|d+my<".f60|G;O֐QDJ% I4*YtcllߨZ'*,TQnZ8!wm?_xd%EA; )wwwwTTi4U%{KVlle˲޵w*((Pfl88 }]u0008.f#Ś90M&O`?l'j"J%\r+&l,. K3~^>3YXhĐ>H"FKTս=33F=@h"`('_WcTY&tD#z"6vܩZIHVyϹhbdY#E @2D}F>7է7c<:7O٨D3v9Ea~;Rm S7Rh4a(+6v5D*ee̮H0z”$tzz(J&PBVNxq> l;( A;tSo%ND YL5Ex+uKllbRj_Vk -j1m$xd I@#fsfÐ`0{(/7^׷JYY֨+"K?vt,/obę{tZk'М75m :݄"ҵ&hGDť*$q]].cMpp:e6X۳v{!n6{`8ųˏoJ_ZVB*[235%7/˛6}`C:]"Ej!"">~T@$F-lh` g63-c o=,/?k?{co_.! <0crm064@|(0 r>M#8㐃i@Kq.]ņr= M6 .ltنF|,+?q΄5Zsx[{BϻoYCi4^˅ vpv; 9aP?||i݇ К<0ˮ*yrN'}ChF\ uNkttd]+J|8eX6~g4 `x\-,{t^ _@Fr\Mxa9vX>J|XVH,g,sܫe}W+t>z}}h4Nt:V!cBD.vwwwwwM6m|`?z}{]yXgYW8%,tpXw_yG|8^uP.Mf/+:Ny9V?p;4w8|>jE/<_+%y+nNG>QS=t[_]OcE"(Y>ߏ˅0( z'IyC M;e3ۖyRtk>tŃz5'i44nАɄ/3Gb,X~G|8z{˲Wl_ |`?iPvb8-QqH~? ,dCLLK{z:><{6g > B""|ϲBgY8eC cƻ;?hl|mbv680 2l> rDk,_H&<>p@NN8+12F`0 q M~ eee]g'lM)[A` 76OhhD"dWN' tA ߏPY0N`hqN(/bb=5##{볳bÁh>lB;yQ9:fkg'T"=ٽqth<~vX,~E\C "{E|G0vzu/w] 3koΖHb$#G ~*`hĢP!>Jhf]omwuN=PHvT*Q|!>J 0 Vo?{/X;'m]: i:j(G6r>xe><̲PfgM/:U%%j ^Y)ZqĒ>s¥1χ: 0r tr@':Mmm]XRo [c0]ye%u#5=}|bϩB B%/Բe].8TT_ɴ󑃯5yKJ`Z+5館]Z!j5'_B-aɲl+M~`a{MTe_OnLOO0ZO8gYH8=ČYggv4*7n()q5C=_Yɞaϰgx2T1 ﷉aݭMO7?{#WY,n}dʐCEVH4/'fT@|8>Lv־`/)|5C5փa r5IbuZMb1h*N; 4=2XT3>|ἒxk5ٜoF.TޖtMhwj5IJ$~?;#[~ 3MW|ν}MTiϺQ>`鶶ZZrǕSS#?CZ4J,*+Xzĉ=86%tps7o|z9Ǵu#=guʣV+$4JإXas,a^hxsf|{{e>A#;|f+֕ݕݕ螘v6lYVH%aR6li;>[`ڂ\7.r|PqG99ZqGr4ZC|_pB@VWW{eheьFXJy C3#$(D$ax&)wFuu?[%UGZ>G3-1 ZT!qB|%(?tXX]Wo{#9r\WWSx,Pq:88<*KhIK $I$EQI~`Yf4~Suupx]{AV\l дp1 @_$(| O_&4gmchhha]ݱc򋋇_x%M|CJ>|*z١_`f1]ѻ{*.f 9Hc1@|  d (aUWw֌{msɹuu_/8DX> @< 'I(cDBQ&J$"x<l)?8ߧw'}!gqׇy"IR&E!&ϗ˥R0A\tϩnyoj}Q}ln7,(8%ByL$BT *\.I|3e6[P]1̭۬:zQ\l"ą!!&'I`k`buKl_` c%0!7K \T z[& p9`GP*U($2I>V,VA+dhL^ÖHP $ I$"_[#V3F5\R$rMQH 8ZD.HB$bl`c?DW\TPD"$7E!(!H!(%O~^a HJr"4@$BP+~q BI1W@T0N\'H>V8ࣄL"A$yQESbJL7?{Ma䑒p9PĕPb8ryHAT!!h_&C@,T®Ablφ0aB%{p\.h1L&Cr9?&RixX In&|g]@ÄΓ>q<&&4]/$$ǰ0Ð~0,,,$%$?2R,PçŘ a$zl5山+R)ЉLC@(W( T%(Kbʇ F"p\. y>$ RqGG{mP* ?[ ok0;IƯ̔d2 C#Pᢹ?l8.P*%-Y!qqɇq+5 ?%V\>E GD-w8Id(hE>u\5܂c>?F1t*lN'!PaA-XB%WGP̵?+~ bs$u2V_K) ݟPJQ`lSG[_wߓz]dgxN' M Ng|t$R4#T_ ?G&F 7d]t: *oAȸ8b;?{$^'Ʉ'8IN'EDHhIM}x'\rd/.NN>=st;(& { ~?<|~TJd @uGqqTA?H cC*M# #I`ّhiY7.:k'ukfL*Pߏa .T\C`E%xKQ JQ/TftN<|%}i=zbbzaѕy_J^U|<?ϥN%ĈDh IMw;:`LzH?]4lxH~0T]"xQql9E)[TLH$,i0n7M46 nzrb^_c!>$+lJE&.(Jq6lU(#$TAikyT}vG9aͱ[,]*0 qUȐU*fŠ{z s\ "]KbKbKݾ/~YoXܰa"|.F؄%dV7?{Ux#Q:C&~7&P gYhc?kמ+XhWxk}> xZ~BJEY<[YhFL E@aʲ4 VoߝG'qઝ;nXq8 ?ATN`+_4T?Rcb( %!Z,^/@Cwtvk9B/X-U">,'{T*j~ {5Qb_K|T8u{׳v _e+;,mkC|n*3 hVɿVDc+FPTlix'~CL E7^3ރZMݟybaٳg=zo~[Rcc`i0[4C#zL}t{oIÆjk FF[[Ɗ3'7^HZuXm7u_?IV*O-yass6Zg[w6}g[h+gr+nu]mႦ{[l;LXu%/YѩξeI,T6'tg inZ;n(g=˷i}DC3=b^t+ڣ[ʪ7F~7 %kS{-{rrT! sk3_'>i_cHC7Ux~g%fENNya[UAAFc+p+\rD7]zF2Rvfz3.wx}L7ϧ[Tf}(6~{mep.ʡu.7'Cxϳ|E}99a!*zkB&MuaX2n/_O_K_K_v6C34CU+Ǖ1 DRRR=>>۞#ϔg3.G,`0 'l[Ͽ3^9 Oҿ:?HW;ꩬzI1BU{hs2ђ$);6>;6Պ399QsC l񵞈ݵf?nxug|&ik9A{5G=8֛)^U5lwSVLyT"ɨ?:yА{]2^Tr{fw"3ׯq CprxΓe?y~7[+*jk0޵jp;Svǽu76W|NN!C<6367`?|nx1/Y~F_? ֖>HopF˽%غ2v̜YrXT%,a47^XsO z._5 ?YvosW>=0Qڻ$:G򢴯'IѰ06EK`29[d^P 0_\[ ͳUflmiol,ǦQ0#"H1 Dɥ:c+VGC0un03`eA&3y3u%佡dߺ+PRs;<9hgqp@\E*nQzh2 TE_.*0H-mXͯs] =.'4\! M40$EBٹu`#l+VPe׉;6(E5`vSSKs2fytx" ai ompbrRVN]rqn3٧!ǿz1-ɸQ7cOLA` <#r  ߀Ћ\'E1 xSIENDB`psi-0.14/iconsets/roster/default/online.png0000644000175000017500000000173211305557613017127 0ustar janjanPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FPIDATxbfXĪj= wy}ۙ;~ ^{V#2Na3ZbBdTMQgxvAZW@C"\A(͎ X6*0 3qp}|̟3ã | zb.^e`Va|]y A4 M%Y+ ,sHsl /~d`S_АX@}pv&?'??!5P';w`x$@1{{+1yA1V@E@ ϗNgx: o|Ꙗ{i6@Chop{wgX!Qc^.3O(|VP1iV`dq2|a_kd2 E*C_jLL<2|@ Y9Rd7Y1pb÷? h@," %(N"(% $#Tz'_LB|̒@3yWOvQO]CJXU# ;ē6ߍ~z~Uᅩrl{c{7GVZ^L.w{o @H~i 1H12 4G>'@ @ 0P- coIENDB`psi-0.14/iconsets/roster/default/chatty.png0000644000175000017500000000164511305557613017142 0ustar janjanPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs   IDATxڍKh\e5/otIL5M!QӅR_U. MB* "Н.$T IM<ɘy%Lf23܇*HP[$k>uFwoqá8u݉z~.}roWh?~3X9ҟ9l\r 0%MWSo?JߘCK@Jq{7mǧK4uCl Ö<ѡР?t`B J.*l2+UXd3[|.zDwΧZ;AyhVW8h4n1m{ F|wgBCd"#%?e>6qk5րr,>>l>!♿P1976 " `:hCg盋ߜmDveK^4Jlc4*}~A09|G$8~O]VôCy7B q.u&MhL|_˪Ϸu3ܼ| opKzzD2x\2ǎ;C0Io"fcA!$29)27'21!w7D]1EEfgEә; pN$vM$SP~'DQqsϲO Rڱ7jk$À7oؚBS2Ƀw[[p@O!\_ϝJZl6MC3M%!u*?[t}gt^d>ɵnlmOښ4tӴ`IՑ#qbmwN Be%TWCE(j\_Bb/@Fik a;!z<,-,l^v[(A\WtfǼ--!Npa޻mcqq;*+!C{}QU_NSB!mn>ݾcnh e;^ >8/%/}Ve juUkwEm.g[)8pjkIb˗NucyRhdBb@!y*յ7 -IDATxwtTULI!4PPa!,QD ҤH!$:Lwn?0Ok޿q7wÝ sO{9o/l7/ ZVe pd|'ɾ,m[-~ ob5V)-m]٦mYJDt~@rn`@+P ׉&qy<++Mi}8wjx[d0\5W4 Uȋc[P&F5Lrƍ-?e3w:jdݫN2SB%}\;T)eSN~r-KgS ՅBH#,u6P\ɴ$VOgڷv:+ۺ}i~ޏvްapp"ky +@it\//TUުz5?3Lhcfs:i)}bRw۵+;\1icu+rv\ӎKM%gS6m۬<+ZCɗR-]KPu:m ܹ]QU.T혎NX еt-)7n[uq/vKwoS]ffZ!@pxӃһ^?/\8l|fff[ɡ(UxKFksI>}b<̻wϠW:N'[En-_MmWy'SRz)% DM[6~4zp7UT(C!E#҅oZTqg=$qbkq?3r8K}&3˽zs+Z9?,KQt(`pp3p}˖udod`sw|Df솧+|vѿqfŁCPrm׍bF]`ݗҡC^^v`k}x*쪿 uMEfIrIRdrG]Јg;t.93N~f u7&|G7?jӔ'ݷU9 zSV5UU ] 0PBzWaῥxxx˿xx?>M9 F"(a݇eeUUeY] @$Ȳa&J,[K+Q7!/-$ |Q<թڗMӲ!`opS x{߲|;j{D|f o6 O}\W+q_g Uzvvݥl, CJAxovrIxW9ۭWiVa#(v_qz1&p\ɮbW0egH̤YϨ }mL9-pVIKNLJwb^b>B(jo{ayIIxS_nE]Ye@m6B^[K:%2vyմ4.>Eˏqw8.s;0Kg[bGSRRb[z~mN׮{\ngkÑ`9~ӷ{΁_x2#L}99'3« ψsWNә o(;;֞.]޽9TUhj "ss{wn-}j~I_ζme?j-=]8ȷ\n׃qr\gii]jȐ[}n7!$mn߾wH}ذԤ:Ov{|fѤ$+gk:EV}9}tսuJ7u9R^Yx, 芫>ձc99'VtgkF׮;ω y"ǹ==--DQ=MdYtF"eQ ?rd^wtޱcTuTUUyye%@n4o1p~ ?3I=V$lvoM[ ¤O]8zB@mۦg3CMGTrv{hv+O,Ǧequ_o1ݙԱc¼zmXz(y(Z4| SgP8q:gg.P"m Oj]Sֿ`bkZϾm.yת6dߙxϵ9ΩW:XUNȌFK'PرS.1o䨁iiNx| 99>]u<նyƎ2yC=17vӿIJsV9N{5Y@J wQs.90ǼQ*o$cڕІvYа|:D}㏽N/L:dCԮ=۶[ޓT|HHHNn|>]4_Q 0c |=0aBmQ9_y7z']jV6uk?fry?<8ϝ~С-we[iIJJOp$!y n']r&N<=P>Ur:h-]?m ^eK-O?oo/-Q޷&pge r^ lvjZ`I+MsBg0XHR$"֭;w6mܸw/pl6Ei#$CΌm[ O|ee7th߾VII^VafJB4Y)˒$]8رmۡC@[1g W-+g~ul6A, !EMSUL O)I)!@4<>|4w݅@}4!{U:ѽK?^ؚեKAA(i>q!*ˀi:2kB?Ѩ,EEǎG&$45a]s"q8r234Y=MyL-0Bb|]WI4-Àea%O?'x?^ ]%&r\R(1>!Ʒ,MFd|ÐHO875p2x|WW`TN?(v;}Y;2!Jm.߲TU˒HK$¼4՘w{ll|s{XV$"IlE~9r[:q3y8À6V oiH$<,,y<6mQ^iQc&󄰕 o +-_?g?,KR($IGq8L!팟L/+ 'zybH0v_/cwC$Lqݬ].Kn87MV? e fyn(JԲmYr?KO)/g즕\~$<9. x9N' _U3MEi\x z''_ y$40ӌDLR]PhK /).BK5OVh+o81xVڵk.)vEq îa |1c,=گɘj/o]$߹[n6k۶-bN)Lk<,6H`9]ol4M/vy쫰kϞ],3gY,Xi[ ~Wuꔙ˶ ,g.,Rd [hZ} 7tȬ#? |M 5ǎ]\7SŻ.O;ֽ{ZZN\p癇boiZSkvﯻrk6oзǻ==--3 iӲ7Z֠i IOc,˚VrX&Y%VWoR{]`oYFtc5 6MyRb1e!>m&O4hvY]G.r=7<<<>3 Xq5 PH.|JܪdDhYF;$I1"5ysօ 372^7C]My=%3Eؽ,3A(%I|7W{/YB\oNe;i]qv;L* 3<%vCUYiCdr.dϸqIu'>fr!3tx`󀦱M=DZ{$2EB6YF%b>@i q=9q"Tr"y^]EA b0v0,tR _8 }ko,XL`ϓ_ls3Ť$ fc.A`.:v;`,54 0 fZ<^/p͆( KXi ^LW5zqݞr18N'`Yn7+\{Ed!^}H1n!/z1Sx_U*+@ eF"WiR ?gXEF`Β!oǗ.Pj_r3*&[*J,<[1dmqe߷ôxS;;ɴoY}>+a9U5*՗q'BӘuvr[,׿dyd?%M'ހ:h<*βbUmjb bl3yl2Hy%;O>)!5$u>զaza0EȒc yX2pP $uz Ƞ笫'.GÂw2'Rpe{>iە5Q3MQ8Yh:}S.d'gƸ|n  Mm *Q$㉅@ty^ ,> 9 4T%Sea?x}P.MDlo%&l̐yRguul13(MLd!Zfd h{] ܋x<?oo/_TZ)/Rg K•eIF'2f/ B1O|#XH)JscXoǗ>>u'Zt D=4έ[$"bN&SD-K_$61c6C8ku\>*ݭbv[J H aٲjEE"՛z,3=r ˒i}Lv"c&1Ηf-#6X.,*  Tvjo`;g468w4Ynh$ e\Ea+fVX6~hΉ)֟O&Iy?O&O_վ?|Œ5y AQܞuϪE?-+;cšN(l2:7Kb b>A|̡h v:!<j}E]]( _|s^Vje%ۅ͸|Foc݁Aq&~E))l;SHZUGMqY3mޔnEE( U>g\b!۔A7c}esG f>Ŵ>? -ΘGkjTůV=)I/7/-~++0Hm:a,dnyBokDO~_dP.RglA{]ձV֡Cf&[iìd.Ď`.`]g.ql 64440˼ ++? BKVhZ])k% <Қ6uu_dH]t=2Q5MX+r},u8l#V8t<feNN)TbDR=g\>7Djn*s<Ȼ+eǂp84MY׭nK~yߛY,IHp\)|(_[xXQ^y[a?[6@5sTXnnӲtq]@~M?x:rbFq B&03cl/ <ZeBoXQ;1J_VSS-L:vtPoLO~K]ݑOϮh|ܹ#.riI[Z['>GpV vݦ 3zyf1b,ԡr.0բٓOo%;쯬|IM ٦ ҍ7MMo;VM֋b׽Y6: /r"ᶎ45:)U44/{p|^ m>l7˦6uvGVv8Pr~nQ{oi_}N'6yN$wj/h}ꇸezw8-#GDCuu<~v{wjoI Zkλ_Q2˜eL&kbL)QrJ甿"~`U}2Ҽ'4TU?ck 7{E UEMvo !C wKJP9Ϸ2]VRbUE5bǻ==--k_tRga3'%m$k ϻ:G hqr"JᇟJRJ=h#qTyjnJVJ`mTvˋ5@ Ox]1#RRПKEgKi_ڗN8Շ {زHɣ K04:tFgn D%tzz"yh9hPocq*g񜗤SSyN?yCr\7 2_[nčsOӧfC6T[!sX:aB/V9-O↤$vA\m% ^ZdD&~E4>E"{,Gr':jmd91 !{c|{Իx)B߄h.i$a&rM?ӟƍs˼^(z<8k5RIDATx}MLiƟwRZ #̔=AӆDcqopa1 kB51nbdوӔCwޙsOloozH$~eYu\ >t]D"(-###Sٶ 0%c4Mz``ǣ8M2 cX,?$-* @Es񴪪_BMlm1:777f&!mmmnw?J)E:NRk5ҡ RܼLz$Ms:; i?՝.ϲ(clC@ Db8r-FS]) E"CLf98Q/.wVW9ssWVx&^壣%EQԣE wp1$IPy;NO)hD1 I?  ( ܁ L Нj5unb]0y4==|S~w~^}A>ķcyX|NLedc³pX/$ T[pJLQēPhOUճ`@DaPԨ.YF5x<|` )AaWCC[[[1v?V[d)a"%iɣGl۶ bjSo5xW,僃;p|>9.ڥ`IENDB`PK Xb3"crystal-yahoo/away.pngUT WhCWhCUxPNG  IHDRabKGD pHYsHHFk>IDATxڍR[H=3κkw355|V}mJIQLJ̈BB¯#Hȟ>(PPK *tmgv=4׽{/{2ʰư8XH`Ȫ׃PCybN^m>O?//ŧ@g.a?oEtfcY'eGA>'.1af*(Ohɠ7@ɺ+yuQ_@Cݛf^OXC4mSܸcDžėl_Lg3WxHpxސFژ3mtߜsݞ>?WTUwiGQsgv_nk='=zIZKԆ'M$1dd8REFc>u"u\nIfslua~ԢrQ-׆V;)JݺBE#?8I10[?pAMH}C1?ZӏS mʋ1p,T[ci`s6i0eTY^q4T,v(l=5 ]f[j\W@54}[JCq|5'Aa`Db jBk~?00,U+yt#09 y%;$CIENDB`PK Xb3z((crystal-yahoo/chatty.pngUT WhCWhCUxPNG  IHDRabKGD pHYsHHFk>IDATx}KHTqƿ;祅NΈ6+E(]Q!"ȅ AEDZDHȐBH0IQQGgs>洊t,8Պ(Lpl!6a D PTFX4˱ {+pB9fΎf kɳԕUn k5"ljCՍCPTgۥauZeʪ)+'u;?]v ҆׃>m9]^5)r=EUh|-s#e Gh>м Wwc"4 W6v#at>5aR*O)N;\ H/>w; *2"8]D/&'`'cܶd2xUG<6g*j;Es<*VTJò3x-/bar*vt-%C$j,hg/ԏ_-Mo\of8˶O%S ߺ./:{kIENDB`PK Xb35crystal-yahoo/dnd.pngUT WhCWhCUxPNG  IHDRabKGD pHYsHHFk>IDATx}R]Ha~oNs[fN& C "2 *+( EaEHH*"hM 6oa<=o %F%Ȕf雱J땜[9e<$ԇ2CWgq'6:d>?Pv1=aiaK\yy.ݾPGKJ:rkNn<6Y=y>!CL8FW,ʆq}ƈt:">{ M4e38~uE0< D4PUGڙP8?7Rd" AT-bZ7[k@s3P,j 5i7/, :5Uj`6vT|=  (@:eJäZ03H(%MGeL䰸j}PE 8~ݎENN.&`4:!}zK?~më:;唑Z"]rlvOc0Ľ B; K4TIENDB`PKZ8U'pcrystal-yahoo/icondef.xmlUT  H HUxUn0}NN*V6M*mI&SCсld;ME.&i+Ux_cź,RSTf\,}2t?;a7n'(0zvJ FV#˥PWw( 4߇S\wx|s.t(z #DnDP xHCI<O!Fi]+{y R:SwN aKKժT_| (VJoNx哄DI;VdKeѶ+E.i t6/rcNoaBL!0k'Df)j`2xf’^AUjswv ߖ0)ecegd>),JƠsg6KO毽8s)jPiAv`*Ir/6 n5 tߩC ԗm1rfmľK@ 'lPX ;Dw4e؊m4jkFfg"kc'\IDATxڅOHSǿm{ù^bVJMZjS GJ xh)4PTmDn]DzX A^( an(Uӷ޶_5w~~|VbٽIg8, al +ocuL O(#e2r7Yjy .pl%<~O(@8^Z__TO%[ma5 sUw.k0 NI$bH~\. ijDŽ] v8A,$I)HP*"Q3܌bi''W #zoEQxcrystal-yahoo/noauth.pngUT WhCWhCUxPNG  IHDRabKGDC pHYsHHFk>IDATx}]LSgƟ=-Vʁ l`o$n^-&Kf\ls[b],^YހqaYNiv΁sԛ1'>_ B4MhID6AbS~?T,! Ƙ*Iu߿'|i.˲ӶfWU=/gcS|Jod(_{\wގc>l:#.sp W^)oIJW ޹ņ.zCͦ2Npkdg?=W9Abi)a]|hmt ]|*7W+0ˍX\8h,YB4a0374vjlzU-+2㰘%n#u#7ޯrGk㞵bfMUO Ij5M-ÑSawԺK[ܖgOw:GE Qb$r;11q1{@ C%OO(?(?=??{.?.Xa%)]Kn+X,&k؂cvze@E8ȿ Z~WIENDB`PK Xb34;GGcrystal-yahoo/offline.pngUT WhCWhCUxPNG  IHDRabKGD pHYsHHFk>IDATxڥQǿ0$H$vեnA u'Y:ҡDKNҞfu 钘h0"O߼.JӺJ{}ޏhzuۆwȄb$!>& o6ܶ,+NKtEFV+ ]ddyVeYGnzeeTz{x<~^UU}8۶=K@6{$yP($@_Tj[Uz!a* G!R#EmY0Ʈ6͆뺻J-#U.rPe_Qh4h4( ?qE{ !l1n;mybk2<JVߟ[udZضzyf7M4Z̀-hv h41|L$Oؘ@se<q9G,}d2;akC6v:?$n:IENDB`PK Qb3fcrystal-yahoo/online.pngUT hCWhCUxPNG  IHDRaIDATxڭOHqǿZ?/jØZ=`ZS;4<G $œAAK Ɉ蠉Dprwn﷋mx>"dYUȼkPӪϚE()bS;@i氅`B{6n띾#8f^rDgSY%aG5H`n2!4Uˎʼۿ":6aIE? '$:!Maζ݈߮!C,Wa6,a>^Fw{?=M]cu[:',KW"|z|[w !$s3 _ /3gz}6S Ct;RB~U-Wi`iZS翎7H]'Zm2-IENDB`PK Xb3@88crystal-yahoo/xa.pngUT WhCWhCUxPNG  IHDRabKGD pHYsHHFk>IDATx}]HQ33:ΚknPCADEEwDtDF zDE]d?Eal?sBʬp9ҁC#Ȏ?"pܕ^s@#.5>I<86:[<$W<# D)?-(i邧kuAi\=pM㹟w(u?HM#$ğ jIK8GAr R~ e.omo}~-lm E̽qrj*{lorQtB{ח6RB<{/9s8o}̽yeP>h4 Bfj),"TEC40 ԅ* ~?c3fJ!HEHgm\ё[OcӚ B`6L,)+ճɜ/1A( v&m$2ճlbQ)4M|e\gqԫ=ߴ!w rAPu :۷޳b]mbb́} ux6 DQTv8$Og_ٹDa=̽>IENDB`PK Z8 Acrystal-yahoo/UT HUxPK Qb3r// Acrystal-yahoo/MakefileUThCUxPK Xb3_EOO crystal-yahoo/ask.pngUTWhCUxPK Xb3" Pcrystal-yahoo/away.pngUTWhCUxPK Xb3z(( crystal-yahoo/chatty.pngUTWhCUxPK Xb35  crystal-yahoo/dnd.pngUTWhCUxPKZ8U'p Hcrystal-yahoo/icondef.xmlUT HUxPKQb3+h@ crystal-yahoo/icondef.xml.inUThCUxPK Xb3   crystal-yahoo/invisible.pngUTWhCUxPK Xb3&N> crystal-yahoo/noauth.pngUTWhCUxPK Xb34;GG crystal-yahoo/offline.pngUTWhCUxPK Qb3f ^crystal-yahoo/online.pngUThCUxPK Xb3@88 crystal-yahoo/xa.pngUTWhCUxPK ( "psi-0.14/iconsets/roster/README0000644000175000017500000000245011305557613014367 0ustar janjanRoster iconset README ~~~~~~~~~~~~~~~~~~~~~ For general information about creation of iconsets, see psi/libpsi/iconset/ICONSET-HOWTO. This file contains only required icon names and some details about them. Read a little note about animations in the README for the system iconsets. Note: how to add service iconsets: modify src/psiiconset.cpp and add new service RegExp, add the default iconset name to profiles.cpp, and add your iconset to common.cpp's category2icon() (and don't forget to add entry to lv_isServices in ui_options.ui). status/online - Online status/offline - Offline status/away - Away status/xa - eXtended Away status/dnd - Do Not Disturb status/invisible - Invisible status/chat - Free For Chat // special statuses status/ask - We are asking for authorization status/noauth - No authorization status/error - Error status (contact is unavailable due to some reason) // special roster icons psi/chat - Received a chat message psi/message - Received a message psi/headline - Received a headline message psi/system - Received a system event psi/connect - Connection to server in progress... // these icons make sense, only when used in default roster iconset psi/groupClosed - Closed group in roster psi/groupEmpty - Empty group in roster psi/groupOpen - Open group in roster psi-0.14/iconsets/roster/crystal-msn.jisp0000644000175000017500000002435211305557613016657 0ustar janjanPK }Z8 crystal-msn/UT  H4 HUxPKPb3(OOVcrystal-msn/MakefileUT ehCVhCUxK)MIUMNMIK.,.It U 旖(䧥dhe55srT4}|!b\PK Xb3ֽFFcrystal-msn/ask.pngUT VhCVhCUxPNG  IHDRabKGDC pHYs  IDATxڅ?hgGwg[:iԢJ*YvPHq%.KI'C3%s :tL7;$%$^ЂdAĖkL&Hr$dwסıBLLLol<}m3a7ɝbQy$_^/_GW_#>̵ mnKqhno( v9B eY9CP8xKjZc0~P껾"<EU.]aHv+@F`4v4O@f! vh xK J?_g=SZco0oLsٝBAA H)_Ξcca9| 9|*5՗H l}+W0c,VpmնJ: - N#mB!~h!z}XJ'j'9r(NVAc6g%@r{^rX4?(:%àknZɖg,7JlFIENDB`PK Xb3\\crystal-msn/away.pngUT VhCVhCUxPNG  IHDRabKGDC pHYs  IDATxڅKhTȍJLH,LbB$ BAEADC.j>LEL.}, & +:ԘV<&D'kIqshM96c--}m==476tDZ7ߔuu]<:jY+[?GY7,okkE wv"$ϳ*ˤYA@x=`2kQeVe:YEA4A\;v8Ӂϧy5&bxnxn覉(I^O8{L&% 2LGr^@o'+ j*,R1GdmRIl!kr/NՍ ƽU;Yr9ݎCQtP{{QZڻ7_~;.bNR0q a ӱ຃#=}$~@3%(ۊ)]/X{m+V*_J11BA+f'w䠳~L܇S 30ܴEs;  d,F__ ؜|!svwTYjwN'fX$7'{W_NMl(dZ.'>xQ3 Wv7{ёs&N>bLmkaPudY]pvw  ib6ibno3J|}r{-6P@Ħ^,v]<< 2ymÌy-`Tj:_85~H;K~/U*}}ώ9mVD M*{=98ί%pݖ d\N;da|q\J<[oz`J*I muzѕH q_mɂ $g?cd3s濧AgJycwuͨ-[͋vd mVzFA}<m.&䦜M]A*EvD{T^ #y\ZU7BGAn'+}29zvDTǼ4+)Y`Pk=s#{?S!eQgzMyq;<7ю'gKNtjږš@=TVW1 z6U.o]CkIENDB`PK Xb3(h%%crystal-msn/dnd.pngUT VhCVhCUxPNG  IHDRabKGDC pHYs  IDATxڅ_hS{ޤILׇY4UJ lA(TT؋WA+* YU+Vm3lx5ɽjMq'vt}Ӧzqx09}|F]}Awcci^fy-=}}?2Enjcg/ڱY&_*QuMCEHk~|8oZ H|aKKt00l00,d@cjuaX%´ml \>P{i@|7F@v 敪b*JH3Eʹg<[u+"8ɑc}>Rϝ;I 9|X0tѢx3<jKwU@`5~mW75s33Sn4[iat]HuR IjbӇ$0] ==ٹ"m-XjOoO.޾}ZYSSk[S -xCT6*d'y$ |>(4y&NG9RR,297Gvb⡞X1gAڜlFדL3.ƣ(KKjeSpp;6jgIENDB`PKyZ8-kocrystal-msn/icondef.xmlUT  H HUxU]o0}N~T mUڒ)SCсv~~.&i+Ux_s8,`Js)΅qE*3.]1黟T gah][`%j +t8nfSh@LDMN\zxt6/ ķ;G街DwP ]ܧ[I<M)Imv ;U Rt܋ sI aKK,>>Qg O)Y{HXI/F n%t\lƖ$ 09uB؃a&ρRTelx’]AUj34wr _ӂ0)eked>),?05A5K^4(4i::X#J%qņemz:UR\`o,FN풗ux/ kG1B]*5hf& s5oȚ r4=+9%Idcrystal-msn/icondef.xml.inUT hCVhCUxAO0)ꩺdTo9M]ڂP޺_e|ҩ:itAL-N5l W>o {r^4nZs֯5cA1ȁ/me(`рm b?8HwuЮNˈ2g *OTPPXk"Y̾B\e`#0HwbpxT:">J'M`U>e paW-T PVIT*Ap`h w\ڃr{ v*$J%ek׈lm{o޼ww.}g=T*IV0M}t:\:=<|`imIENDB`PK Xb38Rhggcrystal-msn/noauth.pngUT VhCVhCUxPNG  IHDRabKGDC pHYs  IDATxڅOh[?5/yM$K֌6%k;&V7A0*Û(ԋ⡠n*e*ښ&YM4yI޿i% /'H|_H|r)6Ta>??=\Zrs97//=xx;_{f_Uyhrd4X6?bn#U+ZO+G.g ^R 3/>iyXIm/4$# ¡ǹ'/ЛAg>b'8گF*G48kDl.zYkgUI5 ^b+PȄg^{ŋ cd2sv&ׄ~!bUakHn051J"yAJy, rf OOMu) g§+$KlFZ:WVm(%E9+F?}>,Qɞ%'(xUJ X[ÛNc[ .¸HrD@VQsjj(DeliJRyo1lONWt4jĎaP0v:og)IENDB`PK AOb3,?crystal-msn/offline.pngUT hCVhCUxPNG  IHDRabKGD pHYs  tIME*f{IDATx}OQƿ)38@B)PM0Fʒݹp_&`c q!1l\( k({;{ zv_/kD,6M$Z8~)}{ٳY($Sɧq''u4r|unͧo?XPhv "~ h q1Y 66z2M؄`ξ>hfA~Cm# <0ǁCsPuloCy3j8vS ]*"!p(k۰ ښzT]B+z. 64@D8u iZH4"rZZ$zzm =br2n:"(6Z,B!q+U5;N-1eY$YFHQx,gk,܋Fb$ M?KL1pގ[_mss+.( D`aj*A2_,AݎR;nw`ŏT <0J񠺱1X1JAd4:P)5c`BDEPT 4]P8a ,x\ՏQ!S |Fe76b--уd½$8@r]٩=? ]^F˅}|ۃ#+׻bz ˓5]+% ia,>q}}p?\|й>;Ɉiud~!},J`0  crystal-msn/icondef.xml.inUThCUxPK Xb3Npchh Mcrystal-msn/invisible.pngUTVhCUxPK Xb38Rhgg crystal-msn/noauth.pngUTVhCUxPK AOb3,? crystal-msn/offline.pngUThCUxPK AOb3! crystal-msn/online.pngUThCUxPK Xb3xTT -!crystal-msn/xa.pngUTVhCUxPK $psi-0.14/iconsets/roster/crystal-sms.jisp0000644000175000017500000002533411305557613016665 0ustar janjanPK Z8 crystal-sms/UT  HS HUxPK .Qb3r//crystal-sms/MakefileUT GhC9 HUxinclude ../Makefile.crystal all: $(ALL_ICONS) PK Xb3Ghyycrystal-sms/ask.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~IDATxuOheoٝm4BvmA,TL<$ "xRJ)rQDOj-IZ `J)M6+lٙ|R>~9t]d2@wVu@!⚦u) ʑHd"833sqjjj8L !ƁN! lˁfx* !0X[[q6jzm۪WDQJ۟OXlzdd>:Td2)t]4MR^/3xejjWڸW'{z.T 6 ʝ;J%:VKY ċR VVcpH:;?\X3e;jqxx8?='N)˩ T|^{J ;)ؘ+K)'BipxIǽykb'''nk_@Y.Ӿ{\&i4XmHiB$0B!K/Z^'&+ f3gOlD"98H(hmZ xGP(Lu8KRx4vJ(y98aIENDB`PK Xb3V4?crystal-sms/away.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~+IDATxuKhu?g^cSiVJcE F-/EDDhEr>`/Ӂ@U{@)Biؘ{?P}4cYQˁa~ ˶qlRJƢWeIcr#& R߹}q*WQ]Q 0ᖐP kTR7o~[LRY+zeZ_Oa-E 4t5iJY3?=ut eAщRQ)GS]?K-z.vZ7*sz`_o !]$XnbG$|1fij=~5@%[lhD 'x2xC c1q ҍ b~(,% !RJ&Ҷs/YXJ%k,J. S{ⅎ}>| iܒ)xdunpѳ1۶'n=^0hv 45^ƈǛ8qKz^Y'.V7ݑ,]u^;D0`fvby IOOͰ{1 AnĢKVuf|~Wv;}};1SH<2˦yr9Rwݶ~5tnLv yʣ8L w~+C!Dlu5UԤiI ^V=9S?}h[=IENDB`PK Xb3Q:||crystal-sms/chatty.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~IDATxu]h[u4iMWۤuLzXB/Tc z=As8‹(R ߭Mt[׏#I{rr:٦wޟ䖨Z2'=q]a\ "!DRJ_E6~pg^=cEcX9"l]*!C9j֔ !Ro}|!RSHtPb ;W[DQWyLd2*Ci81>QcvujUkmE Tm?j֤ ŵbjt~!)W^aHXp+< :z O~ܱ7q#ò+dPʈ`7$K#E`[[;>qdgh@.5Ez?( T~^$hnnZ{`zߡbL|Ey gKTk 8/{TskQs&}>$rvLy!S$0֭m4NB)tSp$E*8-wè'oZ(66*^fcJPmh-u+KA,$XZ濛]:x[Nzo( O%'#sssV. RKI]qF,% pesfDK8 g_ ZݝyH튅]SgݗVONB/C^i&a',hQ(~pIENDB`PK Xb3UYYcrystal-sms/dnd.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~IDATxuMlTu޼lg:LuLI'`BԸae Ƙ& 1nЍ1H4j Q 1.C> a03ň"ړ9\{ip69׻WHH!DRQuRJջXt}/M<71L!|6JuDNJCh﫡:j攸CBο-H˕KXk4n4T-#3Sn]\tvG -l]az! \X_T(Rʮjv]hoLofq4XfudN#.3<Q ~f$Z˭#lxO>GyS@׻{(lܫZ'MI!]Z\tNT0G`:H+H@4B}?~-?o49g3G6zT*ܲ/֊OB{JMzmIENDB`PKZ8$^ocrystal-sms/icondef.xmlUT  H9 HUxU]o0}N~T mUڒ)SCсv~~.&i+Ux_s8,`Js)΅qE*3.]1黟T gah][`%j +t2nfSh@LDMN\zxt6/ ķ;G街DwP ]ܧ[I<M)Imv ;U Rt܋ sI aKK,>>Qg O)Y{HXI/F n%t\lƖ$ 09uB؃a&ρRTelx’]AUj34wr _ӂ0)eked>),?05A5K^4(4i::X#J%qņemz:UR\`o,FN풗ux/ kG1B]*5hf& s5oȚ r4=+9%Idcrystal-sms/icondef.xml.inUT ;hC9 HUxAO0)ꩺdTo9M]ڂP޺_e|ک:itA&L-N15l+#ٞ ]-Wwkc {f! r9 ,{=d X4`uX{1 p$ABݻ:MhW`eDэY3f'J*(Tb [ZFj5g ,f_!lDlF|SN;18u*R&y gp _0ԫ*yjr'78]oOƦ-R['PK Xb3 kkcrystal-sms/invisible.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~ IDATxuAHdu?{ofVf芚!Y( уHٽz3m-ڂnEFP` F.XVy:s޼w-{>g𯘦y1vNBjW:h!D4SZkOHxʵoz+\[u ~K?;gT>UT߉ǰ"zޟ"g\ϣq:2.SR/BQVy ѐx得v.fIbM.4F$BZGZ H};8"$177ǡ:@F4R )Oūhhՙű1p]00Mffggi*?C" R/TTw:=-([[['qRteYb10CQ^@>㰷G*bkk 0eii}۩S(EŸ'߫@V* peR'Ix$>sGsB㉺kAXQd2P(Hux^LӤjfGIg_~AiF L&jEQDrCR MӰ,znY֟R"SΎ}25g cR)j5urkhFFӴ%$z<&?LoGp_eM0 rh4[4.8Sb ԅ>ǚ\>nPȶ%ug]IE$Kf?]eo{i7obR[4>nϣ(ʳ'8LL P縴:f,j躾iڕ _:4Z2f[az&X(~Oq>)=~IENDB`PK Xb3qɄVVcrystal-sms/offline.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~IDATxuk$Uƿ[îT"]ib!fPP@@$20{q9[.4;YY Mt$+PE{I=;s>E^Rq)4BTJ=ZkK0 kZKy}3cl>KKKw( RʯR !?}S(~ A[bwwmaYGϧ&Ǎ`HJٝi4ͷ{NNN R J)00:: c ZCkح;u뺨VXYY9qyy#܀J)RjԚqw={\033~8B^122!,Cj0nV0 Q%vvvpuu00t$Y}B-zj01`&>c}Hsp_e#0BțjE$099Y!ci !R~wFïT*qinn J)ʲ)8B\ow3cm B4JCGeI)~s ۶߫}X4M!9ϴGtccQZ(BB /JŅ oZ-0 89?̲3CrFBH1m_4fI6779GiY? L !PJEQRWf%IENDB`PK (Qb3Ecrystal-sms/online.pngUT ;hC9 HUxPNG  IHDRabKGD pHYs  ~tIME 7q IDATxmkTgƟ3{gzN2_FBDiS(hWUԬ .[(.\KhC(PbSI;FC&St0gy9C2,e eiV@ bBC+͍t:qv;}g'N>9'K*V#dnSrBBJ NGp 3t% h?]iǏE,5{.,bio 2V0,T_\PbE5ضaD&7ŗW`s̱<^*qxlPB`83ggɷ- U+ܧvf|oJK<> b+#81 )$zٖV+fLSÇ7eXuX /{? [qRB*/TzKϰ8DqgC`-mV7sdQ]\cRi4-87P?wGLz;a2P47}{l\vbjw$L!5p L@sG+bvw4<_kk;#ܙܴT 6s/H޾ʰS]aÜ}8;Ѝԁ22nMMaE qWE$kvH(PN)bXn`<oY%O;% B!5) p%--me XIENDB`PK Xb3Ncrystal-sms/xa.pngUT XhC9 HUxPNG  IHDRabKGDC pHYs  ~IDATxuMheofwv$l1Ml͆ĆEBJT =E x'/<DQ AMbl5jLiLH6&33|!mU s_bX-}9Ԝ ,HuwO>3nrm*{>25݈aTb{;<=ܵ'ȆDWF&NE;oz&~5ќ ݜOT,+,ܸSq4iNd֜cFx"3l?Fa~qR̮R\`w:#G|22bHh}'wMgGme9ܻlS\CN<#/g!B!ŰZO~~sX(~=OL&9}&+k~-5ԝOdg3)TU T?DZ!WgBEGR] К>X)(mavCxg+4A-.V? ccrystal-sms/icondef.xml.inUT;hCUxPK Xb3 kk crystal-sms/invisible.pngUTXhCUxPK Xb3n3 crystal-sms/noauth.pngUTXhCUxPK Xb3qɄVV crystal-sms/offline.pngUTXhCUxPK (Qb3E +crystal-sms/online.pngUT;hCUxPK Xb3N "crystal-sms/xa.pngUTXhCUxPK &psi-0.14/iconsets/roster/crystal-service.jisp0000644000175000017500000002450411305557613017521 0ustar janjanPK Z8crystal-service/UT  HL HUxPKPb3hPWcrystal-service/MakefileUT ߁hCVhCUxK)MIUMNMIK.,.It U 旖(䧥dhe55srT4}|!b \PK Xb3xcHcrystal-service/ask.pngUT WhCWhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~bIDATxڍKQkbKh`(q M v0l'".ڥ %tJ.ctkZ+KA41D~!1PteudZ b|(KK''0v{B< j5LӼVП3$\I N0%:=Pj5r*ڢ16kuG+t!t(ZA8:j^D_\uu \B Bk.'&T(e\n!) ۛB˲"8UaÐH竪warMF"Q2./.䋔l^F*|iʊ4 i66~9>v8j +6_A˾IENDB`PK Xb3nlϡcrystal-service/away.pngUT VhCVhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڅ]LeA+8EBDra?,3tzQCbL?n2f[\u(T&$ 6v@?XiGi}@\q?vʼn,E`?݁/HoG6ǥ&Af`)$,xٓtoR,5UZx4iDБ%'GX3~Kixq;e@4_ R((Ginmt03֣A^=KlРPdwy2l[9^;G` u]f[|Lh\@l@[U@+E+Rʐ՟Ϣd-T WIh}߾9VΩ=6ƅ,%=bM f#Ggp&~@)#8IPo#+6H&.5>@?Lc+IENDB`PK Xb35crystal-service/chatty.pngUT WhCWhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڅKlTe<; 4|$V"ZV&F\14ư1QE5`01j|GL*6RNL̴۹3@nl6s399p'4pdֽw%~ev%/.'_%)e7 ݾc̷nSPf+zM7 -alu2#-3b?ZC!{厣/=鞧/ ~3m Ȇ"QCHK4Q)mM>/ya'jG^,VFi֋&M#?҄yq&=γu&sgO0Bx مÕE|5,3 C O3>JOtv3hmg~م" ^seݍ5?>3gk8tͧ ˍ,MIP!v:69LPUvC=R1248 (:# ]Jו - Au eA.Ǡm rP&}Ϟ q]\"{Vr=(8Ւ9n= @JKy c'֎7/r_S:GQ33IENDB`PKZ8{T2crystal-service/icondef.xmlUT  H HUxn0)NJMB+&RE0]@%6M'ڃvP*&r8_}~JxCcV]vvt.լ^3\fZ8-^4}Np\w#FrsG[r BBv (=_ІV5yd8{/&pS/܅@5<{z&3&t;9 !6͗ǝGyxfP@Upqt.y]XBX.]V87EXΈJdV?5}Viţ]HD0 B魰Yس}LF VZl0 \!mSa0LְʽD V"GoBbR", !84=!ZKkm1)eC!YvBs+v3d;h}2NK'jӲ4]|_.{-lU)h=*YaJ0*9ƻ4ڇMBC5G[H&3;Ym#b}ȣf6XC+qxC| ߌPKPb3t jcrystal-service/icondef.xml.inUT hCVhCUxN SpC8恲,SaOSpҷ5 >Hh;v%sX`[#߫4H AӸ-0;vs4 Vi%!5j0} B. {# o((&~j4MGљї.^)PFB=>:ыMb˲RR(NLL|ƅ_]sukw JJa!JeaJ)'S}g}|-u)R\.|>^@NhdbH&aii `{{,ֵ{74=IKc6}Zr&199( \.~?w=Ňx}AkM" JBioot8 "x^>Z ccc100@Z 6Fqapp4ZAWWJrLcc&g˲jH)QJ8B,:444P9qLOOx炙!mV!@ A 8y\Juܬq x[[[9::"Ln0Mp8|e*sh vcP:U__d2<77wC S^tU,aIENDB`PK Xb3**crystal-service/noauth.pngUT WhCWhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxڍ=LSQ{h X#b򟐘hԘct30f00qT)7"Ft VD%\R=Nw}zb`6%L2??O#@477LR(؊^/mcYP0Zo Bkzu-C8QXVJRJٸush%2g^kRh!u] SCd}R/^)|R{@i_A}`6R |EpS wt.qT]ugU7|]UX]]E)U(c_p.W{eWrZ$Llbы5zBxxçLF%ie\꧅e4Z30S!̜ĞM#2944u Sdc:ȓB?1 `B~|y)|xyDKk$S ̾NNaF¬oaT(u3#P2s<2\c(++QSaxݟ ?l}}S,CWnF&j3pƛ`$|%)!DWΦ) +%||80L69sV\ۚ?M`,V8|vdu1 쯟 3>T`0۰ysgF&lF:&PK Pb3&>crystal-service/online.pngUT hCWhCUxPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbܵ[|w.̠RBELy!RÑgGdH1Ff,r/Ѐ`cb8ntgg `b{ d Xg` Qry# v(&@ՃR_! ~\/(]o?3'χ*?v3Ȁo/dnxX;ܯp8 . B @&~{&KÇ 0pp3(XK;+9¢% 3e@cL ]T}fx|O.dUA&?j/3{30A,;1#*,//!6௽@Ǫ,7)#CC3Æ PaK[/a |?Xr''/ <, 3<L_Ff``5S+  d'"VetˉZjj^_d@033|K*~a-``LL pIb+Ù@K >?3ғ>w>5@IENDB`PK Xb3ǠBqcrystal-service/xa.pngUT WhCWhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  IDATxڅKlTu{ig2mTU4"QЋn >ąqhFc\0J\N cp+hG)Pqe^SP7-9wrHKL^H0Ab_b~c*wۯ܊!#cㆈqnl?pzB,"=4 zݱ^,fR/\@f`EW]AGZ;|3 I)%RҳkF>/~HXfOXg]omNojqv"OZ4a F̗bѾ[F*xO+.mc&RJzZT"7tHdxm@s{mb圿G:j5Jm8mmz︍ށVH?m[*pTjR)2 BۖzUʆz$*TBQcW$av,%O! VC@YXb:U eY7ƸTW9*ȟ~`jCJfq>;TS6m&eqqD66ߎP\BMiJa9'Rl+ąKܷ}X>7>]c6Z6akF3o=0"Q)K_N=}opO @0ovIENDB`PK Z8 Acrystal-service/UT HUxPKPb3hPW Ccrystal-service/MakefileUT߁hCUxPK Xb3xcH crystal-service/ask.pngUTWhCUxPK Xb3nlϡ &crystal-service/away.pngUTVhCUxPK Xb35 crystal-service/chatty.pngUTWhCUxPK Xb3NPrr crystal-service/dnd.pngUTWhCUxPKZ8{T2 crystal-service/icondef.xmlUT HUxPKPb3t j Icrystal-service/icondef.xml.inUThCUxPK Xb3' crystal-service/invisible.pngUTWhCUxPK Xb3** ycrystal-service/noauth.pngUTWhCUxPKPb3ȕG crystal-service/offline.pngUThCUxPK Pb3&> crystal-service/online.pngUThCUxPK Xb3ǠBq crystal-service/xa.pngUTWhCUxPK B$psi-0.14/iconsets/roster/crystal-roster.jisp0000644000175000017500000012653311305557613017404 0ustar janjanPK Z8crystal-roster/UT  HD HUxPKPb30\scrystal-roster/MakefileUT nhCxhCUxK)MIUMNMIK.,.It ֶKKKW).rSӑ3K<.Ĝ+ Gxq\PK PZb3 GGcrystal-roster/ask.pngUT xhCxhCUxPNG  IHDRabKGDC pHYs  ~IDATxm?leX 4b˔Jv1RiW,%NTlLPՉ%ݢLLUDUՐGj't 6UN61cR.\%]{$EemxxR:L&'pjT*ŭLHBߎ}T*iXE\fyy+ Bsu-r_MNN~9==-g2 BTU%244aeYvm(Hm|?n$Iq$L'F]eggqxY㠪jz7>7'V  ;ûpI92u]f ixk|iiPdj 0Ul޹Ã.{{{}2o~ig^}Gv ydxY{Ӷq lۦT*|y\xdd*b8{&J 666m\]Ey!~H' 80@oveqC!jGl ^}g##hw" ܺ}.j'OHy{Nh"pYbKuV t:v,xZ B ibϣ&!YRVaֶvww-X1:sx \JA<ί0] ,鴤^ņZV)$I$@6(,0$"IU8w.VOu_^ _-j8BIENDB`PK PZb3?}QJJcrystal-roster/away.pngUT xhCxhCUxPNG  IHDRabKGDC pHYs  ~IDATxu[hwI51e[XgbȔވʪ"x!UF&lxdl6FuU)C0gIiksr%j}KT!cjWrVC~GQ'_HŬP拝oUP-H Α 2U/`N#kvww 9\ Ufz'7;ܸ'9[DbMlJ~G KC$Di?ŷ^`G;Y7ĦaC,LI4ԤL݋Y+X`?9vOOWrdJͨuhؠwFGx6;zڡP6O'ǡ;|^n0acUc&\-M\́KԬB-5'29yW:WPa;4SXmI0.:W 4w0ykJ?/FGX("D3ÊDŲښz&Et"(:H'*^DED:x<_uO A{8ER֧s굛tnw LC*-P(|`FZX S?r W⚟&mGMY~fkuzhdO{꾯)"{]2!ٚ.=*au NOӵ. FoZw7<!@fBIENDB`PK Pb3~'crystal-roster/chat.in.pngUT hC|hCUxPNG  IHDRsO/gAMA7tEXtSoftwareAdobe ImageReadyqe<DIDATxb`>U1_0b%A T:be lzZ0R@8 ``cgscrRfK@a5mC#cF  OD- u1A/Я9q3 "/cx>߿ _|d`` @= ƿ '0;Y%A}"@{N2~}Fo#P3Õi>[ha@}C|n+>L?ڼçmw2, J:x?Y"X Çw0l  JJ ~}'DR<?@(zȞ 1#ïMP f0=bO_93 oB :L @5pO4\`hՋv_  x NdP>05 :+Pρ'^&Jxob͎UHxv́+A.ENM~wt@ BDbhl>`{J)4wu#o})& kc3dR?0dIZ4@l8WBǾ)hBd },2ȵq27[/Bh0@y?a|6~ʭBiE'rtXұ4|#GWWTzsN-_ Ņ׃_gāMZKXy*yi_rR)f'+k틛'~:Azlυ`Hy8x%a8zۀmHXIjDo߉QE\^濈e|<7@Gv4tx,:qx=7[?G 0d1!{Ej'&lz$-זkI6zEo 4Z{[@)РEeW͟3_|1>8h+sGhx?+0ހl[YH,Ugk>xe\0f8<[Z?Jx;Yh9~^ Jg`QnW]yJF /xY_cK?{m`1%)I UAgj@O,EA$23V9ٹDMt$I%({- um`w-MmєǼa6 %dW]]=gdJY^ن})ps߹q_SKH< XC$cB<_,p9\*PdvrE Vc|VH|&vbΦDD:cPw=܇G̴mmo-)Xlʹ0@/*5+ [m4uj57.Eҁ[ +got=?LܜΉ @NΚ^6|Wb0׹R3x#1 sPWW_EG.!mL*,E"{n1*cc}Zu L {0TW<q>pFNtk;|-#>UFNJ% k Ms8tuO#뜸Ha6s`M:Q4L蒻U 8^4vұJgH=i6'vT[;˫W+ Lc;UhI]Ʃ;FNsz>ݱR'B5!vQpnק~DK{3aA @]|U_Ǟ++fyCy5?CN!-dY(Bu,^G"wQZ!!A15[#: =˫+"WTrJctEȣҸ!CCY)O$$}mBǃjܿ 5ΖueAl-n-1ȼy? /ү}H!tY+0>ƃY2~OZ-݆=N6$Zb/BN띋2,do u PBE3o(HQ[\a'76ަ͵k  9>沉e@q'Ey5 UPO<Na0'T:LTg uڭ50T3 Ǵ|k0h(R )Xo}l N@g!"GGS>\^Ka⼘Ij1fspY'5t93QgD*uI~Py>'+_`niBA,`;pjII/^ot vOsUVDtDԂNJqp g=LNJTbwJLU{YrwGd'VU.Bte >}Ym᫩J|VdU{_K-"$MfTD=%a꣐2+M7g|R(Y\ZҐ~YEi-XmdpF4žZ6o*X9 #t?xd/Ş*VVL͡S@}ks9K.h4#p  #U\9d5Mz{^sI'Fb r{#"R Cb(沕8RKA֑Yʑb-"2$'_$ 9Ȉ-Fk'`QWu6Rϔ&ݛindxމrqN2FYZ%G e/S4!'̚J$cIn_ӄsU1;| YЙOjtFEB) Jaoj8?F.Kܘ;IMm;ՉW'p㪒w%[PB}e'܀eV 4CdTl 7tb 塠b!aG3e: 4M1/jGz;]q3B-\#%Q6թ)KEߏN6IX>{wqΎv }BY[.6潨򡹦>#\&dzGO$[Eڏ`_`rmsķ&u{=U#3h7aO٭1#sjӾպ7!mDX֭Lw"|] ֞j}[ke-(Zd~xCf[2SҨ9+'6iV :aZRfR̜hr6C~:)72[vxez'YED#C!5@oMϦ=oDž#~}g í[#9@ٖRѭ/[zɪS2}".ÞYfgj_HtFwk9]^Ե6;:KթV\`xVX#q*Z7؊S(M(f *p: jJ>!BL,ԑ^sƤ9 297E'TԠnOB[Bk?? 4˃J6SƚNT]j[nZi^W/ÍK>zXToP(ܣpK^} rO?[* 'V0tLᣏӑH*#*Tm3q}Z"! H%F>`"6",%p] C"(j?`j/a͹MWr4x' F.g!˦Q7{Sb_SyPxQy"*!έI9m-3}ɗ?R(ByiVKe .k j>#?PPm{(s9ɳ,,YXڅsC>h…rŌLZ>] MquS0BsLZ_F:9 Q@LW#&4fL6a}b_j}lSN`f<xeӘvtݩz8hJ`)Du=Q嗑0oX.m@ÙYKwh$FOhLO+ysXkҵL]c%'V -1} nN@l-b:gw:g9g?uʗM4]7IENDB`PK PZb3 H  crystal-roster/dnd.pngUT xhCxhCUxPNG  IHDRabKGDC pHYs  ~IDATxu]Hawm-͏"CEfEݔHtEХ]D]ЕAe723fe96B9<#FsY*VP(fXX(%n:jJ# [ۖ,Tۑ\  K;=fk}Nh )Ο؛vuelwK,Hr1oB-%z7EQ7wUJ+w: eǑaC$D?W6uZ+Qx 9r:d܎1;ł=u7 PLG )`M!b̔S (6 yG w#eopj` {2 -X\Htv Q_/,DFi4vM^PC#wҝedqJ/Z~ien' .L:l5hTH;\$eXk=BC}!@adC}jxӋYxˡE֚|t1$WL4 v;1).l+BZZdEIY?U/T^C rSl8sed­ќ_0|t$|SPl6Zlf46KNe0Go;SEUݛ<)ZUp,}d'Lʱ?nZg ,3IENDB`PK Pb3$@FFcrystal-roster/file.in.pngUT hCzhCUxPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% X@ĒGqr }? _~g ×/~w Ow0\x @.XO?iˎɞG`>:z̟?oN+{ _a셯_1|:?>6V~c߿b7?116 s QTŘ!߽RĘ=*rǎ5C!Z @C!;++#3#';!^.W@O?  @; 4Xr`G(a= .]@@^ tf`|i ' Y_?>'v?A O80‚ hׯ ?;Û7؁3 LL@W`@~@Ac0?Pd 4ϟpb/^axSEׯO@ Z`F_??#Çׯ} @_7778l (Iׯ3 `2  IENDB`PKQZb3"l crystal-roster/file.spinning.pngUT zhCzhCUx]XgX֝$4ґ.(]D&A@*AzބH PD9s<9g׬Qz:TԸoGr. [-}E^.W5̼.W?Z20Sj޿k?{mb%7UR%b"#]pJ[~WĘVa`tLm1E K)na'02YN2]wrҫ>^{͊N1sGASyʁ\y̺P=ھ )$>< kVJO4<|3+m-y1JO4W \@T3lPhT$ K/@j'7,hy$bYI[H0ԺZfNy)ϑ.͈9]ByLEw@;op@0soTdkm 6Y5kY]kUQSج ~u\|t/\_]rexp8V?K+9V +x妻򔂻yuRAsG؋Zh}x*w s$48%n~K| PBX.nN'+I8D&~m'BsrpvB|m鮝 oԽ^xrn[n=Sa9NNzC9*;;ney1QthFnMa?>-UYHfG 4J]2q4%d:NZ|7*۞l~&Tt)[eXIB?w8_?zry͔eDֶht_u^d'?4io}MZLn'T3ŠG5 H<>֗zU*_tXͮh(@o<ܷmAߣh *o7I0#w;ݼ Cns"v7&bI EI+,'rgyg"|Ll45'4*_ЛnC'k2E6eҙK 3B.wff?HK+rBgQÉ2S~7AƟT}WԭVD> Eۤ>RtHIV:8}4{|'dQS1wVS=ɡ̴"cz=yiD,n̛ ڏTʹ4G)ۤLJ7 ۑ_&b- O77g.QJ$TiZoU8#ӛe;-4#1Lrb. p7Y߿oڊ˝<=a "û\\Hm\DcѿOg8"Lg3BD{ ) ]d+@(?c)%iFgT P ,:8w*98w#Ʒ|Ĩ8ѧ(l'`13xR%^CE㵷kgЃS`(;H-wSn{@=O{=پ=MJa{X4L݇BV F2N/nɟ HR#tƉSBd?>[ 8 xG!FYߡI훡'JaHLJހdhy\wY! #6^1| Z3C=oP7Æ'^JN~~aa"2EƭF ~e2TG卞#|LYw٤Te1x %ewy n{I{=НE&/:tEQ/II01q57TC&"eX@^/*>0/YJK4ݩK3F_RWwacqDu  tHdbwjܨ,4T\|WxHIGd]Y`Tm(E&z"8r |@ mnW+Ajy4DMwvUQ_)MBI͡"H{t8>t轺"/9M ě3iWҕ甕GWѧbFRTK^yLt FҨk:oԢk/&VӋB劓`mfeuS{i?߿6 (0?G 54lDDWPkΨeφ'- x|(g$e{ߵ,|j#kIZ!$(l ^[~2k[v÷eZr{BoZh$ F 8.u(27{t<.zdwf1E "֬,D C VvbwdiNGF1/={崤: 62WcDiħ )VNЂ 5C+] O0[Gz: m++ˊ^c$fwufz9DGLJZ6Q.&ְؖHX~NRG拓ci|/f[wj=DCjw6-\o=/ _qjSά9^cgA8 k‚=ms1{99PiWooww-DO,ͩ 0Rb(г0a&EƱ9MMEsQ&'xFL+=Wui~z ?rݘ)8-V-FCF `BvL@Qܣ~ƃDL`-O(#*A}^DP {2MEA$sᕧJ26|tk݌kLQPjf`j!ܱwfXixABԤk`37s}Do(#! RgccUfI p~21W6.ؑ(C\_L[ M:g|D:doɄiTRD띂4ÒijZ7mZvg7˓{[7E{}H,3Xgb^ߥ¿B/4 M0$%8lHTS[S`>A'h <̔ffoiVU1(ڎK|~e_(zR[PVx F:Yrn421$Ag/5- ux|ۭ^1K@NL]dr^N"yѺѿW=0ZYapNT~*"W<Ǽ bθn ELΊ1 u*R K6ŭ Py'|+) d91f21TBB!|<]Hp \e|H>yZnE-(nAQ G p \]]h.q|_?µ d0iKe1ݸҨʗe`eja8.`ڟ<==-k6_4BkOj9Ų 9w|QoiZȸL{4LV3@>biQFw XZԚ]\.յ%^szw@RD5{ЀjcsFWġ"U(Z]룋_YܟQT% sS]Ȣ#cܨTNZ1XtXW㋩v)ml,Ό;$wHWnBB#5b9 y0//DdJՊ)ƘFnS8/wl]&=1BÞ>&ܥȷͣT;^+>^GX=Qx95=8زl,.1866[W:;kl,Cj:K^f =!͖lM t,*I\{rۧ3Zu#ٷYŷ TE^Jh+2' &K} FG)6G 7׶SͿ Ya dGGȰBAz#1wir>LGfKMJ{Yf fPam+PG&`7 5;͉3zXa*Kz1 ,8`25~'4PtTV̇.2F'(˩į7/MBCCf x~@]aڤ7S<7ZH SldK){_/4UC[mX1m*4vYb}8=s!#o ߊ lKܜ`e%E yP#}}{"`|nˠO;fT߮yM ۈTx$3$;'Ӧ6xo9O=Ll(;=LϬsknwZ@6nw56y#0_wFY*S"ag6suOqN)6(R>< {PKfbz.$e򣆤5QetKZo|5P,ح-TX>"ʩj%ilnW^7d ?#d~~WzT5{n@ϕWErۣq>p{{JCf;ߏ#G2E;kjk :RwIcfMxFuV 6C{=d W&Ed^Kspr/--aLY|VZ/[v8Zwg3J5WQoC'Z9ꠑeghEaު}MԤOl , ؚ//'aS_ocl_v(z0d[1GtH]Ŭ =Dz㓨@ѴI-λ[4H}Pi^N[}Fu\Z>Ayԟ?eO], ִ>=t>j6=&vc`ha-|=k|Iˍdqx7Ӝ~o~buI/E$8rqg?ᚕSi\p:2~z 9#>y@cc;Sȱ`hw#AMUppUeL\*SJ+>W#/T)aO-.GƿV3d ˊQnuCaⶸ(6)_AFgO1-O[h~倿Nq^>aqgm~P\4v=lR`e.~wuum,SLY~H>F%A.(+C;@#*?xFч.tjYF,rϒ].wGrDbPgZY}4O?ooOfGWh(xmLL+hdWFWF;~SX;UKOԿ x` Jv1W+p 1 ׉d^<"4I4xn_dg@ Ʌ*暪:T_PKPb3د crystal-roster/groupclose.pngUT hC_hCUx sb``p  $2]qxD30p 0㥻u%WX9dZ< tq tFC".0s+3Iti87yJJ)Qr]IX1jeXԲsSB -{2$40$j1T=sL ˮ(XsCQ+xȏ_O[^6) PKPb3sW\crystal-roster/groupopen.pngUT hC_hCUx sb``p  $28 <"Aa K#ƾ߁|d _*UfKRW V3'uRq+yaJ Z  b9K8O8i:`pKBKBK!H`3Ƶ?;롪>.o4UapQ.9mM;kD+p+4,st¾eWcvNa`X0Q1I,dzUa~Yc97Q»%NcdP^CUEpGVFFFwB=ctsYPK Pb3=hAAcrystal-roster/headline.pngUT hC_hCUxPNG  IHDRagAMA7IDATxMLuҏut+A6!"s2qaL+fQR"dbyxR$DGGGN`Oڻ‹ IRM캊EU !u IJJ ekM7=.=4ڇfC-'02.EFUTUs5x.\bP8:ՂG Zzl$YBQdTUQB{&n*ҙFUQX[75X4͂[VYQfj6^tQuS. 6R9fl_׮] fGؑC^mg|jO?or0>H`>Bnzg?gf!m,,__]܈ ~H84.$yVhu(&H4!Wm2UX*,#$XxߟһdÍNvp׃n-ͬ=lv`YڊDf~3V\".IENDB`PKZ86@ crystal-roster/icondef.xmlUT  H HUxVn0}{&5 mB*.$ۑmZ}~l7vRx >>&:[Pd;zT}K/Y܍xdۉZFN$BeQƢ~dw QSyp7'7?ЅN%d4zA\ Fp5osԆ䒆d2·0ܦ~܅hFA(Ȝ^?>{'Qt --?!L`^|^AK(/ΥV*Ȕ T`=T|Ip vMB L#0]sGd(*`9{``aIvOP31wr _ӂg0ZvS2f'f6=1GGO-15(hFv`Kv Co>H{q ,(\9:ۂ {\9{q wgCd6KalݤQaZ X&eN\>p)M";`kllJD3K5hfC`[/NjRQEPk4JBW}΃g뒆$gcSr)T6w ́f}-ʌhZl V2 d BC&Zŕs!eղ(MzUp7 Ei/6T%vv'4PPPKPb3F= crystal-roster/icondef.xml.inUT hCxhCUxVN0=/_Ү zUPWe{!mX֩syy<>d^XpY-N تNfY}U~/ΛZ ;X7'Z4j 뽲̷ z5B;b>"WWc(f>^I:4RNIvy7An`(QO:&e!$@qS4y]E"zJeWOixLS&K$^O-nKx;rihšadEs,9T|)cIihBK~ni#)64`V DjoC7;D3[ݘSY~~=GjK%nBE}n(%ꄔIzyupq#Jj|Ri|>U'_ PK PZb3ͺyhhcrystal-roster/invisible.pngUT xhCxhCUxPNG  IHDRabKGDC pHYs  ~IDATxmO[uC-d$0IPscq\(DҘ%K\ h?Eehb0/d%0[ڞ+z'Os{$R^vw|v+7>qPxU|.>:ǻ.g e/yn8g6]wEx$ұ"1=:"(xq3TWO*+ܷ'{F`l6K&.{9>y !qf>ůheibY(aDVu$׋^;/LLLH۶armmM˭-Ne2HDy_>%d"B`^immc&bUU4 Mp\b*E-1V/I*"Hlll055E:4{Y,]_J Vr9<ӌ( q\B!6o*mvjaH)YYY!LB077GKK PMhll.7?&DJIOOhnFFFg``r6qGb88 vRFGG|\.G}}=[,@4˲V(i8˲j1fKgg'Blf{{rGeCD"N ~RĮ/VNO᦮.wg^{LJ}ꗟ㕔ՊSKP'pdIENDB`PK Pb3<crystal-roster/message.in.pngUT hC{hCUxPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<{IDATxb?߿!~/{.._ݓ ?H??~Gqk;ˋ;wСa߿lV @h24R53Sdfx3ÿ /?Hwd66 t?c"uue$dY𕁗AOOAݧѿ~@,@z033FIyjkK*+0prۯ@AQQAWWa˖a? X88hyz @ p`~O \ r?7@1~1\… /^|/_~2] @h< 6b66cj*w_2:upLLL kbk fK7>|5PVSafÙ34-$ϟir_lc/\P3221(P^0v޿pUb0m8}ϟRw߀à"Ơ# ?PXas V ԛ@,Om8p؆05ǏpGOt;;;b7VӖ8q+QS 1 q7=֭GӁeee_>b׌߹|7r--Uea80ќz߾}&,,f%'ONo}4p@ \x 4߿X q. s2:0֤򡜔$IENDB`PKRZb336=X#crystal-roster/message.spinning.pngUT {hC{hCUxmy8TU"d+YBBbٲ3vB}d_,QHBu0ֱoAe,Q}}u9s]ǜs~UJMFFF6$#;|%c`?Pkp '*'pHFƌMd%9"EL$܎zqAgaRH+eq"oQ / Wg]_% ֡ܳG EfE)zÕeeܡq%q1Y0Y⧪޵?)sx~r\lіm5)Rgf߬@ѰUHO6m<`&W*D四'7_g>پdd-b`n`mݗo3z 9J0e>T3P~Vb;b)9W}&Vt-hlef v(yI#[IU7.fDOtޓ{H$#~K| PV3s99?/_|o rrke}ѺOtRMQYj A.#cKӳ >ik8%Bo5t^i؀'O"or;rԂcT#"43126K?/pn|nʳIL P%jjd1XΌlOMǚWOFJeUԾ  ]S&Tg!++O3 ?$ٓ.Y2 G}hOXߺ_R LH{)t*Ji aL$f^IH (N0_k.Xs}<+lp<!@;?z>=, &(  v-X:e'>_d4.{|P9 6J0z;Y:\n8zf@(Tj8q̟ԡ6xYt Rh|x# =[ܑf1bMk&~׹&*Jެ,jgULBQ;ATU;_fZ =g =y<4:㾇v$EzH%ԓ]I2#B's?+ pɳref.!i`ǧZY^1Vj+*dsw=*kwGG.,RuiVIŹtCPl]?' 0i8Ori[8!$aK-<)*L1~cRaQL|(~fkX%f$t[?%5)#:ǟhscbσajꠅA,ª2ˆl\,T}Q}JŜ77z] uLn}X}u5 bB"MB!NKt,!̹9ӞƃHSB v.V]d}к5c@n389Z" {rc%/ [ Wm`MLe'hv(*dSFX_g 8./]ttE}) qc#mea3ӀڧՕ(_:Fyn:Sq>8{Ux)S|Ϗunna :;{r@& YF곎~&jMqtyyІ(<;;[2Ȱɰ`42<<,)T-.+&FCy'ɝ&+ݚ t ʗ&r / >ܞA:[[B. "5赲:pZFo+-H C}q*To0Ga`H4+b6Kƶjn-ިSr_@!BL(&ʈsQ7 3g6Qm|mJKV_lc֢ؕtI9q+5?ArWps"k?RG/iPmLݹD2wǃLZE "&/@1s9Cg1si!$1Ft/K8~3t#ܷ% 8nK@ Ag~DBr ('t^8aWUëkcErx?Q(^1G>:v- nMec@…S)X_;>V5$ch>5O4OGDjDjDV+'6㨦0J1/Tj?Ԓ,+|Pc9*^o^ dY;1Gᐡ#g}]Qj<QMokNѦ&mQsZC_*׏q^j]3dTgi}'DB1Iu!a:- f-OzT_ر*LM$?}\0OU54>PyrX.l.%Kwup?hk(L =ММSjn^cg5``~9>WiaiyOUU>{ι&dM{N΋칃 >K_y` o埫4A5jWPք ^@~6sg4e+S7,-UDD8W[$$NH8&ɂua{a`Os:_O#ԓ_c,yIIuv ИʔfoA(-xЌ  =Ћ%MN( iv V'>P;M_- |&wXF9nn苎Ө䲪XniWȖ*.'z1 z=t층GKk)ڶ zƛ< p:|_Ү}۵3ʂ@ Fs jN ^xu/׎i1zolLp˻m" <}8O?8\hT {OP,H.*ϘH$H/? 4 oe xpdAG S%x6xoR^mxtvRGʭ_"^mR|._.bB-$AwO:.wO >W,+ WU^c@Ap~?.̔Q@VLiDRY[5d[ q⫁XXWGG7听1z䦡NRJT >~L\޳uD>/f==xbC0)\ДRm `V}77UJJJtsm;/*%v< ,jttiu/5A L6%|nuY61eۮ]ME^"_.7m_ :O,kz'x*@THYݑe*lۀ9|YO'`0%zK_؉<4#ϔHDQS:U4ep!w#%q+dglR==aH>kw(vÏ'I('CA{ڪUtC9`H:X౟i,m1ʻ~8!YOIjK퉉T{Gb雩ȡVw4q-=V&md40 AR₢ok9;Ù)f cu # pvn W[B;ywRd_WB[=ՓS!e "vB ÌYfכwhmk^ol.qWyNe7KR .Fʟ%Ԓǥ͗6 DUae , 1[ 7#mEV^䇗)lj>qYqs;ت5{} O Q3j3CFX k`ȾSܶFB6mN>̻f g 3^`hYPsMyV2P#J\_-̳Ö~񽾗_IKA7-obH6Wa'BZcgoTc%2gcn="$&S&&eM-JXҿC%.nS f&_9ΫaOSQi:@p -qэ/xCЗRŤH7H==w/@edr}[aVW8:yAr/㡸ɿ֦=~K(kjUUٛ-t'eYXy($%%e"e藎6A[p}w98ul~%*lwB[(m 2<1 V}fvD,p_;Qf؇ЎS;Q <ɷ? [Y躺r %Kҷ~E]8 Fض&I?ЄF]X[U Nzj39Bۍ5B_.&c9h^Bw|_ѣjZ:vޑ"VwOS'J޵ 22ٿ6Ϊh-I"O)TGULzb^cYV{tPH~ b.aAطQ'rGBkJ6k SS%C]Sɾ?KwneҚ~Q6${Ժ{r+Eϣߞv\61A Bݚv: sDYғIRO% <F{K'Vo%g䛸OrHl bE"!jʷIH%1Ưj{_PK PZb3^*f^^crystal-roster/noauth.pngUT xhCxhCUxPNG  IHDRabKGDC pHYs  ~IDATxmIhaLI&%.$CѤZRAP /"₈͛xVZ'iSk2dd{І}wyx!pvtr9(J-ˍYxH,8d24 l6C4phTgӆ]] SKZbe*|@ 0 2(K N;Ej}}t/X VAw32 wP( >h,wzh5O#ቌa3l౱8k6UU!IRdrr24[LVm6ݤe>l\c>QhKQ0>>~9χ:E-J"tݛlT1HKE >$zRx<*`4*@PǯFwڂɊPB*KJ?`{aTӠf J r[#MCTRdY51SG5~YS|.gxo`hۢH~d2 Z1r3i2'R(>5oRjX$!M=8tv#oOdWa0ƘeZP"RTk1k-ZR8u !N,{zqqA$dYRtfffp=`nn}߭뜜jg}}=>>{WBxGGGq{{!ePggg{EkdE_4m?C& IENDB`PKQZb3#3'(!crystal-roster/online.dimming.pngUT yhCyhCUxUuXa7|4(iD$DzC I隀tw3$4H3Hw>c?qGjk*%f பK]aSPcZ]%Thcw*&^V??2D }l/FBkܱbO}0W30X顫E>G' .u󧺣1h&X1ڧŘgK }@=2Seig^-Gȑ#9:D!~sNyީv}VMүёh7tE99 u STS(jŅP$x>x#tL1w=>T gl,"ޤ\~ĘxjsVS--.U8|]|ܐ}Oh8a>Bg`[Ѻ2s\+^ǯ$AMyI`Br-p\ΡHHp[ϙ_)=fVj*]8+qiX;Qsr*:Pޞŷβ! I dj1ֈbliA5%55l"'BjssB;yd@'DmY~[;4491.q癃%=O1`m?gp$*J.lĜY-L4g 3Mrkx58$N (| wLY,##X Te6L Lb$pI ~Gn!2oތ𭦼S?#X¼X"c 0qa4|+ut]P[|W!GUԌv6kG2UM5{F8f ;˙ſro˳}dHA&¯l,+q{ÔveqS-^ZsDҖOr@?dw 'I{ˠWZ`HUpn.ꤶ6+dDG@AWw\<9IkJtBSBkI{4%{s'ts8>"כakCRWKͪRp) }gᇦ-䞭zA' Plrwu2{U=0=mNX~ֿۚȬ֘h I|4j.axyK˱2yGQ@DS ڿv+Go[*Ev3/7,z?%-?a,Dz{Po'W_%6ˋÿszRZM9. z]q| *<(|sj[Z3@j۽7pfggVk2DE?% k}v%1˩2+man$bOƑP`x5ȥLȘ*E(fw}*.K$+&hQ[k騣 vHdqRff|Ѡ&ugmfmo@LggBRF &^y<Ύq*NEZbZv΁Iwt>ˬ݄17_E*S>NlKx=r >b]3<;͞u$ 5loq=(]OEzՙ\>*׊C>--6syĊF8_RR:-4޵wt g sU,UO~:GGmG,&b]1[fsFM,6<;>{#P% >"|UReWSS#"L`"=2'Ļi2 {ڴw@wU9HKj52ۙ_c2<^UEȗ@r:'?B"qjǚR0G>p77~n/!sɻq~q]b)3M۸-rŏDk{|igr<,2߉fpӧL}IFHSM=Rѝr_GM?ʺCawP"oeC 7^dܸN [wC?DSUUUWWǍWSو<|}fk3)*R@2K͉^hAhm`|ŷkϰ >ӥ:JplHzI{^Uqj0\^6p $&A[" if?R/ЛiyV l7œSKU"ڡBcbb{! ۓrX i \h<#]W zi:2x )A޸p}ucUf`GT&)AB -91$OEh$ax{wC㋞+Se4Tiikݨ`˷W]7YSGih+[TM]KT|/f ()WWG ]t vfi\#aǞ#"x¾KD(sWlS\}i}˗@S@jXͣ6*Ѐ<7}MhNɣ?;o|@nc e˱zEtH\B6ã&!ݰN{GqЧ˱EEG+w)'"8.'JH@aMi׌51JCG ez~.k Y_r{nMI }F;r AP+,®cUէOn ^F,ax?~K1|E6L .|qZ)—R't>Tvhm%Ň!G7w*pD8DxK,>cà R+.V4>n[( <)AƂQB YӞBI§bpqqqeӶw):ؓq)*),Q;xTdBA\N1aɓKjA^uO䟽Wa8.FDtO*/4] 1p$~Og7\hth r[6טpA;bUt6u*ZA!*@,#$O!UI ӵ? ̠5|M#G_+Cτ d>7KLAݎTLzTέ*_M#GA:Ԑ5{!sA/# %x-ȧ#J*ΊN'&'w_eu٤NZȱ׃^4/08+Eu@.۫ŷ ւǏ(Aߊ7e m{# 4}ؘ> \kZ{0 Krq1C tκ=so4Oi@hdz(olMN1 zpy˒ްvtC&rl2AX! 8z|˽oAE~>$}@p`-b3#X@ʓxIHJ*nξM 'Dq'H2ę%077 B3//~PhT!8}b9)K`/_p1 RY ^A,amMrv~%IN˙ ||3-]"SopYiZu巋2^!`cg#$lz{IIAlX}Ɍ۠w)gt/.% lkNN(tZ,hF hZ\c{z.om] Xϡs c]ـvUy 4,׍i鮼((ff.@^on6g,iRq%sIEKS;TF0Ec&c7 :3 .2Ju-<ӧʛf& ]?kh{u V%žTH2;:K”_6{w9H1k5V;HkAd$&~Uv>;LdvB.Z/qr&"MR8o&3t7z̓⊊8{?SsD!:ѓ64VUI+#DAR B*]n{ ]]+HS- \ ʺ,Y:1j?\t YXDؙ{'OZgrGI80q 8{_:Ԙ3L!̗;.Q|0< }ui$:7Yܼ]$(1P&.dlHRrb7a;cikx±l{cXsmJ4C uK OXuqi6/?R7NkZh,/! Wtǎ;/E=h}'5bS4xL_D7#WTLk'U:<mNcT:.70-%-XTCuY@1ǃ~S)oN5'j‘,T0ŎPoD__q2]Vu$y0utؖ|k^ef\ꏾ'PetJAGwpA ^jQٌ(zyz`Gr %]y7כ*X3a:bLwpOi|Z{&wFL10.wN-Z[ +@&O  ?&F H;HN FmK-7BHH5.Jܠ~jڮ FIDuz %*]쎎L@V^_L+nݖmJ)2ѱA 5X}f<,3kPO&d'? :ͷ#Ug_3ryrꃈE C^\hy$kJd}@?|ZHXV߱@߭]pT\7Md6_Ҋ8~bٻM7{T1|z }xYi<\aMj$i[r̷c!G4ح\ƪg{#*/yeb ٷ@t!$Db? r}UgUw17p 7م?eo"﮴Rd̂ݒ+6Sw,/e/qۓ>=#6ofv<ѝb3 5 aX͜Uf6]8Dk }<|-?̂HHMn{CO/a`$+!cFGS wm]-̷-8UF;?J $nMoIVΏl.QVK^W(=U'P[:2RI.FG l6SI,wD[0t80H](8vj-(fsj"4-B\].NBC=cƕVK|lSqKK-"+Jf"^"L( t3B*oаEjm?gh5x߄ ucd.s%M 6!^p,蚳:`S7vRWK#u&t}%L`ְcw4kƁwJ=֔x+$SMooYPU(̎6މhnig~v%~;pxQΓ]9,p2RZ }k9O@:u5̩ݺɝPSJ 髡V^S4m,g|0ǖU)rl;u_毞Q _s~eCF e vǶ[sX 6y?R`=l6E-E9HrK^ RhB/h;4FIg^RZXD=g߰?8--.N}~>s}؟d2#}y`a ]HL{OI-vF^u I1=l5ST]&zfz9w2~Є^hΐ캎FR(工%Q}6+(*#",_ILJZ2tIv@i֪<2q=d2s(Fz68=mhg' ~74ăKCD߆9뜬pP LM;5'p!/gI*]>vYz)қ] T{&PLF+1zv@[\?A.o5݄w\,r[s.=G{%z似~zcda(]rpgr.x=gj*KJW秧.a.l[}جl7sOmE3PiՅ5W&ff>_Sћgp@P&`36,o.:),\R]hz&*e8noJP?Nc$q?v0fCuKZԫ.CY Iz[4q[s/͜]*`cWR\ ]xhNz#ɕP Y%3r%B*r#2Hp!Hm-d/ck䉼Rݏ\7YfQ*x-uƕ검?*q~ )wT=~tq#Gۨ tbBnXj*3!Ѭuͅz/ Dzӧ|N}m*G Iy>G2x_&ϥƻ9!DȺI_Iwҳ%Qx T2Oʖؖʮc0WY~pڅ3 |agou,>u#l}e;mzkyiy+ w SkY,Ev/䞗[sGe8zhS\pߩ^<0Ѳ?je߾*@s/'h4íI<5 N%~"o7=[M|nz{\7{L+Vse83PT//^!(/d"K 0M$ݱ BUE͗PK Pb3kcrystal-roster/online.pngUT hCxhCUxPNG  IHDRabKGD pHYs  ~tIME#$釉JIDATxuOQPRZ" JQѨݹs!хl4cB/`E .nܘ+!1Q-?h X"P`0sQ`'9;{ )%daU6\z6GؾПyU/U|C 4!Xоc1{^ _yerPvJuoڷ@j=l:>͕΄8tbJ[q jZXXrs+9#dLRbLD讫QeEa &Cqų &:8EhIa&,J$$=P2}=I*WuzOu=Ơ3 ywu;[ ٽ_;7^&7#h5-=9PvZh4Eeh=vR'/467Իe%,}s5G##ʝ&On*/}ŀBx#Mar wjNRʋGnl.u&MhL|_˪Ϸu3ܼ| opKzzD2x\2ǎ;C0Io"fcA!$29)27'21!w7D]1EEfgEә; pN$vM$SP~'DQqsϲO Rڱ7jk$À7oؚBS2Ƀw[[p@O!\_ϝJZl6MC3M%!u*?[t}gt^d>ɵnlmOښ4tӴ`IՑ#qbmwN Be%TWCE(j\_Bb/@Fik a;!z<,-,l^v[(A\WtfǼ--!Npa޻mcqq;*+!C{}QU_NSB!mn>ݾcnh e;^ >8/%/}Ve juUkwEm.g[)8pjkIb˗NucyRhdBb@!y*յ7 &n1MʒthS ) B .4KHLHnD @d;O=P X4 lblԆ -[ 80螅_=#a},m0nRtia˲8ưB v9sN2UV\au34\cf8kq`ތ"_nx.˿z><^eQm=Ǧ ޯ4ޡ@7 'XhOW?uN MPK PZb3'~]]crystal-roster/xa.pngUT xhCxhCUxPNG  IHDRabKGDC pHYs  ~IDATxeKL\ey]2PcC D[BjJ]h2Ѩ .uIc n j3Z*RH uJ20O{wuA)=-T xw!G vrp׻|7QiZk03wah=gVX'u90:7 [wμ£w8^zi0t6OmRcמ\])W}'6hJu:Eo"G>cj u:f 'o,K:f X9/,Ia1`fkE[FSeϞpk: @uv'?:[-+) LNX`n|z%ϟw9{*JR~&C_ˣ\z$Κ5yS^iL<\))J!E<5tcMdU2AIXT mdѤ={j s~|lioo_2M3 ta555͎I4qiiiy4l)[4M$ro}ERX$ "u @&NlkYV]*bjj뺿ކn# @IMȎ'L3ܓpE<pp?ik~byhHJK%ݻ;z5t:pJU_EvEÈśRDDDqyx\:{VFFFdrrR" ȗTmuvwtʫW 88j.WՃMHP 4up5&VSUmHkx>/d=yoR 溺./Û7TC! J|xܜ~ U4 PYzcqSQ(*qu]"}56NlŶ:;hhn{w;H " WVTڴ|>EsfXMB8333L&PXCؕJ;dSDӿ.'`'px1<칠IENDB`PK Xb3eecrystal-aim/away.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxڕmhu9le\s0˘04dB A¤MZFHٲ#1M26lَeڪ휝sՇpFR׷o3b|NQO(`UB[=7xHvъK@5ܤ>UAdoyGڿ;$7 H`?I4Hz >HKr?[mFշDgSf_oL&EX͗cV3yҽ@f gƦjZ=Myy1]8 6v8PMae23M\/,i?ԩpFƕu}6 jv*'^ 0L$`ك5ydpX+aBe ] ~ 0+v4_9{U֪U{MZ3`|<'SWqJfW󇙌jv>&G*<U! ף|~c֭ǃzk4Cٓ_VL:)ܭ2ޫW~YS=fmjQVdMQ`tXݻ^ V:ڈ?Jw}ox~ZU;|s<`o| PwAKgUatt>S̄B"h,_:sD@$[b`7pLIENDB`PK Xb3]tJllcrystal-aim/chatty.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxڕ[luvm(9%S$K4P؅Ĉxw&hD 7,@O.$0Cd2vc[׵ra&$7y~<`a~S `CA-3; G^8y~؀YEO9=-blZu&kxi@ ZV{ ǢzK8*L=Sb%%:= 7}su<&dn\ߦ.0ZW&Ķ.EҳRͭn4ͳ{pOR%]R.!fidOy;$D|wh3 //⻼EU|͚Nkxy#y#^k٧0t nZB]?4?4Lqr:z i}wۆIFfXa6}W;_m]Q0~,.;j SɿٔFLnјW^Jzk"Gښum^ gՅ럎HEmh,~^nL^d3@@ %KM~k'~OPaVPǡGI٣k"^n5¿P&yK_y~{ dCקS?(y}+k33 IɁo@.?`ȼcaO8U(ό.@7p.sC5IENDB`PK Xb3"Ogcrystal-aim/dnd.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~eIDATxڕ[H߷oݼ, D4/!FP`%SB($ޢzB=DSY`7P $(RK*5)2mh؁pdY_Yw{UK y^97Ҧaђr{+IK$mH"'i,} `|`aPcy#x-hU;bʳTSA9* Ur7}ݪlqkV鈲˅'u @.P)*/M%RU%b6X,k4J*O_;rݨ$_ wigcSgTtB[$$HDC!:/Yl7ƣnN (#OIc;LOX(9j7|a=@-0i󿡨 6&QMq\ Tx٩4ZZdME B pQLl6M=典8W@{m}ZE?c|ҷ 3޴d9?%k+X f3?crystal-aim/icondef.xml.inUT }hCUhCUxAO0)ꩺdTo9EM]ڂP޺_e|ک:itA&L-N15l+#ɞ -Wwkc {f!K r9 ,{Ϟ ,sj½s8 ]&+h2Fj%T*--#5Ȅhl6WY"6X#)`A'R^:xu38XUOY/D*yjr'78]-oOƦ-R['PK Xb3%ԡcccrystal-aim/invisible.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxڕOHdόo^:#FApé0PаBAe auHv``HIk&CP:,<qtG#}vGNK "g'ykKГW@獏O" ̋o~*Kg0bX@lww2;r 4`SR)999m,KeyyY]N O ٳ҆yjjJJ%,K lnnJX|>/DB ø}nPzzzf3̫{{{:i*e1<<>ȗlmmNߧ hoo'|WVK?Slۦi&''QUE&&&;Pa[(J+++y8Dgg'p]immjoRn "}}} tx<1iB`88 zFT*l ~TZZ ujJ\\.cڕW>}BBi QzNXĶm\ץ[@7y7m=;nI \.w/L^z <.Vjz%/8ko1>>oG@l/\W<*]ۥIENDB`PK Xb3WНxxcrystal-aim/noauth.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGDC pHYs  ~IDATxڕ]h[󓟓jkMιv˶ЭX`L ^x'^wE--$irbڒ=م#D ;OTHngDHo{qƄli4(wt528UY{:¾ⲕ]gB,* N*uڿbbxyP:ʬ#olɬ-lk3mX^^NU.i}7ûNjywjU X%S̟+FigL @Tuv˳@F_㧆#b)sFm\nsڲdH$K$W"Dɫv]ћ9yGKK|/߮l9A#\&''l6{61&Mf8 ?o A\'@Ov/s2XIENDB`PK Xb3&ucrystal-aim/offline.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~.IDATxڅAHa1Wj6uEcU$jav :,ֱ :.BA7!P Ck(,2 .l32%d5w|<}|Fhmm]zD|ԔL$rzzZB2L4|= ø\&;;;{بVP Vrml6 v:w[Ugn ?>>qrr򲪪𫥥嵦io:oqqhhh(733d2D"ΒL&J)͎KR!ׇB!@S Q*'J{R,~q2ۋ`sssV=R!]]]/V8Xu6BX'IQ[XE]ױmt:0Ki2::NSJ=b˲p-V*{Bᑢ((ccc7|cc#*Ty%!ēnEQkڇ3pX*W@}/?I~W:IENDB`PK VNb3Kcrystal-aim/online.pngUT }hCUhCUxPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FVIDATxb?. * lxUm_Hl5>eۓ'Ě{D@HL-@ DC1glp{AJAZ+0D@@|  \d ?M\?ANB>'؍M33cp_JNS@(ix{ڽ{_R ( 42%0p/dO|?ۊgs|?|`J?N (FLaa3[g ğ)wjBv#qoSTUd r`«55$2ZHq;(#li5IENDB`PK Xb3̟GhZZcrystal-aim/xa.pngUT UhCUhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  ~IDATxڕOhg3;3fj4kkn"Ak+&*Xѓ'E=P)mCC#T6)J$(&m.DM3|=ۂszQa_cԋg\Jwվ!_mPѺ~] ϿUUvS)c XO;WUA|).+ȅ> S̙+T,1M+=*+SLq ϭinޱOW.^`829ߓV7{ Y_AFɽ@0MQRV;rdeC+u=j_U;V- +((۰k-0RJB083YcM@W]1H)})%V|i_ly @+mMr.$I4m:[!X!JJBjv9N {o'[2 crystal-aim/icondef.xml.inUT}hCUxPK Xb3%ԡcc 7crystal-aim/invisible.pngUTUhCUxPK Xb3WНxx crystal-aim/noauth.pngUTUhCUxPK Xb3&u crystal-aim/offline.pngUTUhCUxPK VNb3K 큻crystal-aim/online.pngUT}hCUxPK Xb3̟GhZZ crystal-aim/xa.pngUTUhCUxPK $psi-0.14/iconsets/roster/crystal-gadu.jisp0000644000175000017500000002625111305557613017002 0ustar janjanPK hZ8 crystal-gadu/UT  H) HUxPK :Qb3r//crystal-gadu/MakefileUT `hCWhCUxinclude ../Makefile.crystal all: $(ALL_ICONS) PK Xb3O7kcrystal-gadu/ask.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGDC pHYs  d_$IDATxuK ?X8l-I4eiQ0 ^zCdnzYn任Ӫj /7*fff~}QUU{k0RZd RPH#[Ӣ8(:ӧ_EZ?~u ?ldͶ>gagH\#P(4 .glY«Www|4MX.c&S,KKKĢ8ǰW.G( !"T*hjjFGG_{߂"ˈd_@1ME$Yڱmai񏶶ht,EF{{ah!Vި*RmʧOYzz/"+G%~yq HJ\?zqYU'. BK^wׯ2a?SeœIENDB`PK Xb3+crystal-gadu/away.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  d_IDATxu_lSu?mv+E 0B=1D4̇a,J2y$˦(/h#dMl.3-k!-]׻v?L19O|=ߓ 3{|B9CڳԉhݍQ5P5/9yI) ;V7/^߷(79XKO%:TJ:9-ڵm"݁W(v/4IfJ7Y4i%٨ xaxS~IVJEf/i2}D0~+EFwDDlmhfvlGRl&H^+G_Qyjo8⾄T:NDy9pI-в*_8d~opqI_܄aF~@p P|{F\_Q ˸V&s[E$.ͫ{[VHFh*ymyuԚc箆oex@wfG-qۣpJy޻ոanEv6)>yXI#B#.[{yxl0'EDX|q>a<'ĔKq)DyAr=?rI [N=˝-fpLL8䃇~Jgde+i$ x1B umyLYk22v[,I,6 e8N ّ87Nڃ-t8j *sD#JpLIENDB`PK Xb3lcrystal-gadu/chatty.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  d_IDATxu;l[u:4n6+(uT * ^b bd'j(q%igz;:~S;&ğEd{qsrKqEϤ㙖ϽѴi{5k3CRFZ^~nMׄ^,űc.X㢷?P#涨 ~HʰIt,v0A:#T (ycZ6u 8%c)HSf~883RGkr9@ o[&BO_e`?`8每OH"mQ&oӦZȍ ?[65%{*^Ku?#\ GU վH3OĐpЎ-Q6LdSQ 舛ܹ k!GP",=X^aj9;|TG~Fv\yk{M $|,?EIOycxU^DRA$5mR(P>>`6gompGn5&IENDB`PK Xb3az~~crystal-gadu/dnd.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  d_IDATxu_h[u?ۛ4i䦣&kYWeUòa) 23Ae/ {T1(8DC[,uKlIݟۥMrso!޽h=Vp<-GE&7KzG[z>-pxanAٗPuyeQ FD|~)?t!\j@u #MmSm{ҽTV5f, yDW (_bS6T`#ƊTʅz.6St>]eZ@T Կ=3}#GvO 7В P ;9*=}dc}]JT0l'xmTYy|>(=GD&&DimD6X>.COG9FFrO#1: p ] "Mm4<^u"QC ~3+/OC ]]kW"3L|U9m0M_وus׽W+oIvUU,/C,2 alPV_&֍DR]EBW.V-H$ .[W7W&bx=+O 00hB( Y~?E9R<\``KsL>'>զ=Ȥz6mL$:-yp=1o=D؈5IENDB`PKdZ8K s$crystal-gadu/icondef.xmlUT  H HUxn0Ư)NJMB+uE0T.Mr ^Ab;q(Tp8|߱,`Js)΅qE*3.]1黟T gah[`%j +t[]> u܃FXډSa'?ІV%@?F@c2%mo8h=~|QGxi&xxaÎw/yT! ]v:WŅ۹ ERz:1Ͼk+7E'|YBSKcVdKeѮ[E.i,kT.scV0Lu]0Ls`"X /ش@XR!T9!jMsUu9-x C"y/l픚@ aLMݠs~m._{q~ЍAqIg?#ۮ5$_27ݾ0lm6@ Nd'Q_ eԶ]/;aMy4-0RcG۰56yT$aGg"kR'hy.V\sJ|<*͙irIT,0T;scыjr׏G5QdJI ߮O=yPK6Qb3Hd*Acrystal-gadu/icondef.xml.inUT WhCWhCUxN0gf2DJ  A `$V7nIߞs"TWYSS 9uNo(]ZMA?.+kX _p-hՓy\sֿ H >Hsϲy~e(cцeWc&`;zr$CS+h聖eF7Rg]ϘT(R Voh)֜E&D}d>-)G`F :ZשtDFK}N) hU>e ?qaZpF K.ۍN۔!R[,?_3sJ Ho XPK Xb3nήcrystal-gadu/invisible.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  d_IDATxu_HdwgqFD츊#!]Y-a^'zXz2#!--OnKάڨ8Cs{g9=,c;<||nv?lU-4M*,Y$;RѪXw_-5Coćm%̓x8+hX=ب4ն|3ֆx'Nsttm[\c{K(Y6vXyr~~^JJ"ڒp8,JcyM~;곳b۶R)I$+dR$K8͛>-w\3~gOfYNOOQU?v/c ʙYr6eh4g``=GEɦۋ.q0 :r4KKKP &E5J!"b18PEQX__@ ~2wOUAD'B!,a!wHrrtvvrrra466'Yv_4MRKK gggn|;]_ݾv&<Ѫʿx`0w/; p=1g{GIENDB`PK Xb3$crystal-gadu/noauth.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGDC pHYs  d_IIDATxu_L[n[ J]]% Ȅbt33ݛ`LK|1>"0ldy1OX$L,..~ `9}o9Ͻ"J%,9U4ŊEI$0kcLWQ5b\|WVv>;cȓzlս,BV%F+QU@/} 彧_LvWڜ{?˯{RɝlZ{lk%,LM~vUU4M[ƝKx׉ޡp; (:˵\,y:^VoJ?wg?|3gD"_6y5AEQl.@KB䜕.hn@` O͑>qqS9IENDB`PK Xb3O7 44crystal-gadu/offline.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  d_IDATxuJ#Q?@j,, HE',FZ*l(H,BT2sf$i].ߙ?q~~"Vwww^j...AD0탃k.//--"4EתjԿIܪjID\cLjIU-UEUKb@|||(,Ucj OR~jiyyr`0>yvP_ DrLO' Cʏ̸UI033Obee x||$ET c=eg1~8v,..l0 1Ɛ$dȈHUDv$}677#JF!IG~Lor_bq*tWnnn}7WU qU `wwwd2:QtPU &N۳Evd[K6]0EED8MckDqkG@uT@sbc7よTjٙ'iq\qր 0a0b{{{ ɪ8ߺEvZ9IENDB`PK 6Qb3| crystal-gadu/online.pngUT WhCXhCUxPNG  IHDRa pHYs  d_gAMA|Q cHRMz%u0`:o_F&IDATxb`_Y3jU  l;O(·[@,`V gG5 ?~927b_!~}ɠW 0c` lN ҡ Yz30|xv> 7߿ :#i3k 5?Ƈ@~9ïG~^{C>>5>ρW ?1pZ0|oG6bJ51@3g'y^`C>|0udgPaxa0G} ?~:C݁Mlo< ͵GE4sfW? 8@!?A Ãy 1)RF / tz `Çg$O>ex*x(7b?'3]w?/Xue/_7{Z 2OHƯ} ~2```a`~&?gpa×`@ S(@LX8DÇ; /R6pr ) PJa?:~y=Ph`A) '$zQ5Pg>0xHlP"RAĈ+ C@ 0\wqIENDB`PK Xb3ʅcrystal-gadu/xa.pngUT XhCXhCUxPNG  IHDRagAMA|Q cHRMz%u0`:o_FbKGD pHYs  d_(IDATxu_h[u?4MzmM뺬QcS )20EŗAA_|QPdঠCt:vMqi5Mw˽>ɝs{8=nb{nqJnV5P'H6'SX6X6S]" j&ʙ}WB~7͖cƐ@5IPMoz)]#6*H'cil JAk: *l]OF m'Q濹}~d7B (+V@^v2} d?n :w;y^׃Xmз7H+0 h:~pH| m OA=[C_PW/anM>щ<[(xDvd]t FcO%'|:t _нw$69>P@?m3z^u/;oM_sFIENDB`PK hZ8 Acrystal-gadu/UT HUxPK :Qb3r// @crystal-gadu/MakefileUT`hCUxPK Xb3O7k crystal-gadu/ask.pngUTXhCUxPK Xb3+ crystal-gadu/away.pngUTXhCUxPK Xb3l crystal-gadu/chatty.pngUTXhCUxPK Xb3az~~ crystal-gadu/dnd.pngUTXhCUxPKdZ8K s$ ~crystal-gadu/icondef.xmlUT HUxPK6Qb3Hd*A <crystal-gadu/icondef.xml.inUTWhCUxPK Xb3nή crystal-gadu/invisible.pngUTXhCUxPK Xb3$ crystal-gadu/noauth.pngUTXhCUxPK Xb3O7 44 crystal-gadu/offline.pngUTXhCUxPK 6Qb3|  t crystal-gadu/online.pngUTWhCUxPK Xb3ʅ n$crystal-gadu/xa.pngUTXhCUxPK x(psi-0.14/iconsets/roster/stellar-1.jisp0000644000175000017500000002362511305557613016211 0ustar janjanPK ұ'4 stellar-1/UT K=CfGUxPK3=stellar-1/ask.pngUT }CfGUx sb``p  $?OR B xn {+%..3V %y0{Oy8XtA%reDCf~ܺ+%T|5d~hƝ(gM)9+IJJ_Mww`յ|NzV@< m:y4 Upd{XWFS$h k'GY $n}Pǚyt:&PK 3 Wstellar-1/away.pngUT }CfGUxPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8 0D;3{t(FHE8Jr~q-DT"=ZG(]/bNVC'( 8RdpӺ̮o;YEt4 Il~  7LIENDB`PK 3[ystellar-1/chat.pngUT }CfGUxPNG  IHDR"gAMA7tEXtSoftwareAdobe ImageReadyqe<0PLTEŻsss$̌' X6tRNS#]IDATH͖ے Dh HݭZB4&걩sqI~ zqđwp=xoizޯ@o";?O;+#ȷ_/n >˟a(Sĕ.5 ɽ)!qS)5`Fhk(-;sB˧\l]5!}H״*pĻݹb<ǐrq88MeH 9wPLvM]q|Hz҉6N8|K״*Mp6j+]tt.^syJ4*Zqr=.f[KzKDSkk*&X뀫53|$-͈\#Nwwok-|-)D"pFtTp솋iV&ojx$"{Ac㵋yA?5?(`A+og]oMU,W9U̐rs\zk0Z gKcIENDB`PK 3b 6stellar-1/connect.pngUT }CfGUxPNG  IHDR`gAMA a pHYs  d_tIME UbKGDIDATh͍0N:&  88d`ϳ@s~8,; :P4Rcq?Pkym9f>n0 /qߣr<_˓ry꿖G6ciY8k  %iIA x !k|GN&yn~-/y|I{'$N$n8tO/\\ק^Yyɿ ^O x[DILj; 0L_Hѧ?a$DR۶/v|jSα_3__X;IENDB`PK 3lstellar-1/dnd.pngUT }CfGUxPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˭ )7qZIKBK#iM&ZK!Gf^&FՕM {@ٖոLYБõAOBT$+4(1&ziLqhy|24ĩXZql0ZYzk^|a+~|ane oڜ 6MFHp$Yz#.d-2_<]\9%4PK 3lstellar-1/file.pngUT }CfGUxPNG  IHDR`*tEXtCreation Times 9 maj 2004 19:32:34 +0100*z'tIME %2S|C pHYsnu>gAMA aIDATx1n0 E%GZcӱ@!zȰdEjs "}_ 8kU@o4.SҼ'GҼٟ~IUg.r)C&K sזCNIRmH 7G&_8yTCc%1.Pyn l/{ DNuSVm5~\QVunwM$YuGEM@+P8,~X Az f\(Pq6CtDߍV T9x1:` t}DH#/WjpxA}Rd@ W@!N`f26.C-*H(/ dʞ 5QnHyKGC>=I3=0"R~cA?fSxE stellar-1/icondef.xmlUT fGfGUxVM0=g{r{ ؕqhJ 0 m66$Qzyx2JzˆUFoYB ( TUF&EUe~J%8Tq oȳ&?4( Pq"IvK簐& a6IE(Ka@Kε㸵xYž -x\ ɱFnQ>tͿq>aĝlȨ\7^aGC()pvIr8}:yB[/&y}6oGWQD~j#}㮳cH\X{)hxXq?`z2Wb~#f0r)Y*#l F,}b^⺙|po]7R2Zf37S:Fb0F)֣p0W;ݾarS;K\k@C 3e*%6W_3p,S{@^?,sC'\j# ]&Cٺ,%+[P^PK34qstellar-1/invisible.pngUT }CfGUx sb``p  $?OR B xn {+eAn*q~[ \wdHcE҉98b/[OϚ=Ijۼ SgLWkTa j:;6[w}fbށ Շx~d_)VyhCH؉]w%='kފ {ĝ9OW?uN MPK 3d..stellar-1/message.pngUT }CfGUxPNG  IHDRgAMA a pHYs  ~tIME qbKGDIDATh[0 DUeO$B@{ENi۶tvy#wByE@I~/Nܡ|tSͷˋlw˃G Y0>#›>[S 3ǒ8+g/0oVVD/L# ?u+gW\`>#1Hx6rl ׾XIENDB`PK3O'stellar-1/noauth.pngUT }CfGUx sb``p  $?OR,鎾 $ B xn {+%NNVE{ؒ]'Ez8X^;y7|:TY Sx$8b+?O8p6ǺFe6t_5&GL6Y/]]3Mq98E@S_w9|q(8ݣx:K^L5g[u_}2o ":&PK3I<stellar-1/offline.pngUT }CfGUx sb``p  $2X}֟0gz KF秕'28'*x&&TL*tq јwPvWoas|D# !/<5w>YRp}'k/:V޸ƦICsX#æI,Gf?XjNeSBPK3wstellar-1/online.pngUT }CfGUx sb``p  $?OR,鎾 Ov%K\#JJRSRQ#\ E?Wcb>,)/OW?uN MPK3)-stellar-1/perr.pngUT }CfGUx sb``p  $?OR,鎾 $ B xn {+%NNV5Kؒ]'EVy8XN=Wxeg=y#O'Vb:dr&|,sW:ɤ۸1L\.塯]?WΞòb?Ipgcf4V9tyJb8z ^ 5XO')'4^njr~kT^ pzlPVFFXtmٶ'G[M'8WԝttXKx| *mx%ƭ]< Gz!z]8n_._ݻ}7X*2!H 2W^LF(N+;yݙw_x؟ ??IENDB`PK3`stellar-1/xa.pngUT }CfGUx sb``p  $2X}֟0gz KF秕'28'*x&&TL*tq јwP^U8r,K>-2yS4 6>W!0Uz=&_U"\^vmNIaT4atsYPK ұ'4 Astellar-1/UTK=CUxPK3= =stellar-1/ask.pngUT}CUxPK 3 W |stellar-1/away.pngUT}CUxPK 3[y stellar-1/chat.pngUT}CUxPK 3b 6 stellar-1/connect.pngUT}CUxPK 3l stellar-1/dnd.pngUT}CUxPK3  stellar-1/ffc.pngUT}CUxPK 3l % stellar-1/file.pngUT}CUxPK3dCb stellar-1/groupclose.pngUT}CUxPK3hM stellar-1/groupempty.pngUT}CUxPK3 stellar-1/groupopen.pngUT}CUxPK3#/ stellar-1/headline.pngUT}CUxPK*PV7q>E  stellar-1/icondef.xmlUTfGUxPK34q hstellar-1/invisible.pngUT}CUxPK 3d.. stellar-1/message.pngUT}CUxPK3O' stellar-1/noauth.pngUT}CUxPK3I< estellar-1/offline.pngUT}CUxPK3w wstellar-1/online.pngUT}CUxPK3)- stellar-1/perr.pngUT}CUxPK 3l@ stellar-1/system.pngUT}CUxPK3`  stellar-1/xa.pngUT}CUxPKp!psi-0.14/iconsets/emoticons/0000755000175000017500000000000011305557613014170 5ustar janjanpsi-0.14/iconsets/emoticons/default/0000755000175000017500000000000011305557613015614 5ustar janjanpsi-0.14/iconsets/emoticons/default/heart.png0000644000175000017500000000116311305557613017426 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8͓ 0EԈ؂XA *{"N!Fi(Ld9NXt- QyĿʒs_ր0M@UA]k4Wkcfq{u}ľ?sݬ{жv:U_Lvm`.=oD}IENDB`psi-0.14/iconsets/emoticons/default/boy.png0000644000175000017500000000124611305557613017116 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8˕0 E=K0jF"!(sҧPm B'=v"j3kV'@!2vH :΅1@UDl.0?D. @aow_mQ؛IENDB`psi-0.14/iconsets/emoticons/default/mail.png0000644000175000017500000000160311305557613017244 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8k@LέnX`bq T5Bsp5#T01ARQH剉'*N|{tmǘ=x8wXQbH ؘ!vc$t>a5T^8\z!ռB> $ބ=} 0{au:&YZit{]X !5E@)uxkaRs{~ҁՈ|w|/]yShQ~ v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8SB! &,ԎD ,`o˃sbfϑS6= =eIm ܥ!bq:.MmׂdV-|s%Ă Ѓc0`VՊk.iV%P tdf: w{Z\_ʹZJVy-kģ@l;/Xg_Zv !חd?gze]AIENDB`psi-0.14/iconsets/emoticons/default/icondef.xml0000644000175000017500000001051211305557613017744 0ustar janjan Stellar (default) 1.0 Default Psi 0.9.3 iconset 2003-07-08 http://psi.affinix.com Jason Kim Michail Pishchagin (icondef.xml) :-) :) smile.png ;-) ;) wink.png :-P :-p :P :p tongue.png :-D :-d :D :d :-> :> biggrin.png :-( :( unhappy.png :'-( :'( ;-( ;( cry.png :-O :-o :O :o oh.png :-@ :@ angry.png :-$ :$ blush.png :-| :| stare.png :-S :-s :S :s frowning.png B-) B) (H) (h) coolglasses.png :-[ :[ bat.png (L) (l) heart.png (U) (u) brheart.png (Y) (y) yes.png (N) (n) no.png (Z) (z) boy.png (X) (x) girl.png (@) pussy.png (}) hugleft.png ({) hugright.png (6) devil.png (R) (r) rainbow.png (W) (w) brflower.png (F) (f) flower.png (P) (p) photo.png (T) (t) phone.png (*) star.png (8) music.png (I) (i) lamp.png (B) (b) beer.png (D) (d) drink.png (C) (c) coffee.png (%) cuffs.png (E) (e) mail.png (K) (k) kiss.png psi-0.14/iconsets/emoticons/default/girl.png0000644000175000017500000000126111305557613017257 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8˕R90O uIR eJ$bqb-g3j9U1D;MjD?,t_ ,dFgi,I v 12K,c2(ϒow:h]H׼hU%h8݁=zIb_uVvO-4i"dօdp ,C^mLiTָ*P&*=hrP!MdbPIENDB`psi-0.14/iconsets/emoticons/default/smile.png0000644000175000017500000000140211305557613017430 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ?IDAT8+Da_+"& !BPSRX)+);eeay뚙=M,^{9O'}~K.=b#V~k&*iˍm|Eޟ ޒ?HzWɇZ`2A!N;gGsf 4(fg`aV43F bi. ˅ A#{&6LN7Dư]m_?0CJIENDB`psi-0.14/iconsets/emoticons/default/no.png0000644000175000017500000000126111305557613016736 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8O=AA6` ^$6@#a ?K ! ŋP8+N3s;˙Y-}9p`;kaճnRi.XVt(p/:rX΀2Չ!hܯ:dr(Dmcz r>i $xUt05k'xU@D @50j`| c$ 0?4y'7+ˠɃ-*IENDB`psi-0.14/iconsets/emoticons/default/angry.png0000644000175000017500000000124711305557613017446 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8 0  RN݄"3Mhi|w#9gXk'q!u,zЁvF!?'%7~7$oެ%#WpP)IT ` $RLjN2(d֬KgpQgPsȍ. #tc7` ZGϴ@|)Xε)J/bTs.Yszs.lUΨ"y~/IeIENDB`psi-0.14/iconsets/emoticons/default/frowning.png0000644000175000017500000000166011305557613020156 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8SKA]7n `z?J~@HgvBƉܱ)ɿx/? > wQԺPhF̍wCgȧ%dx= ^A-{y/~w^ހ~*$0P"0߀>hoʩ-F)F>a S/_=|pCU[q#o8L>/ $b5!2"b"urLfGQD͈`"_ڝ{;o "Q$a_S΀__ݠZ IENDB`psi-0.14/iconsets/emoticons/default/brheart.png0000644000175000017500000000132011305557613017745 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ IDAT8͓AAEo fAǣ}Sޙ H(_IMIGMr S.w}0B$L&|Ԩj,XIENDB`psi-0.14/iconsets/emoticons/default/beer.png0000644000175000017500000000126711305557613017245 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8˅0 E+ϓIbؙ'0W'fyAYrpDP]3itt*JF^P Y h=e_ WbGNw'jb'i 8S9{_ Aщ7;)D Dwp4`@k3L$6\ ʾBΛ  wb?j ]w"Pwbr]霾( &_clfj7KX ENDB`psi-0.14/iconsets/emoticons/default/stare.png0000644000175000017500000000137611305557613017447 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ;IDAT8+Da_+(551ePHjBM,XINYYX~kf7Xܾ{{ߓm'? /䇚|[wޠ8[ٲ7Uڔ;J*J 3!S]ng4 v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8S0I\FG&? 'CHpÁ$8vpz@)TzyP1!JO } w.jTр4F-VhTSJfXr0$i͒\a0[& ."x\-(x6‰X; Π i}cx08@*A5'i?)~@3lM7_|"Ϧ#}IENDB`psi-0.14/iconsets/emoticons/default/flower.png0000644000175000017500000000125111305557613017617 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8 $w Ζ -cfl!60#ፋ} 1[;_}]e/ ӥPH KPn¢uFl}׀ܭt'&.'\p3铵v 6{t?1p王t]ծ&)A><'cmϢw`EDӏjҡ!25TAk_[d\HbH {IENDB`psi-0.14/iconsets/emoticons/default/oh.png0000644000175000017500000000141411305557613016730 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIIDAT8MAa}4D(E$X 3_`131Mhgp{G#st;oc#"DmV 7;׿VryK*H$7;jnRwJ#0jb4щ.P*xrT`pj@U=xl6j7\!T;䒢$lvͧ*6_crg~DbwNWɬOψJm2%@`̌W߂3d'r8{_/ڞ`kIENDB`psi-0.14/iconsets/emoticons/default/cry.png0000644000175000017500000000141311305557613017116 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZHIDAT8+Daϟ"Ԕ)3B("5%5YSV{ϝs8s{:8gL'ʋrK2w~* <>!o0-zytw`joN"H3.[ԻNL{){v++X gJ0av=gZJFd]6gMJ@L3_Aڌ6ĩa7Tu,+pgNi70^!eA0qPMX>pWGLf, ύJ`N BVHz)@ HOv+D_OIENDB`psi-0.14/iconsets/emoticons/default/devil.png0000644000175000017500000000125411305557613017427 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8 0@-ufgFH\E ҧK( QTp8;?8};RJm_ _x@\S?Y ME!|VжwO2]fgY9x|,e$!|,Kg$0NK@@ MP'|ĥ2p' sr]a5 ƭ} +hK_b$+&Q\3FJRqf_PڇrEF_y1oIA(c'1]KIENDB`psi-0.14/iconsets/emoticons/default/wink.png0000644000175000017500000000137611305557613017301 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ;IDAT8KQCDkIXI}Ab/}>2n!pgΙsx_ٳ_?==ݎA3+J5}'eӮ~Ӡ,0 Y{`2wsNbz5;E㜁Π9@+kڎ2e&N[M^3UK.1 h&Szxz+egMur4|MYf7=Z+X#1Ui+9FLm C3·} }rZ*ƭ}IENDB`psi-0.14/iconsets/emoticons/default/brflower.png0000644000175000017500000000127511305557613020151 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8 EIz/)oX2wY!} E_K Xlts%Bzp q}H⤓B@qF |φMbA g@"N֤s@@u\QQDKl&~8<$S8 =#uULe޾f0B󇃵W[9F૨7'~}zIENDB`psi-0.14/iconsets/emoticons/default/coffee.png0000644000175000017500000000155011305557613017552 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8K@'YpI')$8Ap.%t(puҡpnpC:d}|Cc?T!!s#Օ{x/L-A3u(&Yw7A4 HC5Dr/ѹyT h@\ Qd;h;7I:ڒ8pru ~8XY0H Թ8A5)qDc->e %% ^rj*OyEw-,QٗCZuc= 9@MlEg ȸ|#9Pqp41C4kV>&5R5'n/ S^%T77ON[}ɭogH$aϾ ~<<6L zV2Q$ ]OlIENDB`psi-0.14/iconsets/emoticons/default/pussy.png0000644000175000017500000000136111305557613017506 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ.IDAT8mq0 DՉr5*_Mf܂saX,>lBo/۶t~YY-s3zdm-AG1)?'tyX)ÒZ d0^A{P4=V6+8߯+QX 4 X) Y%b jozUMQ*#*"j M{";Xj=&Q9]{Mh@( w14 /p;)T4E@0QTE"D,8 IENDB`psi-0.14/iconsets/emoticons/default/blush.png0000644000175000017500000000122111305557613017433 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8MP \՝q2M탩--ht1:*"Q^\_|z6 gv0J(FB B v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8˥A Q*9)Eɉ J⠔&jk$&N>0v{m4~3o"?|uK5i w#U RWF@)3\OryhM27{e2{/ۡ;s vU@wɚ @wO: uN d"V _dGBS8ෞCH"֙S~HgM;'_ H^-IENDB`psi-0.14/iconsets/emoticons/default/yes.png0000644000175000017500000000126511305557613017126 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8˥; @E `!܁n@A]%FI"3pljBbf/E(i7k&?یLv;Ҁe  I eϙ(R1knUVڗx$H$L [rɜlLHcJ^SW=r?O0cBeAmXQ=cTH! _鹿1= %s!IENDB`psi-0.14/iconsets/emoticons/default/cuffs.png0000644000175000017500000000131211305557613017425 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8= @ZlO 6e* vc5/L":o$Yg|U4-7(՛`)$F1(`=ql;v}38׹>߭=@-PQ95k#DLd-H18861$bAC0 v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ*IDAT80 Elb\ -AA'`.wPc}K'qcYŴ/uK1OPZԅ;@n6@BjdW! )(璬 4N5L(@ s0u|;d-HS:x>)2Tb{$}ULts!`Fo(7 g$).${ XU9r|69፣/9og4S;K$Zte{ Qd7)׽u0"jɑ`?a}n8m΂أ IENDB`psi-0.14/iconsets/emoticons/default/coolglasses.png0000644000175000017500000000116011305557613020636 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8 @EO[Rmu OYMn !@DFqf ;CJ Q!6*ud!Zu.y!ڦ\e6 V,7DŽ1e~)#rc @:/İ *@>¿չ]?8[IENDB`psi-0.14/iconsets/emoticons/default/hugright.png0000644000175000017500000000131011305557613020136 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8˕Sɑ0 c=i"URNgN~LJ<%I t ̌}[r}-B]Sv-hp՚k N9 {me.1\Zy!:r/l\kؓ%{gi~ ՟T9)[rf]WuUސ*倗,j\=adruqL=,xN$2ʉN35?!`[Pu=IENDB`psi-0.14/iconsets/emoticons/default/rainbow.png0000644000175000017500000000150011305557613017757 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ}IDAT8StP}PPA8  BaP) ƒBA!( `P4vv`ggpOI%1o`D MS,S,H&HX^!;obVW< #;|+@}@,]FM]<'!CT}!vm5Q<{UuV2]9n@]ڊ71saH\I zߨHV^vNN2l3;h#=0 6̈Lj)va%WTc1#9|\ XPŮO½0Ote֒Aκ#$PA^_cX0~>%s ygͿ'-IENDB`psi-0.14/iconsets/emoticons/default/kiss.png0000644000175000017500000000125111305557613017272 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8c?%apӷEG0Ҡ, 6|`/ { ߄Xnfb4PU Z F2نDKc-Q] /t|o KH BllbKA=P !@FPigc&$!cY3nTwR-` _f <IENDB`psi-0.14/iconsets/emoticons/default/lamp.png0000644000175000017500000000140011305557613017246 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ=IDAT8!l1+I,yD"'II$Mbb '&&*_|q]aI =`F`Ơ`6#WP ß Q4%5 )|/:]*(d=P,;l Bx3K8yrxhzͲZz\NSuz5Od3ykVJnv۸R2<HTi}sn%J klW߼*P̹U1ĤDSY..¹񜛲5lP ur DMIENDB`psi-0.14/iconsets/emoticons/default/unhappy.png0000644000175000017500000000147111305557613020011 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZvIDAT8c?% PeLqFi/Ƿ>ZWMhΞ` _o|f0K[?[]y g4g}G6<{C7$ d0 `b06 د ?@3i} mbb>3Usۃjc"K@D qyҹZt܉jHd(<qA~W?_un`r,m/ lg{4 M >Hl l0  ]b9` gkƙv1F.-6 FL& IENDB`psi-0.14/iconsets/emoticons/default/tongue.png0000644000175000017500000000114111305557613017620 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8 Eb`  iJ@D9BW^|f$LE]! J⇥ h%J!,t#Io\A  v1ZQzPBj:2Qkc^)u `q,YX^t{k7^?b{PIENDB`psi-0.14/iconsets/emoticons/default/music.png0000644000175000017500000000143211305557613017442 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZWIDAT8˥!k@#""*NTDLh L-T,PU*1595`ɉ]kG.?e䇄gpzNT9"@FdwyO|zl O}M` ?ʷArJ@4jι1B8@ά*H)Uq#cP*JM5L̀٨0@^FiF@+q|>6Zt-exUCLٺx487x=r`zV{aw+}IENDB`psi-0.14/iconsets/emoticons/default/star.png0000644000175000017500000000131311305557613017271 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8-@FW"9WlQT AT **@ +~|Z~nMg6u\[Ȧ`9/\)Y%qE>(2>0w~εF=׌fX Ba,[撹m>ǟ^`wDaי(GΠWekC"7xสaP7DՔ_)9 .\?r? W(1ʯjeU}fϓt!c6nByIENDB`psi-0.14/iconsets/emoticons/default/photo.png0000644000175000017500000000136511305557613017460 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZ2IDAT8͓-O@EH0 lE٬!YYY@lA VbDEŊ˻lӽyI o(OM˫kzܠZ7mAyW~jM[ݻ?,'ӄ8z7N>,}H L`.l[O z}غ8apjg-UjIzj_ vÈQ6ܽ%,WJ+T49ť$>A?p6om/IENDB`psi-0.14/iconsets/emoticons/default/phone.png0000644000175000017500000000110411305557613017427 0ustar janjanPNG  IHDRa pHYs  ~-iCCPPhotoshop ICC profilexc``2ptqre``+) rwRR`?> v^~^**`d`v D20\@J.(*(%8h]^Rgd$e@좐 g ͗a_ ' v@t0l-bVep/,L(Q0TpLOJU,.I-VK/*/J,IM ! A!h@es 8|  LƄ3H00/e``3e`X?!f o³OgAMAaLA cHRMz%RX:oZIDAT8c?!?+?69P\ AeHkϰ)3'h@5 (h@.i? ,8 # ȚA4SjJ]0( p(0I.qd&γAIENDB`psi-0.14/options/0000755000175000017500000000000011305557613012034 5ustar janjanpsi-0.14/options/windows.xml0000644000175000017500000000047611305557613014257 0ustar janjan true true psi-0.14/options/default.xml0000644000175000017500000005646311305557613014220 0ustar janjan true false true true false true true true false true true -1 -1 -1 10 true true true true true true true true true true true false true false false false false true true false 100 true 32 true true false hour false false true false false 100 true false true true true true false alpha false false true status false true alpha false false true true true true true true true false false true false 64 64 150 360 0 0 0 0 0 false false true true true true
true
true true false false
580 420 truetrue false true false true false true 0 true false true false #ffffff #f0f0f0 #5a5a5a #969696 #ffffff #004bb4 #7e0000 #646464 #000000 #808080 Blue Green Orange Purple Red #0000ff #ff0000 #008000 #5297f9 #000000 #969696 false false Sans Serif,9,-1,5,50,0,0,0,0,0 Sans Serif,9,-1,5,50,0,0,0,0,0 Sans Serif,9,-1,5,50,0,0,0,0,0 Sans Serif,7,-1,5,50,0,0,0,0,0 animate forever 10000 false true true true true 25 300 -1 true true false false false sound/chat2.wav sound/ft_complete.wav sound/offline.wav sound/online.wav true sound/ft_incoming.wav sound/chat2.wav sound/chat2.wav sound/chat1.wav false sound/send.wav false sound/chat2.wav false true true false false false C:M
Ctrl+PgDown Ctrl+Tab Ctrl+PgUp Ctrl+Shift+Tab Ctrl+F Return Enter Ctrl+7 Del Ctrl+C Ctrl+M Ctrl+R F2 Ctrl+L Shift+PgUp Shift+PgDown Esc Ctrl+W Ctrl+H Ctrl+I Ctrl+Return Ctrl+Enter Alt+Return Alt+Enter Ctrl+Return Ctrl+Enter Alt+Return Alt+Enter false false false false default default default chat true no false false true false 8010 true false false 10 30 0 true true false false true false
psi-0.14/options/newprofile.xml0000644000175000017500000000244511305557613014735 0ustar janjan crystal-aim.jisp aim crystal-gadu.jisp gadugadu crystal-icq.jisp icq crystal-msn.jisp msn crystal-sms.jisp sms crystal-service.jisp transport crystal-yahoo.jisp yahoo psi-0.14/options/macosx.xml0000644000175000017500000000043711305557613014054 0ustar janjan Ctrl+Shift+H psi-0.14/sound/0000755000175000017500000000000011305557613011471 5ustar janjanpsi-0.14/sound/online.wav0000644000175000017500000015047611305557613013511 0ustar janjanRIFF6WAVEfmt DXdata      *br@Sa5 %u -w Vj~-= _DM",5?%r%~hDq?&)IOeZ[(@K$mrz@>q pI!D J7M{FZT=~7f8H& 6 ] 6~,WI;z 4GZl<{IH 9hW6c p + ^it-~G6,*^~{xtquyphP7b]dgPppL(  B  g;fK%$[TNHAxx)lV?)zo_Obg | T 0 T P CVR2UX&r> wK4tC[7?t Q . Q # o  T # q >Ul 2DWi; 8|u*,.02p( 0W}= |  F i   &2=, s8W b!_FB>V(M3lz*  u ; D  > 6PO2.*&"g7~ Q$>.}X1kJ, 2c " R I @ 6 -   @|fP;%a{;zIn&~voh`9jQ= $ W W V V V p)s5X;\~jBRFK" V I 8 - ?'rMsxk^QJD=6*x2? < E N _ <$tQ O?MR,<L]. &  y Z + a z0~o`fkpv 0p:eb^ZW:Q q  f Z  T _ M*Pveb,eJ0 b  e N 8 ! d  pqrtuvwxyuplhb]XRT, zhVE~3>JU`S P M h q & Ft}\<%NxFy@3^j lM.SW| 3  l l I u (8IZjJ* G tG{(aE?:4...//]h> * D j B  f  &.6= |6 DiNiou{ '7y / > N ] l 2 @  (3>H=erp\^<<<;;Xumn m l R 8   i   ]sYB:2A|P +Qwj\OB6 + ~ # v D  4 : 3AN\j`UKA. H9Nb}2\Z#BbzsleryY9  v ' E c  v ' & %2?LYaiqyrkd]RF:/3tkHL (?VM b w ^  u =~l[H4 F+Yw.q^J7bE M Z f >  > d GI=]-N D . 8 D  Eyk]PB4ANZg# `q0Evh8YVROL  t I a y > g ` &fD#(578: D J O U ,  Q?KXdpQ3 HrTs_"2^;"N{|n`Q >  9 d ` 0  6 d C(UK {O"wR !  , K i  ? y &\~lZ_*NTT=^B' x; T U H < 0 # P ~ )bp}{_B&3@MZje0gRpib[T_jtHH ~  x X 8Z{6Q?&(bj: ,"\4 3 u <  , Ng14lN/6\''pT8" Ub  b  l  AZto]_bdf2v]D?:61vG(~X369#0cp~Z4Le~Kh ^VX N)B\vY< HRU%+:H&0Z& 8f;>kSLn0Io)PvJb1  T b|O", x   77~Ar_L98/b7 zF J L2L@ Z u g$ex|n$|+nO\6 z.3894 ` ^r@@X@Y aZRKDJPV\@2M}Q$<lKhL/'&A\wXZ]`bnz.I O U [ | d & # ] @b9cZ .>O_____s$9ADTycy]?!0 ? N ] 8 ql:H  '  "|1spK;, R&q}FbZ,a% H  2~f8a  0 ZW+PZ} (&$!Gn$X.K#y$XR6H~yR*`q&/qWRNID* 6h!Eid Iv }OLsfRlLhr:  z e f h i j ) e  f aCX2 lq\KWW_fnv>0P  C & Vg,L\B ( aZpe:} "8Ne{-C;Z-F`zO @  > ^ ~ 1 I  E Tbp!WNE<3Z^{0AH*T|\\\[[OC7+2:AH ZR4 } H k|~ V: uxE6E@|.:EP\y@e9 kRap~|tlsz"oU&nXjl9@d;w6~! T    T=9~!bB<4}!9Rj2BHNSYp&xH/G_ w \ B ' vHJv 0 T w iP7&j&iA`>Z"yfTA.\~Nt+af5{$t8J8?FNU6r= X9`P~Ja*6B1  #/0234z^B n%I1{aG-fp.9qz+ke a r r > `n,c&P{ d0D2;[-N?_ ] $ .rk ; V r X/6Qz?[5"@S E~!V ( =  1  ' ] /Pprstv>>=<V}>"No,8`hQUsJ!<VpcD&r6 \&}@~fD!f4'1H_5" :f4 8#Q~8g!P6 k  U j  N ; (K ,=kut Jy9x ThG &  h  `L [  : s [2 >tL#mL|6/( WL5}(  ~ F   8 EFsYZ6;tIWftBTKsd dk<.gywi[M.73/+' &JmqbRC4&_DJH~|m*\e[ `WDh@f g  l  Z+Hdwph`Yw5b~ ~?r 8Xx4 0  % ~ G + w j.# -XXz66WxN#w!vj]A$au2   2 H b}R&ua5|nalv';4.' "$&(R|l N\l Y9Vr9IXhx| (9J\m+?Sgu]X@}jq72,Z^4 UD.W r(I&^.&  0 F ] s 7  / @%oH>>@LrY   g \ P E : a  M *sLnT>b"1n mO1Ix,abLt>`~mbaN(&JBd x.['`<^ KLNPQl;IXft+a8nCxJ~TIq"{.Y*29cc8+C8n:\4k?Q{  k ! | q )  o Em-\2&t_Jf5*vH3 Y O  w h X I : ] f Mr!@`+dNB2 &: 0ZWH d=@x._T&p,usrm^l9{fPD9.",6AKJHFEEEEETdtvj]P\hs%V$`c:~<.w+`.`J4Rc^1]"?H$z7gHE^.k*~V.WD z  _ t * K j/ASe_YSM^o>v$c)7w0}vY<]^ ^ , ( $ !  ^ XQHz4P]89U'-4:@k<)=Q&JX^[WR>uCLV`i=qN*]~0zFr=cD&|\;&nH!yfTARbr0cr \&c<N4'ge.f]7P#` b -RvNrK$dF) z2b T  N j H n  N4J`p#G jlQMIEAI,>oYPH?6r0JqY * I (  j Q9!a!vsLP cm"Ai8nbX,2CG rX?)tM*w^J6! [;qN J$zDh0lU>('&%$S446=c%q_eipK&|'}n$FV>\ U_jt~b-,n2iN4M h ( P x \ 8  EFb7w7d4t2fg5M tXnz1 * R y R ,  l6U\DOH>1UR6#@&ri9x"cAMRmX1,(#b&}Nb|#r#7N D0 1NldGBSi[5NH ] J Auh[z\&j.hs 6LMNPQ`fg"U<"  BP  } Z [ \ \ ] % ~ s h*j,Jg;$Jo(Tm~F@:y9v4oi"2vABCDE-~H@8Ncx[f:?d;>_E+i"T+j 4Z<^+Pt"=>>?@& NX/zY!<8tBY-X^L )\KG~ &F  T8f[,DR|h{l:eFdb^5Nh  4"Z74i~ 'Ej*_j:,~!sfY3{%x2^& > | g R < ' I=1vG Jz 8g,_ ^ n+(%X^0nKx*?81 l  L  )w]6}&WC~~d66 'a&=)L!RV.K x.62+dO.uzHp"Bn<X[> PxzN"h Gz{~@c&m_RD6\*E\r ~,?e p1`3 j p W > JlRG(Y+aBb7D@;62^\Uz"s2n6T?lc" H &  p" 88:@p,R6X e$QYaXP k'Ao1Mifc`]D+oAP#Xf<iCteVH9* lV@*")01234SrP:v0DPB.|<u\-^~e6WZ^&L2cb0`OEk&W*h 2 X ~ [ 6  FyP&oIw2 ^~L'$] c@'Hjnh h!}`CV)o.<JWe^WPI:* |LpU;oR4pT3o> Y:Z.-,,+^@5 A N Z f 3 6o ch)iB)^9]o833 *]`|.)01I|g@2t|}~-,r4 $HkA}(~b5|>s 8e "9?EKQA2"$6GYG6$|iUF6&yA rBVv&hCzdM7Y|?i:T'/7 x\L&Hg $T7H4aj,gvTy-hxE1-PK~q'j   ~0v. zR `d ~Z7Yl \ZXx4m ]f$Bs|oFz(&f(I~O ;]7@dH"WIvDr *;\~!.<?BEHLORVXYZ\WRLG%fI PRr+4JzU0 3mKv=M\l{:]$-$j5t,He2R ";q.43})-J\ KkoW6YYYYY!ypgZN i_fCDgV~dJu:|sT\!(?"J7Xy|V/v,T dC9X>dA0Je%=k&>Vq8`mz6Wx3Le nCV_4z#v(?n)~{xvJb<&"'F@!r<dXK>2j'FfWH=Qg`oY$*S|D h\RBggKv n6VvsNL#hEO#kR:!4_XXppqmi: afBm'TAcq[$lA#.NSX^cp|#@\x /RuEy>m"Jq{hUB%Gv+7xV.aj"_6 >n::l$Fcv}vb(x)8HXH8(\ # |Ry&}H.>?@=:85) 7Og E~.n*h(m"Lw8@IRZB*~UfT5VTBW6M|+J+(Ci4RqEdF\qvO(^ >C6/D}xtXqtvy|A`=?AzGr t8YmH|8Z|EA?@l\2|"8_+oTnwX:pQ2whZL=)yaI1ybJ2?dT)xX8$_5Y}pSjhR)@\6+- Bs0hbp%@\oA>{&=U.jb>f3 uHJ+ I r@{CbqnY1X$.8Bl*<j(P~:VKy@it"^P[8|Fx:d (7FB>:6,! veT?*r]H4' z^A$Z3 lWB- Bf>n>54kWY~\!J"S<5Ak~(aV :i{`%Z*ihtR(tWh|_B& #fx)fLTr^KMOQS{/l2~khJcBu i<kC`8lO3"4Ni*T~2b!Pp82,% |V0v8Yhy2XyHr]bhnsZ{@]<|@9,[dD%z4&^47Lr\n*v_HXhy,bIx[A'd5l2tWLC*k II}B^ULD;CKS[| 0"qT6lTE6'teVG8) zpgWG7'")4>M\l{@bL{ :j"Nz4LD<5-~U+^:<Xqjd]V0 H=[v%3RgF&:\}+^+^ N{/DXmw|pcXNC8) xpgYJ<.&p_N=nTC2" ,Mn#] E-fN(J^roO/l5SinXfd)ysmgxO!nz9X|&{?v Z(NK(V#X@`f>:740Ib{ I4:?R\ NAi~X2_Kv/~C \5rpmjhs~!Dh:`2Mh    xaJ)_<jG$uvxz{?r D{3|SP?fc>s<C@:6,d,uuttt ^,':Zy."pOe8 CM6qN5AH *b V:7)w SV!=EMU]RH=2]/Xr9_0bB# $8K^r-AUi} .@QW]cit~ $-=M]mrx}~uld[B(`6 c8 a6 dP<(#2AP_FZ,tK#kNj\3 Nf`MSbT|T ^\~:OI,s 5^dkrxdO:&d;835Cn'iUB. &-3RpEx<~V+r*dJhhM2 j<W*{Z8 $2Ti#4FXj|pZC"_.`,c4iJ+ =Zv(efB_!bMl`0Iq!-36XyN# XrqppoXB,a'y8u1d-Z-ne\TKRZah4X@lFr4Lcqti^RA0 taN<) xpgb]XSG<0$  !4GZm &B^{9Rl 0+&!lLZ"OY(|gR<'".;[{Jz> ORC~(8IZjbZSK4],w;t1L|:`- } /Rf9~M L>a  b:wC \"sCf>8Vt*Qx ,Mi+8FTY^bgc_[WND;2& uj`VI</"zjYI>4)$8L_r"Il*Fg#(.4,$}W1V!}BuI{`F+ .AUv >p&h/r.kJ&6F>70( b5 N<n*p5h7 4\ 9i(h0r"]:Z{iQ. j>uAzT.yV@*"5HZt>^~8Nd{  }sj`VNF>6*~lYF4"/Mk:`Af"*18@5* [7}JzExFydP;&&%$$6HYk+`DA7q 9h%S%T^]|LoV<" (8Hi2e B{(b Bl.FVfvztnXB+~T+W-fAxfTQNKHHHHHYj|.Jf*<M^p}m\L<*u[A'xj\ZYXV]djq=`%OxDl 2FZbipxhXG7j@}Jj4h<~]OB4&),03I`v-^0n&dN>ix[*a)E UxHs`LNPSUj Hp)]&X*Qx  ~fE$vR. rXB, ,8J]p+8FT`lxs^H3fF( |l\M=5-%"&+0DXm$Kr My)T2@MZhmrx}qeYM- tGWw;]4 vSD6(&,2FZn1e;v)fN?jgG'E `*V!b46[Ep1c*GdxpX@( s\B' ~rfZNB5)"  $)06=DKRX_lz$8KZhw"2CNXbmnnnojd^YH8'tS2 zX7nT;!)@X~LxIIq .QtxeR1m< Zv>X.{`F:.##0N^ou|zvj^QE6( |fUD4#wjbZQIA80(# %')+-6>GP^m|0F]t .@Rdnx}xs`M:'sW/d<jN1,C[ 8f N}Pw"=XgvqX@'pDr6`-oGyof\R[dnwLZifb^[J8&zU0 \2b9lWA6*$):K\m!Aa0G^v&,3568:2+$sdVK@6+  wlaRB3$  !.:G[n.D[y )FTbqq\G2zY9pK&v^E,,JgIv5h$Rx8S\dmvrnkgP:$ mAX'PgH* ;a)T 8d 0Tx}_>nJ#nO0#6I\p"6JYhvyndYQH@8* teVH:+ $".Li"Lw4W~.Jgv~qV; hM2zbN;(  .=IVbnty~ %1=IT_jurcS8pYC-.Ga,Pt9Z{rX>wP(~S,tR00Fg)X>d+V)+,.0!_<pClI&rX?%" $(-8CNYx5Vy%Fh%;FR]hknruj`UJB:3+ucP>,zl^OJD?:50+&&&%%*05:<>ACNZfqw~ (3>JUdtvi\I6$pV<+|otx}*Gd*Ns:Yw~hQ:wL rF oP2 8RmFp,\Ac oW/lG"mH$|l\UNHAHOV]n >]{6Ng~#(.4678:3,%xfUD4#|tplie\SJABBCDFHJLPTY]ciou| )8HWfuweL2hJ-{rimptx)D^x*Nr">Zvz^B' pGxO&t_I:,"0>Ld} +Ot>i &DaunW@*uR0xZ< 0F]t "9Obt|qdVH;."{solhdcba`]ZXUVVVW\`ejqx~.>M\p  rV:hJ-|rtwz|)C]w#Ip$?ZvpZ<}[5zV2pdWJ>BEHLWblw$Fg0Rt)CQ`n|yhVE/lN/iR?,$6GXhx *:IVbo|~ulcZL>1#wlbVI<0*$ (6DSbp '=Si +:IKMOQNLIF=4+" jL.^F.uec`^\fpz>b$Hl1DXlr^J6d@sT6zf_XRKLLMN]lz"@^~!Ce~)<Pcefhjfb^ZPG>4  jR9 ybTF7) #.:EVfv )7FTbipv}}rf[PB5(ulbYPH?6.&  '.5FXiz-F^w (6CQW]ci`WNE=4,$x\@#oQ4|ph_VNW`hq>b7Wx/DXmt]F/^=eF'wrlfaflqv5Tr9Ws .<@DHLD=6.# w`J3 yhVE@<72,%!&,16>FOWblw$4CLU^gkptx}ukbXN>.|jXF<2)  &6FUh|,Gb~!4BP^lt|~xqbTE6iF#uR7yl`SRPONV^go2St!Ef8J]p{mXD/bA!|`E) 9Rl(@Yq " xiUA- vpkf`ZUPJJIHHJLOQRSTU\bhow &4;BJQ]iutbP?- iR;.!"6Nf6Rn*BYblvlXE2vY4`>& uj`UVXZ[dlt}0Ll2Ux-FR^kwvdQ?,|aF*fN5! *:L^q "8O`rwobVI<-|vtrpnhb]WUSQOSVZ^`begov~"0=HT_jxn[I4lT<((@Vm.Op*AXdq~ygVD2`@#`< ~rg[\^`amx%B_~ Ab &@MZfsvx{~|{zxhYJ:# pT9u]E- ,BWl{ 4HWft{ri`WPJD=1&}utrqpmjfccccchnty 0BT`lx}hT<%hO6&.Id ,Nq.BVcp|znaN<)rP-bE( ~xqtx{~">Yt .Pr !0>M\^_`b[TNG9*t[C,r]I=2& %.8IZk| '4AO\jx~xtpkg^VNE=6.&#  ~zuvvwxxxyy}%5FXizzhWB,w^E3",Gb}.Op #9OZdoz}|vpYB,xY:nN/{s{8Wv8Us(2<EHLPSMF@:'rZA& r^K7.$  !*2AP^m{ (3>HNTZ`hpy}wpjd`[VRPNMKE?93-&  |vpieb^Z[\\]afjnsx~$1?UktbQ8v^F/ $;Rn0Pp (8GR^itqnli`VMD0 dG* }`D(,@\w4Ng &-42/,*% nZF3tdSKC;30,(%'(*,28=CNZep &3;BJRVY\`cfjmpruxurnkjjihfda_[WSONLKJD=60.+(&%$$#vjd]VPNKHFFEDDKRX_hr{"1@Pbt  zdM2yaI1 :Sr *Hf &6FUekqw}yvrn`RD6! vT2hP9" ,E^y1Lf%+# kTB1 th[ZYXWVUTSVXZ]dlsz %(,/23456=DJQTVY\\\\\`dgkjjjiihhhfedb]XTOLJGD>83- whXK>1$"! $*07DQ^k| $<Tk~ (58:<?6.&nT9v\E. '@Zt6Sp2@N\jlmnpg^UL?2${`D&uXE2 $4H[n+ATgz}o`RD3"{~ !"*3<DHLQUX\`cglptwz||xtpib[TJ@5+  ~tkbXMB6+$"*3+ 3FZj{,CScsyl_RF:-$  '.6>DJQW_gowz|~}vnf_RE8+m`TG:1( !,8DO`q(=Rg| !"#$% tZ@% pV<+ 0F[r8Ph!&&&&&u^G0n]L:) %.7GWgw )7ER`nw{ulcZQG<2("  %0:DMV^gnv}~vng_QD6(tbUH:-& #.:EPbt $;Obv  lU=% {dN>-   2EXj-@SfytdP<'zl_QG>4*)(('.6=DJPV\hs~$.8CMV_hqstvxxxyyxvtsnid_[WSOG>6.& &2=IQYais~rdWJ?4( reZNC8.% '.6?HPcv.BVi|     sbP6~m\J:+  $0=Pdx3I^t~kXF3 wl`URNJGFFFEJPV[enx  *48=BFMTZacfhjheb`_^]\WRNIC=71,(#  +7BLWbjqxvlcYJ<-rbWLA61,'" ")06ALXcr1FXizn\J7"n]LB8-#  *3>HS^o);JXgvxmaUI=.wsnjfghijnsx| #&),.146<BGMLKJIHFEDDCBB>:620-*(&%$"   $0<HS^jr{|ulbYPB4%tg\RG<852.0124:@GMXcny 0BSdtwdQ>+seZOD940,'((()18@HR\gq&7ESaoxxmbVJ=1$  !$(+-.02467988876421122223442/,**+,,*('%" &2=FPZcjryuj^RF;0${pf\QGB<7210.-4BFKXdq~,:HU^fox~{tng`WND;2*" !""#$(,1568:;<>?@DGJNKHEB@>;9988841.*%  LISTBINFOISFT5GoldWave (C) Chris S. Craig, http://www.goldwave.compsi-0.14/sound/chat2.wav0000644000175000017500000012226611305557613013222 0ustar janjanRIFFWAVEfmt DXdata@ wP*Cu,z  /DZpxI@fP' z-oY%>YZZ[\fE$a`IH 9RjrzBh82L < o b#2h1H_ cx)c!X e Sj")0BydP^lllll* e   2 ;|X%MwU2F Y l  1 N ks{aBtn_ &?U! 0 t r ^ 3lH#u`9ao*0m 0 U z ?   \ "'$ fO h0i   R s3zS@. W@z@[ aN<60*$ TIjP6P$apb / D Yn"a( P y $(a<R4,8E C 3nY9 ~"k8G(KG;h k?j b /n J$t9^"y&XEE P \]I4 H2]6>a0d0Je F 6 crT7Z' ' ~8\ C jn v \ G 2|MO [.>T Bw3 N h<lF W`16g?{T  $x Z.b.]+B*  F x l - NQ2,s>2Rexy = !@ < & ]8(LqBo W Dh L  6 K Z#j ?]H{hVC+xM" 9 1j]-br%j8 # 2Vyi4 ^(>N{rD |T, O 0F$`@r y.h6>  "TX ( z-6k(j,oBP^l z h UB0Jc < 'nx6pp20X$ 1 D lY:$Inu4{Z8 + #  <m 8 ^ s.\b7eV  * 4r 3w2Kd}2BfK0p {T ; ".vDP|=w%d  < Y3|na T F R ^jvR'^2i(f4!b R N  r> ^<~JNRUY? <m5 b S`gn v } p cVIc5{gX>VeJ / #  P % * wA d(wG\p(p< E '=AD H L [ jx;V@:w+b*q . 8 C NXX{ j zXMB7,vwS/^*?~< " s"8M b x {J'd@r2RZ'{$    (:\ .Zy${bH.Fv7~ S  $s F >]{? m6Z   $ (-|A 6 ,G4"TrT7OgUN ^4e 0Cp*S|rCpJ%Il/t\ C 2!Lx *WK  (S 2 p3Tv,hr/Kfb^[W /  | @  x 2{0r\G"Dt\ D  E Z  g>@iv>N, D w W # 0<HU?*Ft]F0n( < u S ;jL..Li|vp Z` * f  kT<$DnDf6Dy8 p ,M  y , hAIPX`ir{ Nh?O`p \  V gxr^J2Xj?_1Qrn* T  n P 3 Zt\yC":Natyrj F  uTH=nuJ k& 6`E w / W O G 2  "Dg4e * #  z^o2V%1Om. o 0 q f \ H 4$.V~96 ( y 'K.M818E = i 3 z = N _ ;  .BVK@6+LnS0 . [ .I;-cM@l 9Nte$ [ . _  !rW=WqnR6LbwVzp h > q 2_sg[,ypRdfvp; d . + ^ f noppqm$Xzqhd`\X V ( g >k zZ6ne7Og~Nu H  ` 7 k  Fq_M;)7DR` H  Z bixD6^? o4  d  g  9#@]z^$. Q N  G *vfVF6Zd 3[> G o  x&8J[mv~b6 $~tQ . =  : p 9|}~,4GIKjW w m 5 G  yc0q> '0  V &  > y 4s3l\M8$ e b ` ^ [ 4 t ,  (2Hr> P\ X C D  k w*0i5rVY' 1 ; E O )  { @  !A`?}Nb&M9 '  $ p  z:AGNU64o> }\jH& % $ " !  O  &Gi}*O}fP}xtr q p n  r ( CLV`il,bZGd/ { W 2  NU L9a^\YVB - 2 8 I  v2~Hz6:dlNYj z x l K *  X2Vmb#c4PE W  V ? >b"H h\B( x:  , < > ? @ B 7 , dOrCN;HlRj  ) 4 1 < T 8c<Dr6i!^&~=y    + 7. <>.r,XftY="| : {   N Gk5OnHs>N6V v " - 8 C Nx-V-8vagZN > > v  Z ZK j+Hd^L F t  7 W w F+az$y"L! ~kjh  { , s  v 20sZ,;IVdrdx@ 2 d  B f iG1e&Ad$ d,27 n + 0 F,l`,8DQ[eoy4d#` & d  N U5*V3K=B[R*pL' S  n  V(pPAHPX__```hpy,+c Y  < v  S 7+R J[UUZJ%W/@ ] ( j ' ]0r8D~zvmdZQbH6h M  N Tb Vb;% VPMo\ ' T j?6expi%gq9 | ( } % w  X-ZT#v2|c)6D X % nS?],(#xV4DTP Q g  d  /Z7b^/8x*o$ l J '  u0IbL5}X35\WF u 2 Q  3T6MMLLV B>x V 4  TrqeXL@jC R M n 1 H 6mhR~v8@!\vfls\D ,  nO"Q"Ttl<z  T * TC|UZZ0\hdB 1~*yGMd\.e  P 8 w"(7TpnN D-zB WX^0s;  ~  n"?xT=\2Rr&N^V { w t p l e^H#w\B(`|+9UN8x{ }  ! h*=4jTB=JVcp%pS 6 ; @ D I h Vx ~8c:4Kn,y@ 4 A f `-B{=~ =>@BCXnO0   . d C~\:o~M3~:^ CV i Q |~@X &@1"zgVD  & E z U b=H(< Tej3x( M ^  B=[,CyjZ4| h f . +($!'-l (QPONM$f! A y B NSUW6`vk@ . \N8 | L  N|[>_wne\2^ vP I - s76rG|@tn.rT X ,  !1Am>-PsC(y=%) r *  xGDb_.4;8N%.}z' f I ,  %:NcL6}DbTj/6>FM<  zU0 v&{h6G8C $  Fq#:r D_&h&)-  x[>!ZWuJVS c$    /albM&7h WSZK | %}bGfV': [8;2l*    (WhZ2Ol>Q-be*F a wZ=+zO$W(^|t"y^{B  "Xr"++AXnS"Z&TI#; l  ,{TBr`N;)SAV1pTc _oh0X"Hn{:JZjzX5 {OJr8'Pxs\E$nFRSj2\ x=-RxI.A2# pe T)h(LpX'E0r6s\U] ".:Rx "8Od{Fs.xKMcy].=|8xn@RdwNh#SX\af~1,D\%hu&l.#Cm>?XDx-n~N2TvB Bcyp%h?<852m2H]spl9j0#p\ ;i FX1 $EfF' y;>T 0t#0;F 6T0 d t&+G+B& zFd l+ $Z*:'oO0; ` "FplA|,6@1"h4>HR\W0r$q2 mK(YRD6)^ D~V3.)&# Y\`dg1eEvChi)iCd"bSD5&aHplAP#,4<Emw,X8I1Ur/nN- {U.vcP=*a 2[dD$E.UTRPO @p J 1=JVb+zb?eA_sZAbDvQ,"bv 4H\oP^yJn$4exn]oZ:F}tT4SrxB(o|}V.  -:l]%Mu>~{'}tU;"2t|SUWTRPMy{!tpmuNG@819ApR8Vt$`bdfhzrX>teVHFDB@]zxY;GQcjotzvm @:Zy[X^chn.jJ-^J5& Iq~cH,H^wd$)@P`p,29@GN$GrN)!(HgkP4v0Dg0$9+?DJPUL.MHvP6,D/LcQZL 4$+3< 0 :jWT/&^"n$`J4 d ^  x#, '6E6' 7dz4 n2p> s*g[NB66788dHJ$.9DOZeUE6&UK fpkQ>,]~ulcZ0 M}xtpg 5@K`v~m\XPwPbtr`MGA+n@JRY`htS>RftiLT%@[vn\K<-(rR ?tmf_X^dkq2u+S{eJa7ESaoXB+@&>1$ &A@@?>DINTH{Du;9(nQ&,2% zq-C rcTD5BN:& VL \ MzG)eJ 1)nS8^ .@]u]YU: dNjU$).3X~hFz9 wlb'$7FTcr&eJ0i,/nZb3<FPYHhmb2_WC/H^ b({p;c, $WlN0-N 4>Ir!28\(ob$f.KFr Y4gZs"4F^vX:l!EtI?k.y3\ 0XDLSUVXZNAe<Qv$e _{#x"g)j,,uU<MhH(wNM{jXk@T=aQH'q`O G'{%wKF`%q\F0( O~F|0/lMd0$F0]<TK*0E&]*NR-VF6& >x#XJV!d? j3En#B8*`jw,Mv:y0m>1$ #\D%P_t@j+]=WDt(G/YpN`  qA8.$"c&cp/\q:p 2aJVV>JC^xFl'l:,](a (RhMsLv.S-iJV/Vz ]T y@g~ YERF9$CW n!]6PZ]<w g0*Ot\C@ qam [VX[D,U]G_i+dd*fX:FW#>ZvAenVKzbP; |_B%vi TaXt9pwBi bJr!~-Hb| :KTh62dV dS.CvY6@6'FF~X)oYnuCZ k3 AB0:mnnop\\q"zZivD>3,S\0\`2!^w&@/wg zBHNTZPb6Rw:{5pf~  D}T,ZZ2= t:V*6yL~L*:JZ g|IY>}SXk~9wR,fqP^*R:z\HZ(2;DFa> k)08N'XJVbM)Op]pGt\}S'^&!:dR(DXkE D|3/I.>z. 4VP$lKR r2"Di#[z6l`@voDM|(!5bvr0p-`d94?BDFI<2QErh-pnT!4rI!NzB*57<}*llXFijfa\X8|u]{a(qxnTVtzMp? pdtc~la_:|pd4zxu$zB^zx>Yu}r{$[z?y GvgXJKx~ \xBV-HdQ"Z!"A gA o m,k^QD7M iPmyD!>\zKS~ &?yMw}nX cXL@5I}hTS ":Qi64awt$T$j/ pV J@7.$7nxl6y2 1.H,\x C}P$/>~T+h!p*p0K] Bzc^Xj;8|!%X[,-.lT4R ~;DXll:p q=0#K=T7GXs:TC:1=T0Ne|(++YPf(/b _r8PG2zh(q "h*Qx 8$ JxJ `" 6y m}|feO" Q9" F&6NJ`uh\Ob .>b 54Q)Gd_H"M6> 3KJ`seXMm .;Hj1:[38aEG3 uN7  L+8Lhh"bcL;0R 1D f*FRtJ$<`>5 l B5( jLWfym" LG6(H "8M=Vb#_6 :P*&|U@/[ DYp5RD&F  4IyB`n#R*0W2$n@{- T>Xp6_T9 |'|4t@]c&g@(GZ/$pC{"P@XpM 8vZ- {`j*t 8Xk4tP,9U_-b6p @,Ce'` Gd7vj vD"QpR}V0 ":Slg.X+_t)*YHr*" JtN(s Th>(_e `9,F`{$x>H4fe#3[L>82,&` q8 ~_Db7(`bb>6Rm+|8 x:0c^*b6m(YOD:0f n9 uK0}W/~%b%vwP(@Xq'v2 z3 T^8n 8g&e[RH>r j&^9*{a8.k.(`;Nbu"n$^ R\,hB};uj`UJyf#V)xga<?FBf9K^p^~TyLe%B}M>vh[N@q`wFfZwfDC SFj>N^m}\ tAjB|g*H{MCzl_RDt`uL#nQjvU5M+WEY)h]RF;nbt? ZKikMR*VAe:NatcR g8rj/S#XHtfYL>mT d>fUtvX`7`?\0CVi|^zKq ?ue*R/dQwi[M?lNd7 ^XwrQR*WEc6HYj| PnEd4l_$S<nXq`N=kR g@gSmzZ9N-[Di?O_o`t=V+fm4`9fLuj^SHvY f1L?_dFU2_YZhvPZ$L*hh,W<lVzm`R bh2L?[vqR4L>~%s]iuZ^{6L[$X?{7vcYV 6<]~hM1Q>w$,} ^Zw5:qrtvwDRL-HvSC kp1PpybL6bX;0lvLLj"~3osw{Nd ZRf{h@J@{9*p[q x.\uj_W8*{D O\r.uIXgv`:HF2MxZL{*1^}pcV_P:~E OZr1r6H[n\8RWNMQ`^/DYn_<UT/H}bPspLyndZOVL@T RV f!d+<N`qL(DM9T/v^n^-WND;2PJJl6 :h` bQ 1BR0>XOv- ;|U\N@:4/)R] _ |D @n]T7t(;!Lli>9vGI+v.,*)'a a cMDnN@%d%<!IjdI) C}A2hW l|,k3?c@*z J,N x'@lH$9o-~"o Vi?DM  @`%g ]2t2 f&?NlH$;p%q V>r  u*K_]! (CSJ)p7"j,H\c<5feO1cw0Z hg,,GQG'n *f+Rh\4 "TVA(] =et#b" :WO$fj4Zl"d:2d`D+^ |6ek`"8VU9 Mp8g8xN# 8f T/x @v>j}.F1 $ta> Rx~Q%VBk:0&1RrS*v0h]&n#NlL+ ".:n T-p9^zS+d"Mr@6,":\}[&kUX"m%X|^@!,8CN|HWDnY2j(]_TH=2NjP\ BwNv5w:~]|Ld|xKDNxX]bfk E2o6\z\=J N zk\sL~3o @Xoxl?}B_(hjloqI6r6^vV6vA_2tauEw5t9Qh~re:~@\&uxz|O:u6[wX8r;Ixj\t$X FH^stf8 t8Tnrw|R@z6ZoP0i1D|pc{*] I@Ti~vgY.q5Ofkpv{M0i*Qx{_C'~FP"~oauH{4r <Sjtg<~AY"mprux@{-g.VdH,WW(vcQdv2d$dG`z~R'Tb'ghhhi4n"_-VfJ.We3zhVh{7i%d=XtY.\d(\^_`b-hZ.Yv\A j*i7xdP`p$UL0Kf_6m1|@jfb_[}TE#R{bJh(g5vaM^n~MW<Xt`6 h+r5~VTRPNrVP*VfN=w>{dL5J^s&Z`>Yt`4c&p4ccccc*dP$QgMk*f4r]HYj|MV:Xu`5 i.~C uojd^UHJurX? m0yElXgv(YS-JfW0h+~E ojfa\{PF N{}dKx6q?lXfuHAx:Xw]8u:Fojfa\~VDIwrZB i+r? n[kz#QDz?`h@s4F yvrolH4s;iwpX@v:T#~hu!M9q6Ro|wR-u>`)zriK1l+Wftn]LXr=irz2n$Z:Zy|~eF&`(v;yq :lSDVgx{l^O$j0Nrx~%`I<^gF$g3Gzm_v$YD :M`txj\M"l5_+wz}T>v(Jknrux\?"q?T(zl,]E 8L`u{l^P%j1Ty%\7l Ejpv{fJ/t>X.}.]2i)@Wnxk^Q'n3Z)+b<q!Dfkpty\> h4Q*.[3l.DYnwj^Q&n8f4&Z+_8]bfjoU: n;^6.\4m!6J_tgZNAm4b0S,b9\bhmsX< uEi=%R&^2I`wndZQ)yB p? N'\3W\bhmS9rA kB%S+d,@Uj`VMCJyDOT*MSZ`fO8  S{N"/[$Y !6LbYPG>wFPP T(LSZbiP8 ~PxO&$P| W0E[SLD<Q V#NEx6?HPYE2 SzP',U~Jv+BZTNGAJS$J{Dx<DMV^G0W#_6&MtDr(=SLD<5xHW' (XIz3:AHO;'zNc<(NuFq 4JD>82V'm?" O~ >o%-5=E2 ].yP&,Pt2_(>:63/d8 }M.?j"Q".;G8* sBZ08YGt98887nBU4 2\I|%4CRD5&|JZ-5YEr <>@BD( zM [8/ZAr/@PB4'Qb8 6WCp"?@@@A& xJZ:-U}6g .?PD8, ]-tH%Ds1`:;<=>&^3wR-&Ox2b"3E:.#`1~T):h"R38>CH.\/oM+ Dl$U},>4*!^2^4$@n#Nz!&*\3~\:,Rx%Rv,%f9 ^36PxBl"b<sS3 5Vv7^ ^4 sN9$ #9Ow<d iGdE%  2Pn1Tx sM'dL4 !6Kn$JofEnO0# 8Ur'Jnf=}XC.(hK/$ 'B^z*Lo|X4_L9&(nTJ?4*06=CZp7TqxX9p^K98643@N[h-Kbz{cK, k^RE8ACXl+Fa|kP6lXQJB;FQ\g"?TjzhU9rdUGJLORct:Vr}dK2xbMHB=8ER`m:RizfR7p]J889::Nbu6Rm~fL2mXPH@8BLV`z"@Vk|hT6oaRD69<@CVj~#@\xlR7}fOHB<5?JT^w7PhmZ>"{l\L=@BEHYj{7SolT=%~hRKD>7CO[g;Rhs`F+q`O>>>==N`q *HfzhO6nULB8/8AJSl,D\u}jM0r^J76432DUfx (FdwlT<pWL@5*29@H^t3NjwZ>!taN;9864CRbq7UknV?"gZNA4:?DJ_t-HdhI* |hS>:62.708BLV`w*BZqt`D' zk\MMLLLZgt:VjqX?& md[RINRV[p 'A[un\B( LISTBINFOISFT5GoldWave (C) Chris S. Craig, http://www.goldwave.compsi-0.14/sound/offline.wav0000644000175000017500000012453611305557613013645 0ustar janjanRIFFVWAVEfmt DXdata  "8Ocve:~xrbSD4' "DgFj4bmI%%I& >qH52Ap)Sj5nZE?82,Gw2>IT`>f4S&|l\u\1q@Aj*#6Z} />ZwJz%pR+/2jB\6|bI-y6c&vd\SJBP^lz-/246weSA/?O_ow~oRL(^ j>b8 =&S)^iCUxHa4gC!_TO8d|XzD*jX=vLTzs/Jdv]RH>3{ R4yF&m2}dzjN3H\pF. =Zwj]z Np9'PxxeQ1)Km1\(l\M>.ibB!Ip}J .No4hwB X/4* nw(vlcjqxh8'X0W~+X0 X@x!Y#T7\0ARct'f=N| 3H^sIJLMN{5 s`L962/,hKzdI.NwP)z`F<3* ?^}<[+0h DzV3v:xfM4j' Ejnrw{U/ rM"rZBb$E\tl({C kG$jI(.h&Koonnnpsvxj[L>5,#XX)XlT<0$ 0Rt#iFx=v2yR.e L~dP<(7Z}Er Hpx[>  $3BPj;gr|}hT@7.%$,4<60)#c44IotzfH+oJ&7HYjN^m|zriP7|7h:?DHMA5)2PoUKB8.g^AVlqX?[<\DzC   2CT_julXE1 ">[ Ej0q(|dK3>HR]elt|fF&  8dL|)D^r0rE8`4RMHC> F ,9E_zDu _ `*nzycM7!LvjN2Rp`P@08?FNw!0 |fO8" m$7'  $+2:A u+tQ. .@SfhknpD|Z8=BGLORTW2h; RE;XbluzslfO8 @nlN1\5 #Jp.TzS:$Dc\UNGEB@>1$ &/l"LvjVB/<^,[-a &3*!/Pp*] D|S %:NbwvbUH:-V~2cwN& %A]O@2$Qu+N!{rjaXm%Xc,Bv[l~~l[^8)4?jF"qV;1&Huj^SHl6PkdD=60)Pv'Hk7XD0 Dr $).3/+'#Ny*={4X}.+(%"+4=F|Ht}T1Nl0NkN ":RjDrQ- |Z7I[mhB4KT^gpw~qU9o5oZF1N$~*{rjaA"mF>6-%')+- \:Fh;rJ"(MrtaN-  &/Ic}(YoyHH*Ody|iVE4$*BZq #:RjwfT'"QKz!^- $xEvR43PONNM, mN, nQLHC>. X^[-]: ":SlvhZL&~{~qZD.q2vgXJB:2*6BMYep|b<l@Rdu >\y :^!&, C|/k *;LYfr:yq7]p~*c %Ff:T 4J`~FcZRI@BDFHj hN41G]sx^E+m.R n]K8&l;9_3>JVaabbbK4S b5 nFV@xbMczx`G/&  !-Z+D:0%2UxhYJ:,QvTA 420/-:HUbBg 8Z|sdTD`|@o:v5LKJHGp.r&S?Rdv~sh]afjn "9QX`hortvy`F, -f,:H@81)rK$p0L%+s=fK0n8h6Rzl]N@t,f0j>K 8bO<*5Tr 6BNYeN8! *[ Q !6LE>6/  &@[:Vq ;Yw)s*` 2JbzC8tIte.D[C+ '@Xp$^-L8%|z`EzybK_>pK&VTqT6ZdN9$%0<*Y2 OwTWZ\_ZTNI,cC$x~|^@=:74>GPZk|)2:BK.*>uK|2V:qR.Rv!Bi3OID>8CNYdJ!MxAg`XPI7%"CdH[nvcipv|+E_yhK.5?IS]d`\YUhz$&4~BV>ikof ;S z m( 1[E/Jd~"5rK%^+v:L (D_{(Ii2Z^wL.|rhVD1|+~`KDGQ[eo8xj[~X:c4J`w >tr4]^wC$9NdyID a*EnoHg9Vt:3_8zf{j M pIavTSSn)$\zT)<'Sh~$wc-&|kpv{1lN/5;KMCs.:EP\ kw&9L`s WVt)ft*BYz2N6K"YJ&2lptx|Z7 Q  n ]  I # _ f  gte [   & 8 J *  pwR-{4_M}^Wl#U1&iO5K|]"f'X)AYqvFrL7" & g,}m^N>>=<g |^51,($VO~ YUtD>82,hQdhwqke_ `q&Q\J!i)h{> v#|F:dX$Hm|`CA?=;:987( k"@zodXM]Ql.f"%Im~m*vExF)=iC[J:*L 7P07bB@9O<hRoJw$e UR $=W$hD!&Nv<^F/h^sFPH6/Z =n, {Ln-`3n,lK*NrM(,AVTRPNKh9L^qc7 lf(Ij3" Y@LXdpX?&g/0012o&9L_rZ2W<b |b4d;`/7p$aN/t  $ 1  s# V '  l 3 . e * r  *   . r d W I a y a =  k7,uDTg<u&,rjmD8[(d,%]]$Ma}P"|;p,0EtgD!HpBnZYXWV@*8rN "4F\qdV%jv8vm#^"<ENV_*nT*n _ P_  f  | c J 0 $  7 p  J ~ h D   & ? X  ? ` P V  V  j ` W N D > 9 4 . F^`9s4yM n4M=y> !6L&S/ZLH]ry:4Tj8L Q1*W +LmQA^z~H *J Nt~NIVNeH* *8FyZ-j*hHz(R^jv7sl1<FQ\'@g3kszVPT#;SkNP1hL/ "9O>. wBt `>,: FuDzv4R$FhaZSLC:0' J!vsfC!Hpl vSRPNM[> ;VprdWaku'_>r? /V|raVJ>3^'!jlco{\z=:NatiJ* ]#)/5;8630q<YyiYIVbo|h*c|m^PA*J~$^i: w;:N,BXl <n/o[G3#(,0`$X4mQM#jsD+Ar"*2:T &C`~uL$rj/-8&b?bq8mu!y%j Z\ZXVT7pQ d.zsld]^_`aN:&`"^*htV77VtSO2cAhrVOY$SO"Hq#Hl>xV4 J ` v p U :  9 T p  f   O f | h F %   T w ^ R G < 0 $   n ! 9oR 6<TmN0_88\[6P{etR ~P#Ov&|O"&*/3sT5) .;RjtP, KV j&H >pl\0b(8BKT^ b7 v P  X t A  h -   ( 5 B P ] ;  x I  6X xB aB$]7`0}#[wJRjVKX ~i[M?1'v,q8>^~ 6alxpaRA0  2DUv9j,K2!;TnB =]}jU[[ZZZ|J~?n}qT7:>ADVi| OPQRS'GhYS{dL6m8~cmw_3r> bRB2"9Pf}^? L~6vi8sRF:."Lu_9% $=71+% 2\@{.j"CcZPG>VDy.Bh<HZl~oN. ")Fb~~th\PD. $>YsbQZcluoH`:v<J kKJHGFkmI~;sW;- n<lgb^YRLE>>>>>"vZ5Pl\M>.yQ(0Ms.GIKMOE:0&g)g":Rk)W+bw.Jg`,m8Xy KN <d=kxWG7')<N` 4]iL.wlS: L wE3"pYBDw|kL, I\_ iJ+ b2aW~uZ>#Le-oprstkbXO"wR. AN[huZ>#(2Lf9nJ#^(S}|{zy V1 pT 0jeM@gJ{\ J <n@kf 0 S v 4 ] } g Q ; 0 &   ! 2 C T > (  f M 4   b7 NSlA#>XFkL, Vv 3[eB^!:b5{[?#xEq]VNG@"{bH/ -=b'b>!&*.3@LYf9E Lh>r ^O~ w*h:ku;x,h = p h ` Y Q *   $ B ` ~ t X = ! xsnjedddcUF8*xS-% Z|<~P#rV:=Vx7wnf2m+jP6U%K$r^O@0!u5Oju:[ 8dL3k3H^sLv2Qp<[Rly(V !EPZepDnjfb^chmrmhb]-`@!lL, n9'hB}@zyhW1 V!7;@DH9* kP6 %1/.,*% *7DQx "2A^|Hyui&Q|.jDkNatzo)If "$%&( 0@O>, ].dAraP@/36:>Z+\'zl^/vJwwwwwO&}P$`;-@RI@7. 4Ou"?]djqx|:`3H]r8sS.NmU(b(B[uL#Z ".9L`t!BcvlcZRIYhxhJ8&l:`O>.k"G \F1qJ"t1r4hH'e&g/r^I4 _,f6]RF;0nV?( 2Lflrw}gQ;%%Lt'$ $0;Fd8u#\El,` `3Jbz([(m \/F^v4|VBi.\!^"Gl 1 Z i x x k _ [ X T P [ f r } k Z H 6  fB\4 t=W< ]#eNtCzWi{,_9a?JmEfJ.uIvbO<( &BRbr ._ 7N^nHq*h:ZyM=}AcAjP=| &A[)_2c &>Vm&Ghmrx}tkbYer~dH,rR2xPD8,  e4n< }dJ0f: k5ygVD2X}Hm^N>/)$~dI/oPB5($.7ANZfs}~:Xw@d2St"S ,Nq':f4Y}0G^'>Ulifb_]ZXV\bhn  ~^?. `A"zm`B$R ygUC1 |hUA><:7'zX7  'Jn *Fb~8HXgw~5e,Ielt{(C^y8Rl-0247( p]I$kV@+ {Q'p_M1qM!r]H6$m<x\A&`;p_P@0!! *3:2) ]4 `H0z?\*_= w[%N`=}P$j: bL5`?fF&nYC-"0>MLLLKHFC@HPYa 8BLU_s 'U 6b.Nm#Z(PyL~VF$V (Gw1\@WnAh;Rj  #&)," v`J&lRI@8/ p> W+q]I'X$MlJ)[-T*jI'xS-dE&xfS5lG>5,#%')+*('& #,5>[xA`*7DPp Hq/Pq>mTx1Jc|$K{ $>Wq>c$Lu%5EVhy~|yw~eLE>6/+($ iI) r\E/_.hR<'yZ:ziXG6$mI%|naTF8*nV?6,#$).38=B2" &4BP^r!"$&:Odx.GUbp~2Ts4<CJR^jw8Rky0Qqq\G2w[>"|n`SE"cF9, jO@2$ i]QE9>BGLNOPRNKHD>83-5=EMav >Rfz-Ej 9HXgv @au%:Pf|!$&.6>FS`mz{hUB/%fH*hQ4jC%fJ.tV9 ~dI'{X4 t`K7(   #(.3G[o"=Yjz*Ot 5]w Js=e6Ql~ Ej2Oi.Op%8L`n|,>PRTUWTQNKJHFEOYcmrw|p`O>(xl_RKD>7z^D*hJ, a3X0fD!xK%vW9iG%tI{bK4vZ=% zk]K8&"*18@GT`ly(:L]o*Pw9Tp0V{ Mz*Gd FkAo3Nj'Jn5Rp 3H^t158<@JT^hzwgWG7520.)$ vbN:,jN1 pJ${Z:jH&gN5h<lD!nV7d< rdVH6#vfWPIB;>ADGD@<9, !'.6=DMV^gjmps %>Wp$9Zz(Lf!4FXw*T~#@^|"Cd$9Nbu)Gd /@R`n}}~uh\O>. vcO0zhVC1 y\@#v`H1yZ: r`N=+zjYK<.  (2=HHIJJLNQSX\afv+7CObv /7@HPYbjs !9Ph #4EVgt%*.3852.+*(&%-5=EB?<92*#xfTB/hP9" xeR>+xl_L8$%8KZhv%4CTfx (Eau*:IXo $1>JWgw&),.148;>@BDFNU\dfghjbZRJFB?;:865;AGMJHFC1 |l\K8$}hR=.dG$}hXH8(vW8ymW@*v`QB4% zupjejotyyxxxvtsqrtvw(8I`x"1@O^gpz,Jh1Jd}7Z}1Lh -Nn #;M`r">Zw "(.39HXhw|naH0xiZH7&~iK.}eM5 qL(~`C&vP+qT8waK)^<$ p_N8#}xurolbXMC<4,%.6?HNSX^bfkosx|.EVgx=` .Kh8PhBe0Nl*Lo.Hb2Nj'4@L\kz%0<?BFINRV[_cgkpv|~}|n`RD;2*! ~eL2vdSA-wZ>"jM1{Z9rZA(pP1lXD0xcN:1(  xonljilptwz|~"(-:HVcs&6ETdz- ~uld[QG=3(zjZJ;+{tnhc]\\\[ZXWVLB8.'  %*.27420-../02457?FNV^eltqnlinrv{"5DSbq )4@KV]dls 0BTew"/<JW^dkrrrrrtvxz|xl`TH:,rdWI1yhXI:, mU<$ |jWD2|pdXL@4({pdYNB90& !*2;DLT]es%6HZk0F]s,Gb}.B\v.Kh)?Tj%4BPZdnx"(/6<?BDGLPUZZZYYZZ[\XTPLB8.$"  whYF4!oT9s`N<&x]B(gJ,eJ0r[D,~n_OD:0% 1BTev'6FUdz&:Nax1Pn3Kc{/F]t"1@Rdu%2>JWhx   {ocWB.seR@.{fP:# ~hR;$ xhR=(tbP?-qaRB2& &/7?GO\jx '3?K\n .2' ~uttsrrqpponlkifdbbbaagntz} "',27AGMSYdny #/:FR[dnw (8HYiv &2?KWcox&-4<@EJNV^fnwxph`XPH@81)xk^SH=2!~m[K:* n\J;,taO:&~sg\PD8-" '4>HQ[fp{&9HXhw0F[q )9JZk| 'ARdv ->O`p+6@KV`ir|{vpkf_XRKD=6/" p`QB2"jWD0 o]K9# |jXE2 ~kXI:+ {m_PB3$yrjb^ZVRTVXZ\^_adhlotx|)4@P`q"6I]p"3H\p1H^u$7J^q(2=HT`kw")16<AFGHIJGDB?????=<:887662.+'ziXH7) p_N<*p_N<+~n^PB3%}ncXMB90'}utrqppqrrrsttsrpomljhfedbba``dhmqw},:GU`lx,9GTbo|&6FWgs $,4;BIPX`iq{~wrlgb[TMF>6/'|vpkbXOF:.! {nbZSLD>94.+(%"  %(,/27?@;60+$ zqg]SID?:50,(#zrjbZQH@:50*!|wrnihfeda^\YYYYYZZ[\ZXWUTRQPMJFCDEFGNU\ckrz'2=HR]hr|*8ER`p !(07>HR\fp{&,3:BIPSVY\]^^_``ab`]ZXWVUTTTSSOKGC?;73+" {rjbYJ<.uj^SH8) m]M=-|qfZOD8,!xplhc_YTNHFEDBBBAAAAAACFHJKLLMNPQRVY\`gnu| !+5CR`n|&3@MZjy$7J\jx,9IYiy'09BKValw~vk`UK@6,! xj\PD7+r_L:(yfTB/ {nbVK@4)~woic]WTPMJE@;630.+)'%#####*07>FMT\dkrz&2>IR\foz *:K\l| $0>LYgr~ )6BN[ht "*18?FMRW\aabbb`_^\ZYXVTRQOMLJHD@=9641.)$ }tj`WK>2& |tkcZPF=4*! |peZOD:/" |xsokfb^ZVRNNNNNOPPQRRRSRRRQRRRSX\`ejpv{ %,48=BFNU\dlsz%1=IU^fnw~ "',4;BJNRW[\^_`_^\[XVTQPPONJGD@;61,& |wnd[RF:-!}xrlhd`\YVTQNJGD>70*&"  "+4=FNWZ]`ccddddefflrx~ %18@GNT[bhnsx~  !&*.259:<=>:740,(%!  |tlc[RJA8-" |tmf_XQJD>71*$ {xuroppqrpnljgdb_```afjnsx|!(07>HQZdlu~ ,8COV\cjqx  '2=HS_lx     vj]QD8,sfZOD80( znbUI=1% vlbYQH@82,% &.6>FNV^hr{  *4?JVao}$2AP`o~ &09CNXblv !)06<CDFGHIJJKKLLLKJHGD@<962.+)(&$"! vmdZM@3&{l^O@0!zncXLA6,! }rf[RH>50*%  !+5?IUbnz ".:FR^ju #/:DNYclv "(/48<AHOV]fnw{uoic_[WSLE>70*$ tg\PE:0& |tld\TMF>6/(   !',28>ELRX^djpv} #)/59=AEILPTZ`gmrw||vohb\VOIC<60+&"{vpkgc_[VPKFA<72/,)&#   !&*/247:<>?ADGJMNPRSW\`dlt|#*069<>AFJNSZ`gnsx|zrkd]VNG@81*$ztle^VNG@8.$|wrqppoopppppoooppponmlnoprtvy{|||} *4>HS^ju~  )2;DMTZahqz"*29@GNTZ`fjnquz~ztj`VLC:1( zodXMC:0& wl`VLA7," zslf\RH>:62.+($!  $)/49>CHMRW]ciotz"+4=JXfs $.8AKWbnz*6CMXblt}zrkd\TMF>5," uk`VL@4( |qf[PH?6.& ztnha[UNHBA@>=>>?@@?>>>?@@@@AADFILPTX\afjotz$.8BJR[cipv| ,4<CKRZbirz!'-39=BFJMPRUWZ\^_``aabbbbbaa_^\Z\^`b`]ZXRLGA><:7520.,*(&#  ztnhaZTKB90(wnf^VOH@<72.)$   $'*,/27<@EKQW]dlsz "+4;BHOPQRSUVXZ]`dgkptx|}zvsplgb^[XVSPLHE@<72,&{vtrpnkheb`]ZXVTRPNLKIIJJJLMNPPQRRRRRRQPNMMMMMOPRTVWXZ\_bdfhiknrux~ "'-4:@CFJMRV[`dhmqv|     ~ysmga\VPKD<5.(" ~vme^WPIA91)#~|ywvtrstuvvwxxyz{|  (08?FNU^fox (3>IT^hr| "(09BJQX^ejpv{LISTBINFOISFT5GoldWave (C) Chris S. Craig, http://www.goldwave.compsi-0.14/sound/chat1.wav0000644000175000017500000017424611305557613013226 0ustar janjanRIFFWAVEfmt DXdata0 ",6BN[g[PD8WvlSx 7iAR/LC&DbaB r$KrT72iN 1V|8#Io fkV`idgG#r_3Fwj!|A4o.Dr6M |*--'"BvlQ.>Sh$G}F n:HUbp[F1=^H?^Ni wFRqGWG~$h)|>_v.g vJIHHGd!Z0z?A|5/~O473-V}dJ;P 1}`bdegR<'gfTB1pKfiY * zY8zCByx>^ONk|  [  t >/\JT !XLR"F  d j42L0Wt[Ce6ymHK|PbtlV@g D& })A@4SQ{F>Qc BVk }X4t&+RJz ~`X[ $1=i<;EvCzn?nh4\';ADHLOv8^ :t,p ,=750,Ry_D*TM{U0 $cpk ;WRNJEdN9$4Yblu~>"?e#bM06WI<. Z$ke JEA@!0>L:(.ZmhQ: "  ?v S{=Dv0gzdv>F#Ny`=>a$!{V2]J\n.cR>b B&2>{3"FHHz6%01223:BIPjPC=HS^i: L%"0B"\ ;o`k ,7BN p BzK X'#;a6rdL&UQNJFa8\D~zuK!4FXkBIh\3:4M|(-^/rY )Lo*\%6>ELTcr-COZfrcTD5\C}D/_[W$ESPUB\3tF.{{T.LkpU:4"X zF:.#HxH@hTmv4 ,#VdrT5(X|0yJ]"A_ `  x;d+;p"N/y wJ[S.h65f+w *8Gy T 2Jby2~fEsFn'(B:]@<71+mrT5Y~HTFz (2<EOJD>9+tE}B`)NQKE' Ex~cPF@3zU0 V7X0:lwZRJA90(f a4Sr]wsplh8p@k41EYm_<}@Re Yht>H4 n1Mhcvn$]N>.n8(C;3+#V>PW:Uph_WO~ s((r{5l@"DT[I >Sh>'JJ` f8QjzbJ2nR6#|\<taN\iv!URf%ch'j,2x~~n.n:+C:L |1*Ln$< >p0r-^4|uZWIk-fzN}~32|6[td1Dh_0&7Ieh-R 7cM8" E~*>\yL &VoYC-;HVdr-Ck.u6*hPu,CZqJ nKMHC>9 x<T"vR.$ &Kp/h!`+Y\`cf(p$7:\v"qNm(Lx&0uw4sU7?GOWr%Eh9[/NntI`rbC,R/BNA 1XY*;zR^ hBMoZF W>9Bj{HY RD$MIEA=B90(h Ti~<<Quvj7;>BF4H$+k}n \:Y  )]x8wW7  @:xI&jEx@ ^%b<^Zzj 5_a9,n$` ^<1^ T?_~"/<JJJJJ@6+!n9HJv[mW@&XxW6@JT}Na7\Wqvc*g`YRKDtV>%x"cBd|6dB  zh/W!*4n {nbUHrtfm{uoic'"D,D]xhG7'KnT;Zu4(A[gt(^L&tr`\XSO0RL{R*XT_".9DP>+,x\zh WTQfz4d^XRL~cV6Ncx~cH-cB vU4yncuEx`JEuP }M]XRMHRF}f *V}PCxS6zk^R2k@! 2G\[ZZY axb| 7Jxvtqo_P@0x RB3$>iqyW_qtwz|>HYnXB-6Vgx!0(_@xk^QD6)Wd ]HZ4TGDDFpjS<%:fb`p2stN)i<qP..\1m#` 20.-+M1e~-?LUkn)B`o&TjE 08,5 2x:74~ U1 6[n4pj@. `.}B c@:Uq9d 6_wZ1 n }(~[x$m'p%>VtJ>z"w!w#Fhfdb`@ RY~,gErGB! p@X+BX^elrz,XSD$c2d/yw 0LU;JZVQLH%XXT* #v 3nH!`~sC~tfWBj: ` ]PYF4"%n:~J<962/L$\/^7xzz z:5pKS6K|8FPwq C;Jzzzyy8Ln>7RDvX[^beF&G~jVBYp&6V-=M]2Of5:]*i<Y tJxZ;dTaq36Md|m)KGrw"v!R +IbzmX2 p9LXPHA9Uph(!PUV8=- 3j_q\"Y_B&b :To <TDc,7x -=.oP2!&-4 'p|O'K#BXs^Ma e4Xajt}kYG5DIJ>h<HU?j4$vPFpYB*Z2[\8,azk\,qg]UME="iceJ07YF2 |\:qK(aRKrlf}dL j7Q +b:&?$[o[ ;v)~ dir,`7AT7(y?Pu\D,7"7e~ysF,>Pc+5qclo.LrT7La<:]ft:8`'|H%w=p+v U,sP. 4Me>r.r?M\jxM"Qtrh;y4l_vH6#@*laIdX49p& a6V`BRukEchlpu(A:3OkBJd$x#fbCR ]z;X *",>QcL5Q/$n#/Lyu/ 27d%D`RSTVW2 F~u ?z_D( LZ(PifIHwC-Lj4R5]8M^(X,U~\L )2:>|obUH;.L0y|~Z0BsBbFxFQ Py;d;}(|)j W2M=[$Y/} sA+0n*2;DLOXo*1~6nH!<.tc `&)-04nc]W\afkl1 3GQjK+}CGVetOK~0lu#fvH{<Q}x7?d|Vf`^[XVTrXPB~n^RE8,$n/@h\OB6VwlaVK"R7zjo 4G8_dBp\vl4+~&P@h-F` Ab&QJzlGIKprQV\af7` djv{_$">[4LQJnB(feis.(e(Mr6k6=Rm8J!-8DP VL(j ]zRd?4)j+'X tDL<^cG*2UxOg%}[ZZYXi?d>\!X,_d9H)Z?sZB*Vrb4d>g'<e~3QJf7J]p o"L:1(x*bm(\8B}=Hi;Lz@G>,`vX:}V.gRD6(0G^tbZSE8*=^qZB9*Ip:d>||Rneh6HAq2Le~:|bcb`^]PCl`Np8{C[s6NgQc!"n!>|V1K&2wbo4{'~*,}_~ d5| 4\~gPv-pu7$u{`= =n8{+anm=R\$,3579;"<WtGB!B^$5GXK>0#A$GjhB!/\<3h,{Rdg15GYk~/jyL *Fb*hDjLB8-#nM;(]hov~&Jo>{T.;)sNL&3TU|^WZ]XR4{vrm&O"o rbRAl8W0BTgD Dj&fK0Svp%L%`rdMgTQ]c8y;^.2<Fa|N#[3b:(4zaN<*(8$9,%,D[rJyVrR1>%$S.Am{~8e{yV4?JVa'c(8j;[z*pV&]+_,iJ*1a]0xPqM k-SrH xh `iM15SqCZ%c6gP9" ":QhG|2H_v\B(9@Q@VNA-WnJ%irX> l5xkj2xCp],X eqR3pf>?Sh|^-*(%"8C@=:7<#6CP\i RA~c_ZVR8@b`<*n9OAdK%\z9$ 8bHsP [PeD"5+BHM}8.(y|GN#kCejU}xtoj4B|5,&Ja2*#" ,:GUPqF,zgTGwl8l60*#|;*E8*3+ydV8hhijjBZ#\\\[[w:_pvg: X+R v#h8FS`n43JZGt,b/\IL6qo2uL95,Szh |>&wRZNXNS"+3<DW<w6WxyiY@ jG$q2 8d$-$wW6m[b=(z5BN[hr{T"@^djpv\A;&i(Z)hV_k/3HFtNCDPeE%&(*+Fb}->PaVLB7yX82,%BdZ D~|[ k\Pk[L<,i! 1DN|7D6w+3~D @w? -eQ['S~6r_M&t8GGNT[bF$kV'I^CT>v2pl+DPteVG826d5| d2_R&rT6ns |)?gT d2nLN2xqL#_4.(#p6HC$Jq 0?N\k^RE8" ,V &A6,"McO $L^-:4J{6(]b.#^pd f6 ,CQ C{6>^~mG!N>wb$0Hngv<\{"r `<aK*S|c@|\tY\:F25dCv8> JDy"N @% l0*[QyaL7dhknr:9.Ns|G~"DflS4!?`Y!r1lK)6CP]#ex(|%JnxY9o &)Ct tCDE&@5ChFV6>3V.~q^t62auV@%>2kgc/Q6/b8VtnJ%dpg.vj^RvNN~z^B& 4OcxtU6]3X&vfMKJHFv1Jc'L6XDZfi(exVQLZ"l0zP v2CuE|b2;lc.a.o~2\.l $L3_Cqi4(Y`'|Q7A Nha `,)]6p@p|X6nzk$N.:gG'8HYjIEkbA! #6>FOWL@4) nM, /dD2bzKtlToqsuw WgN4| RH>5+hdL3G&>U>(1wC)vT2jb&nW^v)Vt 4DD5|d-?u 4h/qg]dka^" \:l5(XA H)JB:1){T.  tcRW\bg>oDTcrgL1Sv)e*M|BsJJ`NMKGporvy|=,Y ]s(1@BLK3C;Py_E?9z=DDA`~DTZ0fP!eL`j>e#>Pa c#8ln;JZ-)x6oqKVrzS-,tM{5" *Ln9}C/6<CJ.f>y{~ @b ,  vHB\F0%EekliF]tuF"[jz$v D5%(=0gzh`Axu 4& PL)obB"(/6<v dj_$#d ` a ~B;4.'Ffy7]D~XjWv*tsFU:*%b"VtroGLyr z(Z;F( !=|9 S1FZn]L:)~P"z`_^]\m~*Jj i0Q{`FUds,e aK*NrX># bMo@[6>fiDNX.%FfR21]zwW7[';O7Q@->V(D f F~({%+}&2Yth)V`'[0EMJ<.XbtcLGk$1bF_.XoV8Tpvk`:f6\K:(!*4>Xr #  ,<KZjypGpB$LT*r v43uctCWj~lXC.d ~d\TEa~ ^'AFFdDhe?6.~DhB?MF(ZiF$,WJ=Xs@4bGI,QtqNV5gl R(|&z:z|Hn1[-)Jl.D[qxzpf\RG<0%  n]KIGECR`n}>i)LT\dlO2x8k$yF(TRVp,kt|S:l&Gg V0 ~H33333Bk^VR2R2H^HwXjM2>\jx\$Cbbb0teVF7(D1-8|;V`YR2ITcN+}T8BgS dl48_1OmscQ?-~zu>]})Z-t7yk]OA`A]7x /ARHq&tfXK!pjT9Y^c _D?0+. i".:FR z2>KJI40v<=CL&|&*.26\(<@C[: |_D-+p~>X*aYH02'Xf;j$]Hv(T}aE) 2F[piH(uN(Bs#bKI,/` 't Z$?4TsiD iBb=lP4@g{@-z>i&?HmP4@opB:1DN=R*w_F.Fu6Z7gav\0F"Zn+&M)rrBx8x1]1 6`LrtX="} *6BN[htlXC/tS2 "Eh$X5RoysFw.YjF! ,effa 7bSD4%H>}(*o~BA|?5ht$4SsLQ4J_us;"^(U,*Jjh>BFKO0g0~@hd`\X~4wJ-`e24>i5:pbz4:rkd]V\>}Z"y}Q^)V&[}tj&[5v]${ bl5G1aVJ?4{=,{%yN";v>,v Tz^)h"b&jrz+dAr3,$}W1 vdR?=;97FVet0=JVcdfghfc`^YTOJD=60(~xz|~:ZyiBtJ+ N+f3^\9N ?pB<5.(NtL*yN\ o z'b(0_66:u&,27= {#snL&Y545j dx)2~L>jLdN|pK%d$p46h7m"#$%& xT1 mT<60+%4BP_x':L^qv|}xtld[SH>3(0DXk}[8gO6':dBs5>HR[B*a/L"zl=t2u%\y[S x/J=0"4RpW2}@|?p 2H4 7VuA%t<wq3x0Z!ubP>+D^wE R1dsr[D~A\. 8c+_ !iDrQD8,)2 hs~EQ9VtP ~<z=lOXbkt8zA9Vt~Mz9LuF1f:Vqh^TK#t? xJ&Fe 3X~lK*lZHFDCAQ`p(?N]l{|}~xpibWLA6* "/<IRZclpsvzrjc[J8'ng`ZS\dlu+F`zlG"mI34OjCn210/.RW%6h4h2SUXZ\=u@ a)#Z5j;]]\\\<r=j6"U#X @BCDF* uFP19d=hdAydO:9865EVfv+FXj{vjYH6% "(.02579;=?@@AB<61+!*>Rdvu\B)t^G>6-$0bA @b#Mt 0&p? U*8`"V(>SH<1&OT%"JrFu,AVLB9/^+l@>`"Lv$ jBaJ4!:Sl>^~sZ@' xd_ZUPZclv/@Rdmv~wlbWH8) ):FS`lrx}}{m_QC0vgb]XS_kw:VloU;|^@0! &Ff Hk  yJjA2St%Q~ "<962/xF~M4VAp"><:97T"h: *Gt*Y $"! Z0ZC,,AVy-SydB!vbMIEA=IT`l1DXk~~o`QB.!,8DJPV\[ZZYTPLG?80( /BQ`ps`L8j`VMCIPV\o:Xv{W4]I5! +D\u)Lp|R'~S:! $;R{Hr  ^5 hO6 "7Ms 5^fF&fK0)"#2BQq7YolU>!nd[RHOV^ez-@Sfq|th[G3 ~ ,<MWblvvvwwmdZPA2#(<OZfr}~~~vne\L=. yoe[agms2G\p~l[?#ziXH7:Hd;Sk~jW;teVHKNRUhz 6Mdp|tjVB.~ytpkt| -<L\enxti^R>*(;N`ju~paRD2 |xsnv~$;L\l}zhVE*ymaUIOTZ`t0Ib{uX:p^L97531BRct0PpwZ<mU=70*$1>JWu.Mf~x`H(x]QF:.6>FNf~ '@YrxeH+sdTDDEFFWhz,GbulT;"yd^YTNW`ir&;Pf{tbQ9 ymlllku+DVi||r`N;)wnprtv0F]iv|siXF5$zqh`W^fmt5Kaw{jZB*xhXWVVUbp}"=XmlR9 r]UNF>HR]g<Ri}hS6o`RC47:>AVl.Jf|_B%|hUA@?>=M\l|:Ugzs\D,rjb[SY`fl~4KbxtdT>(}omjhfp{5H\or`N;&vjjihhv&=Sbr|r_L8%xof^U\cjq &<Rg}n]B& xiZJJJIIZj{3NiztY>$zeOJE@;GR^j9QjybJ-ui\PDHKNRex)D^xpV; ubPMJGDQ^ly3ObvvdR?% ~rg\PUZ^cu "7Lanz{pZD.ojfa\fpz+?Th|~l[I0tgZ\]^`n|*C\niP8 xd^WPJRZbj~*BZs~jV;zl_RSTUVfv.Hctw`H1|ic^XRZbks/E[qq^J2rdVWXYZix.Harv`I2mga[U^fnw*=PdwrbQ:" }pddeffs/EVhzlWB-tld]U[bhn1H`x~lZ@& tfWVVVUds-Hbrs^H2~jc\VOYblv2G\qoZF,|rh]_bdfv3Jao|thR<%tqnlit~ 5DTdsyzueUE5 ~ .AS]gq{zzzyoe[QB2"{ />M\cjpwusqof\RI8&~} .=LZipw~{vq`P@/~wz~ .ATanz~reYD/usqomw #9J[l}kXD0|sjbfkpt-BWlxn]L6xkkjjjx(>Ucrzm`L8%~zvs|+:JZipw~|wrdVI;(%5BO\imptxrle_QD6(&8JU`lwvtrqh_VM>/ #4DTemv~|xj\OA,srrrq~ "7M]l|{pZD/qkf`Zclt}.DZo{hTA(}rh]RX^ci{0F\s~vgX@'~pbbbaao~'>VdrujVC0|yvrox,=N`jt~~paRD0 #4@LYehlpsmga[N@3&,;FPZehknqjd]VG8) .?PZepzyxvuj_TI9) zu}3EVhz{tdTD4 zodfhjl|*@Vmyzm_H0{jYYYYYgv #:Rbr|fO8"|id_ZU`ju 8J]pp]J7 vmdinty&:M`jtreXJ6# ,8ER^bfkokhd`VK@6&#3=GQ[^`cfb^YUJ>2'$4DMV^gjmpsmga[L<, }w}#5HZlu~tdSC-uhijjkx,D\l|qcL4xgda^[ht6O_n~|s_L8$ vqlgbkt~*<M^px}l\L;&{~"4FR^iuvwxyndZO>- !-8DPTX]a^ZWTJ@7-  #.9DOSVZ^ZWTPG>4++5?ISW\`da^[XL@3'$4DP]jvxyz|sj`WE2 ~zvrnx&<M^n}ubN;(~xrmgov~':L^qyp_N=&zqglpty':NbmxxiZL6twz|"4FR^kwxyz{pdXM;* '2>ITVY\^YTNI>4)#-27<ABBBC>:61*"  #+3;>BFIFDA>6-$ $1:DNWZ\^aZTNG9+ +9GUcipv|vqlfVF7'zrw|(;N`s{|l[J:" ypfjotx,@Tit~zj[L5zpruxz%8KXerzncXD/(8CNZegjlnf_XPA2#(3>CHLQOLJH@81)   (-26;<<=>;852,% ,4<DLPTW[WTPLA6*"4EVhpx~{kZJ:$ zpfjotx,AVkwscS: xk^_`abr2Kdtp`H0ufdb`^kx #<Uev|n`J4}{xvt(<HUbnpsvxph_WH:, (2=BFKPNLJHA:3,$  ")-159:<>?=;970( ,8ER^adhkd\TM@2%&8J[mu|~zk\N?*}pcfilo,AVlwteV>% tgY\^`ct #:Qhv|m^F.p`````n}*BYgv|obL6 zzzyy!4BP_mpsvypg^UF7( &0:?DHMLJHG@:4-" &.6=@BDGD@=:3,$ *6BNZ_dhmhb]XJ=0"| !3EWirz~pbSE0zl^adhk|*AXo{{k[B)sdUWXZ\m~ 8PhvrcJ0rdeffgu%<R_lzti]I5! 0<HUacfhjc\TM@2$  !+048=;:862-($ %+17=>@AB>;84*  &4BOW^fnljhfZNA5"|~ 6Kan{tdU=&|n```__o~6OhxrbH.xiZ[\\]l{0JdtvfL2}n`````o~'?Wgw}oaJ4%7CO[gjlnqh`XO@2$ &/7:<?B?<:70(!  !#&(*+,-.+(%" $0=ELT\\\[[RJA8* $7JWdq~~rg\H3 oljher~ 8Pbs~r[D,ta^ZVS`n{ ;Vhyu_H2xeb`]Zgt/FVfw{q\H3~{xvs|2BRcsx|}tlcQ?- &2=ILPTWRNJE<2(    %,4;BBCDD>70*  .;HUbfjnrkd^WG8(~x 7HYj{xp^L:(yrjbjr{3G[op\H3xphaYajrz4H\plXE2}vnfmt{-?QcuzzrjYH6% '4@LPUZ^YTNI>4)  !$'&&%$!   &,.035420/(! "/<JQX`geca_TJ@5$ 4I^ju{m_Q9" yl`behj{ $<Tkz~n]B' reWY\^`q ";Tlzo^D*}pcdfghw-DZhvsfXC.~~~}} 3FQ\fqpppodZPE6' "(/6<<<;;72.*$  !$$%&&$"  %19BJRSTVWPIB;.! -?KXdpsvy|sjbYH6${wtplw0FVfvzpZC,~mjhfcnz0HYj{~s\F/uspnlv(>N^ozoeP<(!4AN[hjlmof\RI;,$,4;<=>?:61,$    (16:?DB@?=6.'  "1@NV]dljhecWJ>2 ~0CVhqz~zjYH8! |sjpv{%9Nbvn[H4|unfnv},?RexwcP<(~yt| 1@N]lptw{rjbYG6$,4=FNNOPPG>6-!"$&'"   "+049><:86.& #0<IVZ^cgb\VQB3$ 4IVcp}~~th\P<(uttts0F\jx}n_P8! |qsvxz$9Nbmx}l\L;%y~#3CScintzslf_P@1" (1:DMNOPQJC<5*  !$(+(&$!    "*135794.(#$1?HR[dcb`_RF:-+:IXgnu|}vpjXF5# |xsnx+AQbr|qfP:%pnmljw)@XfttfW@*stuvw0DYdp{|xj[L>*!0>LQV\a\XTOB5( #)06<:986.'  $'*.1.,*'  %3<FOXXYZZQH?6&$6HZclv|xurbSD4 wnty~(;Nbu}|iVC0xrlenw 7HZk|vnZG4 }xtoy,AN\jwz|xncYG5#(9CNXbba``VMD:,  (+.2520-*$   "',,,,,&!,8CNRVY]VPJC4& 0CP^kxyz{|peZN9$vwxyz 3H\huzj[K4|rhlptx)>ShtubP>& yqw| !3FXjqxxpiXF5$*6CP\^`bdZQH>0!!+/26:8631)!   "()*+,($!  *4?EJPVSPMJ?4) -;IWeinrvnf_WF4#~{ 5KYgu|pdWA+~qrrrs2I_lxwhXH0{rvz}-BVjrz~xq_N<*,:GTbehlog`XP@0! -5<DLKJJIA80( "(((''"  "$%'# %,3:<>@B=82-" !.<IPX_fc`\YL>1$ 3CScsw|{ri`M:'}yuq{6O^n}th[F0sqomkx,BYfsxj\N8" svxz}&9L^fnw{vrn`QB4! +8ERVZ^b\VPJ=0$  "(-287665.("    "&*-+*(&  &3;CKSRRRQH@7. %6HYbjr{wsok\N@1x}+=N`ryxq^L9&}wqkt}$;L\l}|riUA-|zwtr}0ER^kxyz|}rg\Q>,"1@HQZb`_^\RH=3#"+47:<?;73/&     "# $,5>BEHLGB=8, -=HS^iklnpf[PF3 !6J_jup_N>(|svz~.BVjs|ziXF5xpw~'9J\ntzxpiWF4" .:GT`bdgiaYQI:,(.5<BA@?>6.'     %07>ELJHFD:/$ '4BO\`ejnhaZTE6'*=JXfsvy|uj`VB.~}||{,AVbnzvhZL6! twz}#4FW`ir{xurobTG:& &2>JNSX\XTOK?3' %*0666772-(#     $'%#!  #.5<DKJJIH@7.& )8GV]djqlgb]N@2# 3DTev|zpgS?+~zvs}3JXgv}pdXD0{{zzz(<P]jv~paRD/"1@OU\bhd_ZVI<.! (08@ABBC<4-&  !"""#   #! $-58<@C@<85*  +:DNWabbbcYND:)"3DT]fpyvtqn`QB4 |*;L\msy~vngTB0|(<IVcprstvlbYO>, !0>FNV^\ZYWMB8.$-58;>A=840'  !#%'$   "&%$"!   *06<BA@>=5.&%0;FQTWZ]WRLF8* .@LXcoopppeZPE3  0CU_hr|yvro`RD5! $3BQ`flqwqjd^N>. 0;FQ\^_`bYPG>/ &16:?DB@=;2*! #&*.,*'%!')*,.*&!   )2:=@CFA<83($1?GNV^\ZYWLB7, &5DTchmrwph`YI:*%8FTaortwzpf\R@. %7IR\fonlkj^RF:($1>LQV\a\VQL@3& $+29@@@??82+$ !&&&&&"   "$'%"  $.38=B@=:8.$ .7@JSTUVWOF>6( ,;KS\dljgdbUH</ .>M\bipvpkf`P@0 "3>JVacfhjbZRJ:* *8@HOWVUTSI@6, $,469<>:61-$  $&()+&" !%%$$$ %*/4988870)"*5@KNRUXRLE?3' *:DMV```aaXOF=- ,<LT]fnlifdXL?3! -:GTY^bgb\WRE8* "1:BJSSSSSKC;3&  *48<@D@<84,$ LISTBINFOISFT5GoldWave (C) Chris S. Craig, http://www.goldwave.compsi-0.14/sound/send.wav0000644000175000017500000016653611305557613013162 0ustar janjanRIFFVWAVEfmt DXdata  $530.,uj^SH\p2Kd>VP7]4 \VsoB"0=JXp`5 J uI*;Gx|Y10V>4#Ito8j!Df qao: !*4i>H|zd_[]^`bM:&6RmN\8 `qudD2  #0*~zvF8Z|Z>vI;XXXXX"e@ 6s2v<ZxU2r~PM]XK*a=S@-ff-6?HQ2Nr[q  86{,d:tll`4\JR}IJLMNU\.%J9vmd/ c  ?HPXa$kwhsr.]N6ilptw :8 rv{L(t-swz~5Qx]@f ; f F^<dO2.Bd\N>|_BW(O347klllm @ w L ! v rSc0iI6"sFP[fp7?8b(]3;BJRdv_$ G j R : N b w  h < Ok"$%&(oRt08@-HG<~\:2Nj(la'~E  f u L # HT$W~'Zn8P3p3Lf:6DG[i {4Ec3QZ}[ 2 X  & s  \X:rI@&oE%l?.IdBJOU$-fhwL!~6 M z  p  Tri82:!h=l_RTV >T@`KS~4H$6  5 V $ 3 &Z>?gTXlp Gw@ V2\`c,5F4vE*@ W  O M L J H t .H0<x-sGt_'41FZNj.g9HH\"7G  T o P 0  9 b|/Dp(D*Xz sIJ,"7|>7o e.p V 3 A N \ j  j  f:Z(XB*w)F b 4 E ]-xiQ`dM(7, `}Y5d*V\pZ  # ? 6 . &  1 ceY?(b<c(Q e^, (6Dcf PPhd,.j KX3 Z ' e4d8 8d.fid^u'/ |EMU&xX8<_|  {  Y ( to[7U#A_}0ZK$EZ $0\*6ALT LJM @j_T. 6 f f F  -\B-Gg*`uZ`j|h4y/>&`/R vR-T, f h M 1 l+}&+>YeP z\h7zu]KO=+j)xqp!30,-; x \ ? "  a*BW~$x(@&r#|g 8~"b!$&lVFX BUL a W N D : y9>eYjb%cWB,,%xo.)e"Y%m{C3:z; > @ B E  ~<&IJ]JXje,R :8/F XX qJF5W9+h! 1 B R b  u&rDLV9Trl3_$t=i+J:k"H,q\7*~(g# : R j : cMqt@!uq$~5KHDQ"VMsw]>*r]JIV" 2 C T d ' qJbV$xiH l,DNX"V*\X7t$Zr-nO{ 1 B h6U_Ei-o'M*p.jL. `F"u(CHXjAr  $ 4 D  )DWcT* D~H\:DhN4J$j{7Fw1RD5` :SaT**t_zl`Tw sfYL?=;97y?/%+*=;h$ 3Y~j-.,(<&z! y;vbN;72.*e">q m6d;2* Cp|]>!:)ruj SlVAHPW^>6/BVl%6rnN1kmQ54Z@(HM'''6F(u 6_B&Hi FND`I$W$ie`\X7B10 pL(2lOR'8_`;BHOV\VRgKMNPR4VNI>,bL e(U8]6z )Km-q ~H WBFKPT3PVd^B%u0PBx`,5c>t8\*h RTWw"n&1 b+T~L+\&WJeBZ#2c2Vd"X|@|:Yl L2S. @Y'pGX-[HXN}>K PbdU>_.G.r(M)L%o6i@! ,^hZGJ RZH_>Rg.b8J+n4`@!Xk F&pB[$pso,r6TdfDL|2Q|9\RVE$v,HW0j. }R&$!9V$ #V Zb9q4=),/lD pSLE\|K2U`f5-P|Kh( f$d<WWco.[:"rXPh8" @pFOv 1fKXd|~6sNrZ_d4l; vl\~S@.,QvHZ$@y:^m|cJ^Zm EiV|9 yIyUI<0$@\wB[. 1)FcXLT\8\#IXhL0Z7(&.L|dYNC8Mbx4Dvm @r4CRJA,{i.@bp]lB9>Qs = ncXNCVj}(u2lT ]I:,cv_06jlmhd*bHG`@ c\TMFR^kwN hZL{I&6F#VWviF#YO vNJf L=:62/DYn3ncXSNn4*4=S j`8TMVLc(b"b^ZVRfzXz_PAe+ns=Fhh@@ c1keFs0e]UME^vL_;RhtR5n/9_~R'|'~|zyxcN"|^i'p_{ G+lll{Cb|j0.}8np_/Y   {L>]PPwf3b}<_2TN g>mbWLAT }[J8Fn*|Q"CFIJJbz 4-`6}"Y\`dg6`$EN>66\[Z] {4j/p2*"nQ| *8 ;iD\P@/1FMEXQ1LVH2*81)*,P3^#x/SGnldVVdln-l6lG"TdXvc n[OpAlHoZ wpv+UDv[@$$%&&a`Eycipyyq]<V)R|H]Ex( "8n i.jPLHEApVZvPGSvvR,l2$NyGXC2 2`h raQRRRSy@AlG78ING+bn!Nzx3cK SD61,WM^wwvvvZ a}H";B0 r=^"Up_Na9l-4:4.X&kt&/o3d='! S$~1&Y]aeibZRKq :tXdqdVK5L[>k:yzzLk"~0kqv|mXB-b X&Lf~}6objL&Z1wmdZ.Z a8DOZfVE4$eE}Em6j]z. b8xN" CR:v(4@LXA*rCL,`x#6P(u,S)4u8c6rdTE;%^ .AT>)UK"R{(1AX2>tG8Z G_0nSH<;O !6L5Y'F*Zn1Nj<>zM "Hm"^ b*fK.am @x,D/b3V 0Sy 4`ut=H c6DoXOtO*fP V"Z2T;" \*f$Kr ,\ %^\ zLAh7CtL$ ~bBU&T0tEV6Wx3j-p}H|KPqV8 n1>:ptIJ[Fm$H~O>k[K;+;JZj"_GN~lN%Tt12h~uL$O^ Q'@Z ^Q^ pbSD6DRaoN4:gN0~@Z]Nf~lJ(Zt"h+Fa8w^ ik]N@2?LZg;4@kP7GV eUh{~`C%W`L$Cb&`Ljuj`VKYhv$YFTT. y>VL9TohJ,Wf[:HV^[ l{ws}1cZWh5 {[nr]$>XsoT8\shA_}4w&:X*} :iTJVhN lqX8VtcF( @K@0On.u&DvG:^XZp'hM lb9x6Tsg[OC$\%@4| cDjx8T#'Jm2t2SL~IQ*`Ah^TJ@ d4RD7&`!rFa-'JlPN h#@i93|.c<60*$X.db>5xG+Nh5 CfRDOb+X!$s%V$).38f: p"v]O L;b#|G-T|G}4EUr8k XO)-048b3jvcB\NbzO$*OtW>?Mu5KFK % NRf_8tM[ }6tJ6! Fr:q8+R jpns,i ~J\|$sE786QbN:&?bR$pw1ShmdWx N`0%ePCh(HSQ>AXPs\WRMHe'\[JR efbAz:bZ0d'T bISh|tfX8j3`u&.vx(Vh1w|;aH0+~&xm ]&b$Qcv~qcC#r:fv"z(4/Jh>@iZ=. tqbS&<RipbSD$^*^u$0ktJ N=cLw8|P$hG>4*!0@P_z0bb6~Z6} E~AjnU,q3t1h$XPyLsj`VMV_hqDu)j7|Y8Cv'Lrv\Ad/?v2g"[n?dZQH>JVamQ;| T3zG>u(IkxpXA)Oi.v3j&a&Q"xl_S\fpy5fA~BU#f$Z *K\nx`G.T"D6d$j.\.znbr -YP R$g"X*^*:JZjfc`\F1Ow6u5{@NtD2^V OMD,b,>PbdfikWB.p@t:<v8NZ.0]J|0q9|5p >o&<SjjjiiT?*\*H FJ^$d8(Py>w.m)h \9n 0CDDDE5$wDv>TZn6W;9bG}(b a#c,Z|$:::;;)xL Wh(n0~E T41Z Cy.n&aG$[~ .1469+T"Rx@@OeF(  8bJ$[K9t'Nu $'*tJ\$t8F i4`B# "8Mv#T!V>zEu.X  W(\'F Pm6 iL06NtBq By3qS 1Vz%1$ W.s> DN}KsX< $8Kn2`:s$_4g(Py  a8Jd)y>_2nQ4& )>a Kv"[PBu 1Tx  gBtD[j.k=tS3&  ,=No-[/fK*[BktL$j5c/SmAcE6( )8Hm 8f,^<u!R.Sxz_7mDK^-oF^M<+ "3DUf 4`$W6j4` 4]vu_=uDt@{FxJq^L:'%$" 1BSd 3]#W+b5b&H`xp[6pDZ#}J[0s`N<840,TjvbN0{MNU"`3paQMJFBP]jx 3Y?tEv6d,BXmvcO0|P$_+\)pE|l[XVTQ^ly<`H{Dt2a"8NcyxdP=lBR#f6xK}olifcoz+RxHw7j(T ":SlxvbO;pH!k8n= _6rmhd_mz"Gl"R8hKw6Ngr}|jXE3b9`/n@tO0 2W|"Mz2`?j.DQ^lytojeSA/X.Y,uF{W; 6XzBp&T*Su "9DP[fc`^[N@2% lFp@P!]?" *Ih :h%X8b1LV`kunhb[J9(c<Z/W*bE( 8[~It&V1Zz ":@GNTPKFB5( tN(oB`4|^?  #Cc?kL{"Kl,8CNZWTRO>, |X4]/|R(`@ Ad&O|.X Fl)06<CBBA@0 kH%`6 b8 t[B)(Gf?l Mz!Ji&0;EB>:7&lL, g9 f@lN0&8Ur$Lx$Lu7Wx &/-*(& lH$g@rGfL2 %:Xv"Go?j 3Qp#-,,+* iK-yN$zO%fI, 2Nj(*Gd 0Ty:b#Df`<Z0`7nS7%(:Wt )Nt=g8Vs  bB"g?rH'pU?("/F]td={T0 rWH8( %4B\u%Hk*Rx (Gf| pW>%qL&nM, zeP:%$4DVi|,U~Ce8]x lQ6~Y4_8jWD14J`w Fk&Ox6Zr  x]BmH$^7yeP<(  .BVkAf-Sy +Mhx^C!qL(kF"jQ8 4Kbx$Hk)S~2Rl  hL+ zS,^7nXB- -F_xBf 4\3Sm ~eL*tM&fBiS='+?Rfz:_Ad8Rl|cJ* xP(kH%lYF3(",@Tg{<_El B\w v]D"rL'mJ&xbK4(*6H[n8_@d7Rnt[C$|W1gG'v_H>3($,5GZl~0Rs 1V|">ZwqX?#hEkI'kUG:, %.BVk%Fg 0Sv$A^zv]D&dBkI'u]E:/$ (/BTfy2Rs Fk3Le~|fP3uS/ zT/ycRB1 "*2DWj|"@_Bh"=Xst\E) nK&xY9v]RG<1/.,*18?FWhx7Y{:Z{8Rlt\C' qQ- zW4k^PC641.,28?EXl,Hd8\ &@Ynr^I+ qQ/ a?(qbRBCDDEINRVbny&Ed"Df5ObvlU>"uW6mJ.|n`QJD=6;@EJ\n %>Wy.V}0FZovgXH,zZ9uU:znaTPMJFLRX^kx&Ed8Vw #<N_p|kZ@% tR1^>vj]PJD>8>DJP_n} 'C_|Di,CVhzzhVD,`=uU: tdSRPNMWaku )Hf6Qo9JZk|p^L; |`C& eF( pa\VQLQV\ao~0Mi:Xx4EVgxveTB1{\=iM1p`\WRNTZagt *Fc *He8J\nudTD3pQ5mP4zriadhlo~6Rn9Xw0>LYgq|tgVD3"{^? pVL[aflrstuvng`XF5$jL/nT:! ztuvxy-D[z8Ys 3FXkrx~wph`N<+uZ= {bH.|wy|~)@Wn=]x):JZ`gntsrrqjd^WD2  ycG*lV?( $?Zt6Rl-@RY`gnnnnng`ZSD5&z`E*hP9! (B[t+Fb~ 0@JS\fhjlng`ZSD4%t[@% t]F/ 4Jax+E]v$3<ENWVTRQLHC>0#r[C*x`G/ )>Rf~8Rk$5?JT^\[ZXRMHB5(|gO6hR;* *@Uk/Id~*4>GQPONMID@<1&jT=&|fP>,$:Pey4Oj#0<HIJJKHFC@6,!gR=(~hQ?. +@Ul+F`z$0<HMRW\XTOK?3' zbI0hP>, .>Xq-Hb| +6BMRVZ_YSMG<0% iN4{bL5-A\x(AZs&,3:@FLRXVSPNB7, pYB,wZC,$8Kc{.Hb{#/;GMRX^WPHA6*kR8pV@* 5Jc|,BYp  (08@EJPUSQOMB6+ lT;# pWA+&8Kcz)B[t(4?FMT[WSOK=0"lO2wcK4(8Haz0CVj&09>DINMLJI=1% qW=# }gR>)"2AXp $;Ri!*38>DIIJJJ>1$ |`D)u]F. .?Th}.G`t&1468;=@BD<4+#kT=!nZF1 0AVl2Lg|*6;@DIHGFE<2) ~fO8r\F1 -AXn0Jcy (5CEGIKLLLME>6.ydN9 lXD1"5HYj{ 'B]p$38>DIGDB@92+$nYD( wfUD3 &8Pg~(B\q %36:=@?>=<60)#r^J5q\F1 0CVh{ $@[p)2:BKHEB?80)"jT>% ~lZG5$)@Xo&?Yr +2:BIFDA>82,& mXB-s^J5& "4I^r2Ng",5>HD@;7.%t^I3xeR>/  %?Xr.C[r&-4<:875/("xbL7" fK1$ 1EYm7Ph ",78:;<3*  |fQ9" p\H7& "/DXl"7K`t"(../00*$ t]F0t`K:* *9L`s2I`v#(.381*"}hR;$ r^I:,*6H[n 4H[n $%&'("|fP9" |hSB0*6HZk} 2H_u "& t_I4xdOB5( (3>LZiw*=Pcv   s_K6 p^N>/  $0=M^n~&9L`s   p_H2{fTB1-*r`UJ?4( $2?L\l{-?Qcu|jWD0p`TH=1'  #/;GSfx&:OdxxhWF4#tbVK@4*  '6DRbr,BWl  xdO;)rbUH;.# $.9DN`s *=Pdwo\J8'taTHHQZix .@Qcq}m\L<. wk_SKC;3.*% "$&(,037AJT^n}%6HYhvugYK;+ uj^RJB91+& &-482-''&&&.5BFKRY`gs (5CRap~qdXK=. wjbZSKFB=876549>DIS^hr~"1@P[fq|zof\SJ:* |pf\SIEB>:::;;>BFIQZbjt~)6BN[htui^RF7( ymdZQHFC@>>>??BEHKU^hr| .;HT`lxwkaWMC4& sjbYPNLKIHHHGJMPS]gq{&3@NXblv}rg\RG<0# zrjaYVTROOOOOSVZ^gpy,9FQ\hs{zpf[PD9." vnf]ZXURRRSSVZ]`hov~ '6ENXbkrx~ulcWJ>2(xqjfb_[\]^_behkrx~*7BLWbipx~ulcXND9/&|umiea]`behjmprv{ $2<GR\cjpwzrj_TI>4* }vpib\^`acfjmpv{,8DP\cjqxxph\PE9/$|vpkf`abcdhlquz~ ,8DP\dkrz~xqjdYNB7,  zuqmiedcbafjnsz !+6@JU]dltx||vpjdZPE;0$ }ytplllmmrv{'2>IT\dltx|~zrjbZQH>5*  |yvxyz| +6@KT^gptx{}wqke^VNG<1&~zvqmnprsx| )4>IS]gquz~|wrlg`YRK?3' |zxtqnjjjkkqw}'1;ENXbkotx|~~ysnhb]XRMD;2)|xtroljjjiiotz &.6ALXcipv|~xrlfa[QH>4' ~zvqmkhfdddddjpv|%.8BLVakrx~xoh`YRI@6- ~xspmjghijkry #*06=FNV_hpx{umd\TJ?4*zvqpponnmllpty}%0;FPZelt||tj`WMB8.#|xsstttttuuy|&.7>FNU]emuy~ytnh`YRJB:1) ~&1:DMV]dlswz~zuph_VNG@92*!}zxvsvxz}  ,8?FNU\dkrx~zuqi`XPH@80' ~{xuwxz|~"+3;CKRZbinsx}~~~}|yvtqjb[TKB:1)"}zwvvvuvwxy~)2;DMTZ`gmrx~zvrlf_YPG>5,"|xyz{|!+4>GPW^elrw|~{xvutrjaXPF<2( )4>ITY^bglpty{~~}{wsokd]VOF>6-& *2;DLSZ`gmrx~~}zxurnjg`ZTME<4,# #,6@IOU[adhknpruwvtsrmhc^XSNH?6.% !*2:AINRV[_cgknqtwusqojfb]YUQMF>70& &0:DLSZbehlorvy|{zxwrmhc^YTOF<3*  '07>FMRX]behjmortvtsrpkfb]XRMHA:4-$ '.6>FNV^chmrtuvxwvutplie_YSME<4,# &.6>FNU\dgjmpqrrsttuvrmhd]VNG@92+# "+29@GNU\chmrwwvvvtsrpkfa\VPJD>70*! !*2;DLSZbfilpppqqrrstpmjf`ZSMF>70'  (.4:@GNU\`dgklnoponnmjfb_ZTNIC<60'   '.4<DKSWZ^bcddefhjkjjjic]WQKE?92+$   '.4;AHNTZ_djlorttsrroljgc^ZVOHB;2*" !(08>DKQW]cikmoqqrrrpnlje`ZUNF>70*#   (1:?DINSX^chlqvvvvvspliea]YRJC<4,%  "+4:@FLRX^dgjmpnligfdba^\YVNF=5.& "+4:?DJMPRUZ`ejjjiifda^ZWTPJD?92,% $+28?FLRY_cfjnmljihfdca`^\UNG@6-$   *4:AHNRUX\`dgklnopmjgd^XSMG@:4.("$*06<BHNSY\_bedba`]ZXUTRPOJFB=4,$  &.7@HQTWZ]^`abdfhjhfdb\WRLF@;50*$ #*16<BGLQV[^adgffedb`][WSOKFB=80(!  '.5<DKNPSVWXZ[]^`ba``_ZTOJFB=93,&  &-39?EINRVX[^`bdegd`\YUQMIFB?<4,#   &,3:@EJNSUVXZ[\]^]\\[XTQNHB<6.'   ")06=BFJOTX\acegifdb_\XTQLHC>70(! ")06=DINRWZ\^abbbccccc_[WSMGA;5.(" !)/4:@FMTZ]`cfffeedba`\YVRLGB<60*$ %+17?FNVX[^```__`abc`]ZWOG?71*$   (-28=CHNTWZ]`bcdfdba_[VRNID>92,& "',27<BHMQTX\]^_``_^^\YVTPLHD=6/("&.5<AFKPTX\`bdgihhgfc`]ZTNGA;4.( &-4;@DINRUX\^_`ba`^]ZWTQKE?92+$  !(.5:@EJNRW[\\]^]\\[XVTQLF@;4.(!   '.5<@EJNQTX[]^`b_\ZWTQNKFB>92*# %,3:=@DGKNRVXZ]_\ZXURNKHEB>;5.("&,37:>BFILPSVZ][ZXVSPNKHD@=82-(   $,37;?CFHJMORTVVVUURPNKHDA>82+%  "(/4:?DFHJLMNPQQRRRPNLJGD@=84/*#$*06<CIMPTXZ\_a``_^ZWTPLHD@:4/)!  "(/5:@FKNQTWXYZ[[ZZZXURPKF@;60+&  $*05:@EGIKMOPRTTUVVSPNKFB=82-(" %*.37;?CGKOSTTUVVUTTQNKHC>:5/)# #(,16:>CFJNQQPPPPPPPNLKID@;60+&   $(-159=BFKPQRTUUTTTRPOMHD?:4.'! #(,048=BHMOQSUTTSRQPONID?:2+$  #(,16:>BFJLORTTSRROLJGB>:5/)#  %+049>DINTUVXYWTRPNMLJGD@=60*#  "(/6:=@DFGHJLNOQPPONLJHFB>:61,&!  "&+.269<@DGHJLMLJHGEB@><;:83.*%  &+06;=>@BDGJLMNOPNKHFB>:61,'"  #(-27:=@CFILONNMLIFDA?=;94.(#  "',27:=@CEGIKLLMNLJHFB?<83.*%   &,/258;>BEHJMPPQRRPNKIFC@=940,%  #(.49<@CFGHHIJJKLJHGEA>:62-($  "',05:>ADHJLMOOPPPMJHEB>;840-)" #)/38<@CFJMNNOPPQRRPNMKFB>952.*#$(-26;@DHKOPPQRRQPPNMLJFB?;62.)" "(-16:>ADHKLNPQQQQQOMKID>83-("   $).26:>BFIMNNOPONNMJHEB>:73.)$   $(-159=ADHLOPPPQONLJHFCA=951,&!  &,26:>BEHJMNOPQONLJHFCA>;850+&!  #(.48<AEGHJLMNOPONLKHEB?<841+%  $+147:=?BDFILORPNMKGD@<:864.(#  &,37<@DFGHJLNPRRQPPNKHFB>;70*$ "(.37:>BEHJMOPRTRPOMID@<:853.("  ")049>BDEFHJKLNNNNNJGD@<840,'" !&,158<@BEHJJJJJJJJJFB>:62-)%"  #(-28=@BDGFDCBBBBB@?><84/+($   %*.38<?BDGIJLNNMLLIFC@<72.+($!  "&*-159=@DHKJJJIHGFEDB@?;840*$  $*.27;=?ACEFHJJIHHEB>;840-($   !%),/259=AEEEEEC@><;:9840-)$  LISTBINFOISFT5GoldWave (C) Chris S. Craig, http://www.goldwave.compsi-0.14/sound/ft_complete.wav0000644000175000017500000033367011305557613014525 0ustar janjanRIFFWAVEfmt DXdata  t: DUF  ?o CRnaHEvVsPL " !R?(fM~2C R # 7G4ZVJFw %^Y V  V C)w@zJ& vvq+.".8ZqN; + ` ^lW[9 {Jm)QU~qy>v Stw]WJ k :+kCKw@eQ@.46 uZB> 9M<~;u?K_, K m$n G I H $ 3 po$ s e Er?< rDg3eU[&#]$;{B fi }  ~ B a  ~VB%QUk&-.3k1d GP\N nk?JoEFP,hs4< IG' -Cq;9~ovc;-BD@t^/)2c`, ` w!! `[  f ] 1q=;k^ *<aV8 , r + n)  | x ) Lx7(R^kI65ML)Hr&)\NlWx&.Q#r*9?| dCU(pPT0$Q#[hW"`^3r\.vF=W!j  /U d ! e1g*8A52 !mDUMb'5  I s ?T  ( 3  g b  l *G]lf{{JiR67s:1YrLG}t92 &j`Y_ =3 SQIl_USBn;bhH $[Q+2  j  p n  , ;E1;vcD]0K(6nIWer: F eA @ O0mppI4i@C~axa5fqX3g$ Y&bn;TFr27\RZ3{^8d2hB:xb%z%s84N<p ^  # ,  e X \ G k 3CqN@ek"%( kcf x 7 + < E l - } _ $elRcM$Q00-J)7ot"Q#Y c?|l cV+.:3y/] ~xV *wp'`2} } Wz0dL!tgAD# 5 '\e = & Y z &suVH>=cv$7iBc=vi)@ " 1 ~ u +  # Z v j , * @hF,zZ9@05)~\ >B#ds7;1a^"o.UqkrrOa;*RIm4uc5(vpMVo|>]&&bJ6;pHcO/%4I13|b2  9 a # " F 4 uD={NY4x0U-[D[ Q  V y  r 'n,c }}_R?pJMAz;1 <Ar~C083@U*0 AY:q>[Z~ !9v9. w?)< u ' b w E  O `]+lw9g.z3*gqjp5X #  +  N / 6.X&o &DrJr#*wg!6xnjr{T8!MNLtq4&^d$R-,w14oF&RC{dX\o'!$"u:R5idF ? >   F 3{\a|LQ}+*( -:  | a ?  n % ?5D!o  3 -P $"-T:'kqG8veF5Se-r9M[qA4R*w_#e3.*u%Fl[mlxq9q7JSi C  ` g # 8 zt6-B{Q gbE/C   q \ 5 aSb2"o)Z6HVg(|t &/887-"f*^'V7=wDO*u=e MCL t xq5EPR:pn NX .   ! 9 T [ A > O  v5\A*Cso3Eo U V    d 2Pw2Qr1X[8FwHRw!MWHpA[rr(e8tuR"PYB+'&{l0l&0"*#R(M(&;Tr=PkRO ?    Y g 9 La#wwts1(2U G V u L  Qs128~: -j~Cq4Z^f3^a\(gOUDzAf-Q[ Mi7e-GH! Lsg 8qm@fA;C<B=` l $ U 6 " G z"jIAVU?0GMH > p  4  L=2o#)RVXT{ /93& 'TjlO9ROI&.W'l=Aanh[E,ZW^ R z a V ] r  7 [ a I  " `  SIb,C w+]3|)Gbp* t  ? M 1 j @w4vc@0Ur*DK  _h(OL ]tdrKrxcH."#3@Vmyh.`xf6G<'s? c5r3&b.tI n:'a "Rv^*Y%R-#icP iCy$w #SW 9 T 2 r z +   5 ADa*",235?FD;.-C~8 - l ! B @ % X ` }4v@R9DjI:Q!p7h'6;3( GMQ_@ >qK96=GaEO"c0ka;e{zdEf9h\TIB=MnH!Oi.X$ L $ d  [ ! + B WpT)`9H$ ]  N  B R Q B " Q E <1d7J>Nz9w_awGM Duq=0f0Rc9L_|<|flLO[91PPH_64+ \ f+8x]N:BL  w # l b * [  e  JhN%/@Uql W  "     + (  {  'cb'~ Go|*m+.SI,28Ms=l|] p r'zf"}UYo6mo=O#' uhw}d0i>Mg`>EzS9, %A|Ux |r< -]q p  E ;  Z ) { O  x)k6 P=F S  ! 2 : F Q S 7 P s Iu`,`p`1o!&T[+Lc[2]Z+bGb7;}:8|6[c912`3 U* | & Y s W  v N  # ^mt\f *=IC1 "@wG U > U V # r FQT;b6#//p{uV#NXZg~No)p1\3`/w.<_(Dth # o   Y ' { 6 @gUK>0*-@XYVa-d+ w / ]  R + v:[^#y^('i\:%#5be8n$iW,POZE?E[x V&j_y+HTu= !>m^;/R%t"I_eggcddbc`S@+ 3iLVQ|b`CC/g " = V \ J " rW> 5m  8 e  Q s :  N  /`7Q?;9Jz0rsfuR0[0SLu!p 6xot?fG`5 \'rM-@6}pu;JMOZiH&r$(k6Jai<    " / ; D H S a f U / l}|&`;  0 G _ i i e i z   k ( 1 /@!R)UDzOnF$eL.Q u1ikl Lm6Yg( 7gBt?v8i'nG9Qf}-Sx[MF/ =d} ">x , K a l p x ~ y s ` E -   zX0 :h 7 ` 4 a  0 F I @ : 6 $ u ; } Pka{sh`tdK j9 s\<M .bQ:|!=pQ5 %Do\2q,i]O:d2:B?CCFQf|+d(hORV[v82TP G v w Y = " kQE?5,4Mh} $ > \ z # O t    l  E H>McM$?cVU{wrfSF@0 fX ?qA;eZ7 t_^p$|5!O!}9(e!Uzv|/qBv-hF-Em)]-k P w ] E : -    [D-$>b  8 a Q  $ $   _  %:qt@ZZVr{;oYLCENT\[F&\``pff>W?2:PuS~5c4 |Em-[}hWIQq >h-bs,3(*'S7e1d ? x [  zmqpaE) /X 9 g  d , M r j N = 2 *  W  V$f*&tcu)Ay.xvq* S*{=S,+C wf`U4.ygMEH1u&?c/e*T?,TldOrX@l @ s { U $ b.N 4 P h }  Z Z  \5Fp}dsA5+-JS?xbF!i'2op IMV|'{M,*_?T.y=te@qO* 1ZJ?9&( 1;xM ; Z q w o s h F  aOU_w F p ' f y p l l k Z G * L kmV9#DI`EuW>0.5;>6$ Xov!<3g/,{]D(!W"y*{gB<Cg Kj =r%s8%%2%v\B8RPO; q e C   = W i x F " m ~ S )  n > 6 j J.A`gUYo-n>^; Fn)R5?Zsu{}gD+Je|0ou5g"V>1Kn)/,3Kq+y|5#|$w(|# {  @ X ] O ? -  q Q /  3 K J @ 3 : I ^ r  O y ? ; )l@6mPQDv Mn>(!!#iI;:9( R_*O%D_m:d=! +d Wf|6?9{#fNB?70,8R~9,o2d3c26m5?F<."(8UFPMI-Liu6q) ^   y d S A  h[Y\r G n  ! F r u Y C ? ; 5 ! G o <<!B/3i Z }jJ$tX8 f,zI-S\m< {px6e Dr=(E;y1i-MZ[WTRbwO zCeLom Kd'yhTH #  [ -  dJIR^]K55Dh$ r > a r y s f ] [ \ b h d A x @  .:$h#O%jp,|j^K1#4W[(` t.0c\\i>Lk VW1{Gz:s?r %(/C^P1&kQHd  UC1 q  <S h[ lqDBq9 9  ^ 1wr ^F j4Y  ! - 5 jXq,U4Tk, "PCZvgBNb!P_CN~D986 /8yk:K0j`2w=LY 47m|Z,&j<9 T igu0A(  Ms | _  ~   P : $ .jk I 1  D&v 3 i@9j_Mj)3$vieK P a}zq>A+YK?x|%j% d)>|Y7KE,6m| <wJ;\v; @ z U ? I & < ?B~meZS   I + \ c  8`X?B @  Zl|]Bi 4r5i)0mGb#c%n5qd=]kG+2=m* STEmlqf] 2cw>oPM^ZJ/LhTh K8y" _ , G  H4/PDJX h + O  7 8 ;$c b@\M)HMk: B8W}, f7~d)@8UfAVYmh"Y=#6a=[|;aD`y0f5  Wq @~_Zqs  7 q A  _  @ 5 cI%+:}OO G  < 5 e gD0m#+rWOd).-DJ:' ');!k -`E}]p48L @*pEc"]qT9bf$W7B[ b>^kz3'5*)Wb\_7r{kx8\_F0&v#;e zM+b%Q9 > $  A s d % O ,z<.An4Bq|<2V=_Jo:Cu=F{M"e90FufO~qS8]U#bTbcK+6W,^~('b. *cNL<J -laHTM z 3 W  % !     i @ u 1  6 g g T Vwe_[VHC3O*hz&g2B]?ODjt_;w)X vmehS :8W^"zDM&4hRj4!:Eud`}-TUQWz & P r  _ " > V S <  ,  qA/~cY `    _ V : ^ < 8}n 3.g+h8 1amF 8g.u&t'd,}bOH~H#  ,D^QVf2o^:QjyAVi)2|Eo9jhM` \  I y h C  a ) )  L-c5":YyK~:STJHZy2EvHAh?Nr"k oWRVo.v>s'eK8jT5ivZ$TZp/f ~MrWM[(s$B+nr.9_CIme/95H!]q= aYb^ 2Y 8i ;7vDe[*u0-Te2 EX9EX8Ypr ?Oi#|1qUa:5o0f$ff\ M2Yu~oaVD+Ct]/o=~ 5i*' =  >jRL=g}Q#M}]K?==GLTj$ v Um,S %<9g6#:d.bL $YW6X jS8!!:j!:ij& (53) z-n KWU~Q whinTBr]@:A+A^o8)Tu^OA/\MMS0?/H ~&Oafl 8 _ u { i I   h2\ 7[ F s y q p s x    #  _b1GAnyC Fn~pibU6 _}&dY_UvAW,%>q0Xx4bR2NeneN7'&i&agZB {<Q Q|/Hb*Mg1iD_ P|iT/l!z_smxbG,LS)Xf%{EAk ;Xr}~s`E+ T(T kQ+;m? f5SK8Ut<_FACEEN[m#X e_81z%K[YPB/  9N1No 0Rn~trQ rrT6# !8Og}"9QnlS+_$wCoWNJPXr>g4LdxwoZBgA|F#=Wt3H]sEjt5SM a@% 3Os1sN,o4CIC7'{FoXG=1.4Fa9s"[*rw-0Og}xU&k6 "?NKA95>RtT+f=evG\v@d,7~N'sD /BG>720!z6}'-S&QvK1%Du@b7g[OC-fBxeA4,j&gY#In@tTl,+A  $   _ :  WU.~Z0 +0, PdSx  :mAvz{ywm`UE=AIS]dY;k7OZu(YPPRRQT`o*i|bJup&Kix}z{Gs%BlPhIRltVb*Ut 2HRPH7  )EMH=<@Xv / ? M W W Y Z Y M ) o0[Gd^Mv,l7 wnkebV9 `;zi.xbm9h]crfEy;e~afJqx'Bj +Lo&=DE7-# ")8FQQK.+zGc:gF^ifO/ x^?FsWoU-sR99?Vr}f?^?QMq9u"?e05Uka<)/@R[P4 W9005Ku3^>g(y:Wf} 2zg0!L|Mr|]@yJ s3~Y4 %7Y>o ^BRCc5  :Ui7m0FZlzzp\I7" k/o> 2Ic%[<\{gDdN>1)#+3AXw .4<B?85)QU0 vr?x & g%]   G3V1# {JkCl4K |}Y7#p7s[>m !*8Li<jL>FI=4N\gwv`X]v('jL%c1OOe j'uQ5z@r\C(~F Tl3JuAuu -Rp6Rh}shdZRB=E^}+Yn*(J h]["Q  !;Pk~6yFu +PnsQ-[/Te"k:]4_+j?Io&\3lle\[^ge]:1GZqymtPC}wJalzR   #4<AALZo>A  7W}Aj}5 !$ ^#'y0c5N8RcmfaeyM3EIEB?Jcx}mS.u5$h?Q\lqS}kjm7nXEDOl2DXs *;=+oU9&G|YUemgI&x0FW\L@-`5 $1:DQ^^``lZ~\SVd}EM5T(LjxZ9b'qM::Lax|kYIAEXxDul$0k.]bz9nVJ::=Le:]w{V%]:lH*7^ ;xI)lDq&?Uet$1Hb{9f-Z0Ro=dx}spqf_[cmrmdS@% }l\J7"pGJwDfZ:%j5bF7-{\/p(o?w[: !=b T=2c"5:IZgiozyl_^mWHE;g&z;n ",( sR. try 0Z eDz/:il`cB y`N?1& d8|Mk@{j_Y_q|0IbmwCh&:J^u,YJ)s+gAr =d 4Mahe]Y[bn 3X?f,BWey=f=WqO(cH'*664 wcP:C|PuM 3~A1Lt90=KOWgwQ>}-C)_Vs 1CJIIQbz;e/DMNMRe_-h;u1{cI0~rZ7g:g*l>$&4M`rrgR>,*7F_pN00Rz!u&h$[!U{tU2  "Px/p3FOFBBJUbq~Tr&k<=A 2e?NNF>7,!V;dG0miv 6\z&Z/Odr(Qm}I| (Fh~Z9 +BML< /RolR:,dE' {U(~F rS8+"}/^9jSJKN[mV)d&Pq5_v}voju{|lO+Do/zi=vP$l$GZ_\O:"oB|bD$4TvwdVODEEC(j8M =\pD rR3tflnxr[<]K@3)"#%$ ,>KThw*Ml=a&Fl9d"W< 5] =i !,3ALKC1%=OaoGj #0/" hEB*~6U O cD*cB^ r9[ w6uqbXNKJQj N>eK  4PsFw&n ` b_1\<PZTJ:.)1?VngE' R`F%LX:)B~B|P'}WA1& xu~Z#`9sH?Q~'&   Ugb;-;e"~jh  E<$P}kk`hW v 5&9Zf"+__:?H'v ;xPjZDqQ{E]$|vY~)MuO]cm B+dk`puoDF!|)6mOL?6R:M,N |wi{Vw.&,\KV]q(noaIY;u s`T_L5zk] ZBP^B@6w`s=ER@Gc72c. nd,n1wcWY,M!C__ .y >.D L2OE^Ipam@!`<.S|q  @ ^ 9 'q4}I.ZM?z <f`LKFSSscfBcMdR`0pYS"&oL +gsBFjV)W# sulL}k3>" "Rq*">j ag[oRnK >z%gs=Su*lG >nwM!.XZmyAKa!g,J s*)RVig=5nxa3j%iiYiFj]*!]{|2f!(9vE-'ZN%^Jnopd  bQ\yz,#QOUA, <8 R 8el/p6e{ !HMQbf6)=wPbOfC=`p 44?_U`- P.\5*LSO_8u@i#sY`m'2 [wQe9a' z#an8W3uLwD&u$d8Om pqS +w3Q QC,VW!a%9gSIpR&++"|# `Mi+w; x0}-o<mkaM `SO1rKKyO+w0jGLRQ3 bDQ&-v  j:hplW8OR !!,5=1,?UdcEe&^Zo@K~%zOq"' L y6pIXM^jCu5V]B!?OTH;7*V{.9 y g  k0i6;.f p"j9ya>s&m"PsX%-Tl]<   =qHe)t; p> K<=; %_d">_h>b[f|C>} f!uh`M2((38=GRM4%U/#LGNoT   }yojv>SWI_'`,f }3O*_Y!aviKz"y&\>45HY`\adiw O}KN 1GQ`sDCypn5u#Y-_$*Y"~:yX_#+L)aq6iM_JkN;EiC! 9'9dPf:B+o &XsUKZlP`?$` WsD*k'u(&t(yZ-=L\gbdebO&CZGN>SX@ pBW.Mvo{LuG2DC6, Z-|: 8z~2gDbICu/oC[6!"<e)Is)D+)}1y*8<#X*@;vAmj;U -YUT_7r?*BG5i$6GZ6Ki 9&|b6ln4<D;jWOGOXp<m=qQ#` y+=P# 8]6Yk6KH~JfC6Ehe]d$^Mzp? qE  -RB8(V3[x|kWIA,u.-mN6 :j V"_CHC]+b7 8q;~a!zFa3 kOFY~ 0FH(-~GomM+xQ($>clA)oR]l+ W _ C  u:X#|>e8 R 3YtzZ yUJUxAt 0FND6$e(wo Du~3mWP0e6F[q/~'!@O*491:520%v5sjp}u\F?Jddl]dv2e nO#  6Z{tV4WV*vIk=s>/K~A}@iop z#cnD )[BLd'x"7x.TiX?/Y5rg|=&YORz"<m3YpC36I[m$Mxq2tzKA&_C*!$:]I1CdeoE)pg%_enh[*)Jap{xr^F$g7 "Hr&R  C}LmyPK f> CNfjaL<4)##&1@`:F;E}cF*@lf@f^J8~h<oQ;( $3Ov/vE`s^%Kv!6`}kgjz9[vykK#@U&1P| ?nSTdVCKNtsB hfvF.UAAO.gxB vvy{~f,eIEt./4g0X2 7QlvU3M_~ w3Q;BRsQ\=f}haYU[YL)d<)! 9E Kzu*Mrr:q= *Kj\Qj.h,O~ GeP<2?f9kEC:{+|bRA8;Pz Y,s~=*G`zo<j/j ;kdF*L}QwK)G=g }M_oNNz]MNWhwKeAc*6H |EFt]NNTSA).P&Dq*?YrXx;mJ, .94*7fCfg@pnotjVPSQXfoiIv8{9HzeWNHZz#n!RW&(# #%'5Rp Q9nd:2JfRxnZL@33=WzsV,u.Z!ib/XrN?D\|mQ9 `.MMp[]nZ*Y E,l3jk[[`p KV?Hj.}:Xkys[E54;Mae\F60("  $p:O]Ez#Fr@zNr0KGV)&d}HG|.Y{  &V SUf;V [=drtsdF%uL&&Flgz,t;z'b dMA>DA0vY&PUY T%>f^>T 9S~Q yjy  i5e$K]oz}`B8LYlO2L<n2{A {j\XUJ5% c@p\hze^Z[m+WE| .fdC!b=2;Z#Q3KYdu^J9*mW 7Vca^^enwqQ%)Qv)44"xZ=Yd*qB`; eO9% z4\^5 %Ji|O8J`*+z&ZL#y"vX1s<NPB- uT6 #&5Y(2-kK5 T JMk2wo_F#Y%4d1 1U8l)b(Ll~n[B7," *1;KkG t(:0x3bnY@& zQ. !&!'-6=FZshH( Xw)b'k.}H`1 tBmO=62& 9V{ Bx$9Kbx;Zjyungikptr{'b D7Q!@]|qQ@432#vWB:=FQanu~@HXT v.d>lI227Jez|qR1 h8={dWLIFOZi~Mx>*Ih OF|te+~!t~-ZsqW0i\J*}?]tR bu@J~*c)qI/&)4=7* v;uC[5 L{ :i&Hj #,338?QlKq<6^:HHh2DXchf`M'[*B~%{)f3Z%|mX:])h8p7l2 3j?b*18CVesxqz6l;NuB eCx>OY\N3 2\ 3Yl!kr!L>k2Z@- yKj40HiG.%/DdDtA~  " !8Mw9O oDM2Hc|ysiaP9 N}Do  k1ZIGo5rG)   x^@! j;}> yi_WVbo5k  9k3[(};: I1=EIRYXH<'([3I\y{<@c0z9SvX?/1CD=1$%P~I1;K1v!Fjwj\F/0S)Uz^,iK n'OgK0  pN&M pH,c@(*8F_}U&@Vhrrplc`[XTUX[gzKG7|5o9P_^^^]a]VJ;# #6Oh'5FP^ilpiU:tFCs+wGiYRJ>4%`D-zE ^1k^`r~8e 1DX`inof\MEBL^l+Di!h bO'k'RstbL6 #Cd8Wu~U/v,RVYy? sleb`[YOJC;1b8Y'nZG8& +Ba8b$AUeu?bKN*s<}1\  *A^m?^l(HP pIW1  uFqJ0Z>&Ih &6Pp&ROaU<x+t;u"U/CXp}nomhW5x&Sw] S1]8$ mZP=#c4 `#Fu^G- %>^|I(J^dfku}-ESp;_Ux7?e>\o~Gn}I >T j]#m4pcP:h@fO;'y3iH$.Mj},BQI@753Ff?HT9s4l4`1CPUbq)KhGj~mb`YG(Zg*^-g?[1iE&R#U#R(vL3(!&;Uhu  'DYegnvx|HyEg6p)WHu@f 5[ +:92kN3o"0HaB$eYK>/ yS%{HmCgK( (Fg|$9J_xC`~$InABzJv .FSbyGq):DGEHQgbC!T!\+q5~_@x]A#}qdN1lB}L" %)z*Y+CiGw':Urh@ Qx=TM$~eZVJFEMJ8(W+dI&~DsaM=7AMc&Z+?[rGx 2bBq3q.Jc{'<JPVTQQUk{T(nC @iK+ sDdF0!!+uqmgS.tOA5, /3AMZm!Ae&Q(Im Ep7r7_|,%(8::4;D` C~E\-d4f3lXE8)%qU?%i4|ussqsr3Pr6Uu "?[|&@f@u*m8d-Y ",7HTWUOD<0! ~L\#u7]QhA# fH7(yU-u]?M{6f Bt5dAWlzBvE7`(U"+:Qhx{zzng\_fa2]8<S^$pS: \<)}Y6^%u1?^ @d,DYs0Pw*\@:+j'Px =Xt+AKSNH8)_!IA}5i)|eM@>;% xdI&yY?=uM-!3@KRXdw!Pv  p?MJhT:tiV8c8Cs8kO, >e/Rhox|7P`m{'GmGv=xI.]8Seorpqz{&Nvo@qQ.S VqGdN<(rX4Bz8gWKFDJIKEHPV`h ,R(28=AM\mw}7a*k:xMs8Vr"6?Lez)8FThz~e? ^+t8g2`.gDT&uBU'$N}$5Ml !+=Od+U<1j0Jav8M_fp|~ufT8bW|FfG5# kB cE%wB%Ff(a )5>Qf~7Z2c <z<w :Q^b^SMGDGOW_[L:,'4J`x'~lT8 FW\!zlS0un`N2^.|GkWE3!Ey2BSn#C^s|z(j- 2v}   l1G""?4"8M78}/Pw`~ R + D jiVUz+;1  [5 A W Db Y g t 4Uq0|&L 5"eO1 # Uq'V  ^ y%q1pvD]) 8%^ \SX[ }  u~ `@TF5.+=drg? b| XSpx|8+5%0{lN6Lz6"d ' v _ my$ V N UUWZAY)_Zq34jLQ) = l~? 4 ^  \ W \ f xD3Z|HUVjxs5xs&|v%3ZH&dn_V7Z%[H1\wTx# &tZ l / gA yzkI. ]C O_IVJ t  u o  oh2 C%q"SLY5eoxA HMT& g(.wS7^PmoOO"};xG > w ?  Lg ?s=hq!h5'&=f,a`23VQIHew:?/}Yk+cIH :OGy"Lw~+&<81!s^3o= C p { ] $ U { b }'S`U_t<./=|/OR`'.oxv']MwNzz-AH'x|;bf+Uco'  jW.z7SK1X"Jt S = X V ;  2 N o e9.s+m7 [ ;m|hqbVR^5  ~ 7['P`~luRypr d}wPNq % WaV{u#BHLeecn*wKoBI%OG:$? pv!d%b3mK! DBEei) n b KY\=)")Bj 2HL6$+WX+t{4  s  v -  / } . "  (3S^QzC{K@Yg U#DXaaef`BwnUH(:'a{*@Fy:MtxdbYXF .j# mt|^glqmk# da  . 1 ,  vJ[I5;eUQr*/ vIxS[&02-\)l3Z| wkzR<6$P#^+ 0vJC^U5y;GzN'9@}H h*r|nv)\MR !0kB[j F^S!V[Ac!lbucR0 F\tX8Kw@WZO E{|Ni&_g[_zczEJVI & { j :  N  |oBXTT\y y7l:"$9bs\OmNq1C\n=zI\]Tg jPy:&cU4E>,b6~QVS'$N%bF?>$ah/`1 t N C ! hpiQJepA38<=5' SjJV=Bn|Fs'"`G?CI23.2SbybqXZ:)_,9JR]gkto <hVV. ] H4`O y W vR7[y9W1"-HjP2a`C`2VM{nkw$Ms"RggQ4N TIB|ean:I'd\ G{TC < u u - > CE`wU}3Pj+N Hw,c>MD%EZk?\r$_|r_]h.5bnUV>zW:J6@g/ KT. <Lei  ^  S  a C`+G38PlD&$5\?37Il0fBk|]OYYJmf T1PTMPu2iBiqlw J1Vke2+|H[:n*pS;%}X2 )_+TdPX] (C`qjU@#}yyV Am4K'9gmPvH2K{^o;x/J`nmS>NE!/4<F_!l3;^@  8 < (  = Nol?j"kz`5$1bAlM.y?^YH?y,- "Cb-]7kO;-6 V\>`tHbqnUU OJoi0?Y3R|d=z@ jD]1u S;=OKCzLGL1C{ha]Z`pYCvM0 |nkL'cc-ujaO7[7kWMVr.|dOJ *Mkup^I2SNUcu8&i}:xwqfhwb5v.6p WBDK!\DM?Vl^aS'l5CFD;5'c? PN[E-7KDcPR ( ` z K  e + :8\1}^:Ae"1Q}=F1{0r];YgqB9)kZBNqF5Pisps+YwasX>'G.KpjdQ3%c55ZKNj|b2^w p-qAzY5 fLZl0/~ "JL$2R 3]|q= |fH%U'($/7H[}G=N{+ W | c % n4m [5l4F7zRU! )V%M_d`RE<5220%O)aLt 5g8mF# 9x2SuD#9$a*Y{q>0Hk["dDITyf"p  7 a 0 W { w ? e ;     v;junpxlN!%d0JZU<!<PO/ ;mZ^1-]"_(bOV|2`#7[|~>GsS1 SBsdicR9 Dn P.qHzM4Sajy+(e%f0 %\j4?.x}O+\&V\$yePKCCB=1 Y@ R /54,#tK[Wa[9dRh;  $& x_3S'Dd1CZ&|qqrh[TUcz#e4x/xECsA_o~ 5Xszd?,($%!.Kn PG9_VP@[ @y . S l t s s v w U  eH4$ zYD4'   "Tz4@>99;+g"_%Nitr,;lMV!*Di&1 q2NDv8Ffy{XG)T}IJ,1+.>UhpkY>{Gzg[\mH  ;^Q~jK%r-1h_e)!<c minnhe]I-<\nlY0iG)#7OcZ2&qv+sC }Oqnqvp\=  !/N<$c?mH&9@855FUi'#w]OVx-fVam(Y(a@{;|BY.,3.w+<:98?IV]fs QuHsR69j w;qCah[/5`U/ -GYU7[a0 h,5}~ H^2jeXN3QcvvbP>.zbPLXq X&oq9VMET[.}Y*jWWX[`hy U'SDbnHG?oAQ <l:kV9& "Ai+++.0(|\:)\Ch)y;P W+ /N/\Iz 7e Bz=Tbhqz[3 oilB!O d5~Gk f5S3a`E'pT1V=6GgTV*LlI\3w.y1jlhI3[W sbK)H;qBkI7c![`J6;~A{7LYUJ@. }m[Z_p TU o:UXL8`~-." f<f|:5dI}!0Gn1QdqiL$SfUUG5d i-x2xw!Ca~ O`2DC;;^< scbnW3m-e @v)GexvdT>%(,*(*>f%TS:b.X6?DVr^H+t\NLUcorsV6\/G`lu}}a4a*Nu'J{w5z(rK&nbWLDBM[m_AJR s0Z\ yK% 2Z`0v^Bl0t(@Zp|opwwvcD=i@UbSMYOA<[xlAmL-t`< 3RpG~?`v_B)xA 1l@1Mz@ ~Q- )8Nas/EYbX8K @p4W z/H r?t`SU`m~Eo r?S# R,]HhGw_8)k _\,}"z;{j]Vd'DSSH7(#,h!j m0N^DfXNJ@6)D-m6OmT._|}iUKEFGNNPH6]F@Mh.Y6 |HVKo8U1_{+>JSO>'jC T+@NVgj8Yntoh`TSK@4#NrN=!L[+c4 oWFCQiV_=aLO M8SO*+Kdy Gk9q3b\$CNTQD5#dI1$ +Fx8m'Z(z2]L^TT#whYA_C# zgp @/Z<a|lR.fA(q#W:e3~we]]jSuR(W^`2sKbH' qO0%&=`1k,K2n #;Tix{{ujV+hQFED=99ELHJVfY{Yd&vFy.}4Ni  nH:9HQ`jquy~yqms*Gf<u$RzX cB aSp;^+Wokz#% KPZhF[g^VPH2:Vk~I4:73~a[v *AJFKOYfox*e5CJRSZi$`-=M_~O8p-gF[!x.P\\PMZ| $2DKPF6#$O|?jDf~ylju{Y#n-;eDJ[c)qAh;}naR;|kXB"uAsJm< VpU;'$+5<56;EV\mAw/bCn';HMW_nv5l%^ GVD(wGz7`7BJOQRUWYVOH=;?KSRH:/% "%-;GVp #:Xu`7\%f!JO"CFpV?41. xgXH9' hK1zGy@u@ R#~6k@Zr Mx 'HqDpP%xf4|5m d&U+@IX[_^^[R?)#7Tu4U{  8Xm{wn\B+X;Tu3Rea5 zY;}{yuodJ tQ*sS2 o< _6q< |gUD@I_u ,F[v;_'T)?ZyGz%c2b@r7r>{%Nv "/=@?>?A?=3' 5[{9^^H9$ yJf3X v4Y?( z>mbYIA5(jSFCP\lqiQ0 c<pK L_2tT1 0Qs+Us6]~?b"M1 O2kB>)OkQ   7AMOLKG?0'$5Km"L,CVb]ZW\kruqoaJ$w4vU+T3f9 c)v:x`O:,"{_H2hFsZ@ vF NvV7oXRVdo|/Rs6]x #4FUm=m6Oj!ClQ4d6{,\.Y~ $7?HMQY^`cjv~wjZD1 #.:If-Jcx]._(w4KWuF}R*Z2sW?,' qC}fK#xB sJ%yZ7  ,b :l6n5pE{N4~&U2c  #*.>KRWQJC?BGZl+S 0Ngmk\M;20111(wJ#sK(KX ^3R%Y4e>xV5xaEyH&kH%KyP+mP1#Jn (Gk/Xx$5Rv  &AVjw$7OgC/v$WKEW"N|6]7[{o6oI%LY ^b6L jF( |zkV@% mK']<x@ c7 kW@) +B[rDu'7J`/CUfrwpmow!#%0;Qe|WFAG9r.q$Z/5:6.%$<Up~.?NTWK;(wdR2_6~X2 _W$jAzYF2 kFkXA)xU3g,|\<$~7Um%Kv';L[`k{ !2AWn )Jh/iGs*k@y%TL~4GW_lomaVON\jpW8lJ$PCg>c$\9oX;z^N8&h3c=kC~x'9JLKB@CUl0B^~ ,Rrur-CWiv:QmQ7E*dN&If#( q]JA?I\t4V{^3 lDRwAnXC'DwR2 y{{~lA vU6sKd<tD~wps~"4[v@g8[r7Y +D]u#Z>:i=b!'"  $8`'//*" qYA/xIn8fN3 uQ(p`O3%+(^@M w[H>1lJ, -Gl  (;Qf}-=<9/)%$$-;Qr.V| Y.Rx?m Ao'&$!):New %&!!Fk1Kfv}zmY:tT.O{`?Jlcgge[I+i> ~_>%^$sK.Y3 /Jcw>\u;P^ffgfhlu$BWgt?` 5Wy7s!Igz,/)bRWe{-Lh|%)# tJ,yM!|{mcO5LcK:-xcYRPVYZQ>' wTB:5;GGE1pVA3)X2 }~#8Kb$,}upig`VC%{R1 ,H]ih^[Ydx/AHF?>DRi-`Ct 2`U)Kk7KNIC:;ESm  "0ASi{rJnddjzlF{S)sgkwrS$_qd]UJ:dOGO[l|yZ1i@"-DUZO8wU/ /(zXB'  '2i(0/.&"'=Tq@]v 2eCg$C_twnquyiU?)    q[I;3' f1U(X5|olooj^VLGC>@;:mY9{i[TQY`o}n\J?4&gTIA<94.( vty $3Kf9LPOKKXk#-*&&+4=AA?@AHR`mx'7J\{1`:Xuzy{~l_SG7'      !1596=DLNJA74/5>FPTTQHGE@4% iJ"|Z:viZO7}urov{hI( p^PF6&8]|7Tn3>OWblstk`OD?;<>=GScv*Qp+AZw5Roq`N>60+'! 2BNX`hkdYHA4/%!t^H/vX8u_J;11/+ lYD,}m_YXSTPMEB6* (;Nav,AXn "*)*)'&$),-,.,-*)(%*,8H_x*G_v'Qv %8KbysaQG@>@AC>;/ !! #6H^p~yhO0 jT<%c7 gW=+p[D3$~Y?' +:IZl}2Rt #(-2;DKMRX\][UMIHNWhx7b$Ek,:CMTXZ`eiz~gQ7!tbPH>?GNZhr|~zwtnijmv_>pX>& }fRE7&)4?BFHC>82'oR4{vvv} !/e3Gb '058=JXeqx}zmeVG3$ '/8;?CKS_r-SuEh $:PalusxyoWC(kXOGNSY^gq| &;MUVMA+qS7 wW6uM1# 4O_nzuaL4a;||kXF;=J_z$Bb+A[p~dO80-2>Tf~kQ4#!1?JVXUQJPQao%Pw$Hr'6BKONE0 thfaa[UNE8+  -:DD@5*%&+:Ro$5:>=:8852*!z[?'d=fK2,AVbhkpnnooif`XSQLJDC6* iL* r`[Y_fs,AQ`s!4J]n}|qif\UJ;0&#),3477;?AB??@M^y2Vy'Ij ,3;:81.${]D,  !.9HRcs  W/ tX:oT="':M^jr{}o\F6-&"$  g@k]WYk$D[iu#AWiuw||eF$ 6Xz.HkDhdH++@Z}lYD3  f;}vohf_UJ@<<=BLPVSPNKIFL_rsU5|\? !>^x 'Km}sonpttmg^UTTUVZey-AOTaels} 4H]q ph`UNC80&$7Qj}mO;( zZ<uaSH6+ $9SjxobR>#~\I;44;CHKG;2)&'*4.! 0HWae^VLGO]p#:N_p=[puiba_hm}tdXMJC@?<:82'!1=AE@C@CHNXdxungfnv~iL.teO9|fSG>:;DRh}rM0n\QEBADDEA:4,.09K_w$56-$! &+3EReq{|Y<%'7FR^cinw1Qs3>DDEA<;5/+*'xrmnv.G[qutqsv{znaK3 jL,bF1{umbWPHEFGDA><>?DJUbu (6;@EEJJMOPOOHD?967;AELNKHG><6* ,;HXhx(@Ser*=LWddgeed]SF;*  "*)/027?N`wscSC=60**wnaWF0~fG*oWMGKV^m}#+/36>IZnpXB60./37;??=0& *6>FNRX[Y\co5Ut#043% )3772( $/CZv~ncXN@2hRA8228982#&6GJE7# znhjkmgaUE5% xhTF7-'0EB>9:9AN_x .Rp "9O_hg_O6" #5AEA;3# +284-$ *=JMQMG=3&qI#  wgS@) 5Li{qnvhXLDDJOLJ;)1Ogz5Rl#+(}qbXSPZi7IY^\YRW]m}rW;#  w]KB==9:7,#+=OWXN=$   kN)wlklv{slgfoz+I`lmk[QC:9=ALYaime\G, .+2Oj.Qr(D[jnj[J3 &,+!  %..,%+7JZjstkR5x]B& xcQJIRd|pc`_gmtun_N4-4;982+%)9Nhy{uvvlebgmy*Ge{sf\MC=<CQ^ly(/7><82($jUB1'  !.6?FKNOKG<0 m\PG=40' *8BKUZ][]abmyysngYNB4(  +9/'w]A(  ,B]yp_URV]fs .CRetxqkjmnw~mZNA<=EQdv}wuv~ " xqi^QH>=>>@=3'kTA2(#!  %/535/( 1AReqtsohggipxxlhjnu &?M^fq~vstv{}zsk]OA7-''  zrf_TMKKI@;/("#*4>JOYbfnw.>LX_ffgjmpsyx|uribVI:2*.2:DPW`ecaTNG>=>AIOPRQOPKMQXdvyh\F1 +8AJMMKGB??AHJQSTURJ>3&%.3971) {jWKC<>ENU^ab]SE2! $,4>@FKRWfwrf]VYX\cip{}}|zyvxz|wwstw $,5AKVgy{od][TSQQSX_fqz}pj`UKD@>?BDIKNMNPQLE@6/"   }rke^]Y_hmw|snmkosz $,6<CHJRU[bjoli`WOB=53-+&''),-043679=CHQX^cgkorquz|zplkcc]WTMHGFJKMROTPPNJLLKLHGDDCE?94*)!#!#)018;?ABA>:2*" vl^YPORQX\ho{|sibULFDAADAAADFHLOXbmw !%*1/0/.117<BFOWcjpwxwsprmnqsvwystnpptxxk_VNIGCDHLRYZXSRNTW[]YYRKA80$~udWMJIJP\cnrsxxx}|ykfb^els~ (5<BAA>63'&"#&+2:BFLMMLJJNV^is|~|rlb^Y^amvsgXNGBCHOXbktuwuld\WSOSXX\YYSNHA:44/36?GJQPLA5&   |sme_[Z\dmxyrqpkjkntz .6?CJKLOOPRUXZ^ZVNKHJIINQT_jx}|xnh`YTQMLF@:52*('&$),5;:6.% &-3363/) }{~{{uwtrvx~}~ "),.('##)')*)++,37;;:5-!  "1<CKPX_hpy}{m_RG<;753///0-,++/:DP^hrx{|xspkfdfjkhidea\XRNH>81/..,/%~zupdVLA82,-04=GO[als&3?KWcikllfe`_`__cgkopsz}yukkefeda^TPLGB<9::>FORW[[ZZWWRPLIFEA>:5+  }~|}  $-59AHJJC@61+%!  !&',--,,*))..29BKY^flrvvlb[SKGA=?<=850+&!$*9@N^kz~vqmfb][UOC:.#  zqd[QNKLOXdoy !/?FNTT[bjqxumc]TKC=8366=DLTainrqlf_XVTX\_dgjjgf_\[VRPMNNNLE9*~|~ph\URWV`dillknnu{ #*," &(-00/33159@JVft~si`[USTSRRNIB:1,$'%(,*07;HQT[_cbchflpttyxtlg`YTMMEB=71-)!! zusrmlokihd`YXSSST_jqx|&-57=>FKSW\ZXX]_cjnuuy}}xmmfb`]ZURQLIEEDCFJJOMKJEFDB@AGMV]jr||urnmhbYKA4) |ogb\Z[]dnv    '069<DINWXYZ``edc^YUQORSYbjquxyvtrnnkii`_WPIA</(!$#),6BIPUY[ZYYZ\bglquy{{~yzy{{~|yodVB8* |rlg]SQHE@BA@GJKMPRVZ_gn| (2=ES^gr~{}~~wmjb`[dcgkhhd`YSPKFELQV]ehnrqjf`YZXZ]]`edfhc_[SMF=<:83,)" #&%)*-0233.,&  %/9COVZ[ZTQMGGIKNQX]cfgc[UNG@@>BDDDCA<70)&"!"!"%,+'&! !&,/49>>AFKQV`ipx~yvoeZQLD<711-'$ ztqnommhhccaehkqy %2;HWalv{~zvtprrtrty}zsojd_aYXVND>73/./4:?IS]ht{xwqolhjikhga\NA2& {wwx{{}zyvqmkjikkkiklpqrtttw} !)1;AFGEDAACDEOU\ekszz|ywsrmkfdb`]YLE:1*# #))'(##&)-268CKTYadfeb[SIA<965542/-+)#  {w|~"3BKSTPJIGFHNU[bgmnrnkgcZRLIIIKLGD<3%  !'./200+*+.2:@INMNICCDEQZenx{og]TKC@992*%     {spnq{%'+(!+8@EILLHJLNS[cjkhaVH=0&"'*05/+% '1?EJJEE>;5499AGPZ_df^ZSLECDEEGDA;4' !'37:751(# }{z}  #-4:=ADGHNSX^_dfhc_WQIGB=<7764413.*(&" $"##%2>EQX\bc_[XW[_cfkmnojd^VLHAA>@:40*   &*12/+(%  #)*,&!  !)06:<:;667:>EJNUTVRNH;3&  $$(,*1169>BCC?60%   !*13513245;>DIMQRVQMIC?<;:9:865.%   }"&))%"! #&*/6440*$  ##"'"&)-7ALRZ]^]YYTURU[bhjpqrlic]VPLFCBBB<80*        &-59<<?<<;67687:<<=71+%!  $*23886;8=?ACGGEGDA<80("   '(-/6489<AGNPVVTSLD=4.)"    $.7:>BAEFECEBC@=86,& #'((+07<FQX_gmnqqolfdceglnnog`UI<2+ ! ")44462-(%'*07?FJHG>6*  #+00.$  !,1:>B<7.'%"(+-,'  +5CP\bhfe^YRTQQVY]abb]UJ9,$  (/:DKNOKHGDADFKNPSRSNF@3+!    '2;AEJGHEDBA@<=76752.&#+17>ENT^cjrstwvwzy{}}~}{yslh_ULA8.$!"%)*,+**)%#  !#%%%'(()#  *03>>BCFIKQWXWUQH?4+# $(+,38;@CLMQSPNHDA>9854532.&!  !&*1;DJRRUTQKGA?<9;985/*"     %%*.14420+%! %4=GMRRTRVZ_gmry{||xtme]YOLGC?:1'#%&%$"$#%'./330)'!   #$    "+6?FLMNNJGA@98797720*&!  !&*057:::==8>ADFIIFE>;0(  !'+0/21,127;>DDDD@<:6.)%$  !&+/56842,$!  !%(+*+'&$  %-6AGKNOMLKJFEGGEJHFE?90(  !'39>ACA><::745620*&#  %+37<=;72'%   $'+0356640)#    '.5:?>?>:855567865/,! &,7=BDDA<81.)'()++*+'&$ ""&(.11651*'       '+0256776355523.+($!   "(+.-++(    !"$  psi-0.14/sound/ft_incoming.wav0000644000175000017500000040236011305557613014511 0ustar janjanRIFFWAVEfmt DXdata qAM & c#q. :sCJ1RDU0 OsPz] ` , :2 S }y&9] #;[ZdLauR 1 7.Z gh_ } g  eTR H]QY7Dx1\:" 5hdz7 ERY0dFXe_%t9&) S"rQ s,u7 `' 5  AhB6Nday-+3,> z=l+:- 5 +(B+w* = @S2^ C f 5- Jb2Z@Hks2v bjV @b]7wi~)f:(^`! 4. `Q A \  q ^Z=++Gt!\HEZAfn_p,YnK* V^>~A6ht"[ 5w4=3`z@O^;U:Gs 2 ! D +  \IFM3S1Ul3kt%-nB`({D8qiB''C) B jm4`tZ~-(;a*+  x g l x 5 +  {"aBiLsnwU+e;Y FnY> *St44hO"=B&,G}x4YzW s 2 v  > Q 8qEZZ(Ww" e2[#x.C~,&urIUOY:}(R"R8(c e9MT{  ` X `A : " " (MG{Zns$U?yUjQ^`q.&~#O@{N_+M$ 2MkoJ(b8yY<[d;3z  " ] 9tW _ W ^ p~^[F8LET":\[g ! U$6&8Ky G4~T#2G ; (z{85 _ A r 9 Z z  4 a  }y0Qu`y2pwL xJ.Z3ONS3A{u=*OMUl=]-L%g=bw<n$ +286r84@w h j } C A 4 T  { #  pLaTAj{`% hP C |8 !1Zn?m@2R -cAq +2 f B 4 e - b F 5 j c O*G8l IPyC%33L `%Mf(] [&(=ta@Vr3?.6[-mBO   } <  9 f l HvW*TrXFn]* |PWns[wh0+3Y1J?^+4i=]zH9lXBB)wJ5lQ  " N  t  % K o6ok\d{:EF.j.l-#3QehH KM\A`6fG7/fsz,k7t M  S 4 \ s n [ 3 Q q;#;V:3|TW #/>l ik~A"C4sS=BrWe F{Q2U/eKrV&G9<&{e   2  y   D + #kmE^*p5v5a2mC u|ck t_{,0j&GO=$8vj ; qaN:x/u S V  > ? J dKr8uhho\:An69~-ywqe`v 9_NxLSa @  )aUNE+ y P K ' U)mY?ZXOmR)^6ain>9lSKcC,=3LK$Aj,Z;gU:tr 3 J a Z 9    K {L803=n9m\4 M ^5}~,lok`t]v4R]NDY)/F&:@'4e$*mmGcH / ] x y f M 1  < %fRk [).4|'+E!q(3`X3?ZiX33R[YW}Y~  Tvf)'=;.,@Viy^8+p5@Ccq $G]rG]h C @ z 5 g 0 HHXnW'$Bb78,cIcnuh\VO@wp1Twy`c/ =K3AKgBd Y , o m 9  l  DK`8Vt XcSp-DSyxuoj^F/ {~"^kLCC;=)_.`zmlMA - v E A Cr&HMyB$3#VS ybI6**+'# ybj;cf"ktS\k@]6/6G.y c 2 4 y u n I =Tk5 V+^y!r2 %|D~{bV\L>|Zu i'_%zEm\? 6{K4 9 k N 1  b . <MNX'cy\=hC|?U^xLjM7+08O)xS"uO MLgm; G } p ` 5 g  }1VyUM(G@{fcGXl+lYJ1bD-%,2E^ w6yVxi13r1i.m? R } W 6 ? &\,[&y$SwtH ?#oGtk\F% 21xsr^oYc: 7dye\U'l@ 7 v n M (  & s f g}MH@rM0]i"NU.~jm}{c@FqH1 o,XR"2eaadd|Y 4 e f 5 u 6 VMW/w!7rb8OH -\!H9Y>"jV+|k>Ol $rsRb\?j  ( 2 A N U M 1  { Y 2 )J=8~/VS$'C0{?\%tA ?zkBV4ns_=Dn Z']- g  ! - ( O  KFx8ni 4.8K&8IBo h*Hn-4`JQs6d$Z bjX;cfMw% g  ~ 6 p'?Fyv<"LnkXGn'(gL8)xGj!Jj$o .U64-m3'bA8, c | ! #     $  . 3`V*P.uM k6@',t$'bZ[YL$[6+m0Qq7=*^vlXR.Arv]vu, [ $ (    u  PS!sLi`"}rPYd|#o 6`T[ZO,pXIB.!+L};kgX~ j<1u_0zD]H * X    w & q+i0WIu5rA62).o-2g=mUU_t_5A6M) _2| s_iW7} 6 m  M j f I y I  v;R}yKUXJN* D56vA b[B=Qt)QfJ27mV9y|Gp%}4 w $ I Y V . V  c-d]=y<*mA*SW=RgI%{5Xhzj zWcqRvZ+p d K  P  q:LRTAnMQSd{{w@i>Y#'i'kl;?e`l"qx[B3ImX# N f ` S G :  d@9DK8n_'~<]a]6_"!^5)&gjF/ 'x`X/XwIQ|R c+^U l k F &  i2y]"W}Kc.oBJ *z/>SwG230$9TrE2ie_KVDD0czNlQR\ L j ` C : H e l Y Gc ?^PI~oF.I+>?XMh1a3'(-69DLU`{4sm?O qUVCI)qsc-[%m7 f z o M ' uP1W#]`dbQY`Q Vw>YrG)'7MUWMMLWzAX/hI~VRIM4RM>VXh<'-g)=vHV7zyBoc.r;e#y_E3h\JOp(:Tbjj_D, tGtC@}3U$sici5Gv1[fE6+  6g&peg'pR:%w)K)R,rY.Qn~nWFA85*yQ#j#P V>p 2?rQu9d V$kJ<50*+5@>3?nJ*}&t SP8gls2YB;tr9Vcux\F=93+,#^=Vl"z)0>TYl=Zd>td_fkli\RYjG`g \/W&jgqb)vA@#/7ZtyiZ\dhibHl?v%`=[V=Sj~=Y|$]=vG$ N&[Zz;2UP ^js-Lh-NqgE%pC g9}&,f3ew@ uj~:|S(A$Ju :mwQ!hbkD7x p=2r(c >m{scM6l3.oO,W}8p#8!gz?mI:d+6.sR}Ji*Y]:%_1d4dv{ziJ- tM`F'@t5*u L;`%aJ@:3-* $@`Fx2}%NN vT4BD3c2hAfuM f.ib~2O*aWV6Y W1t_H2'#%5F^wJ/sio"q a,SIU2zO6SsjDj=^_U w,9"YP Ru(W|ldU<) %;Wv5m5ph8/ot%U&&kT:@r"i.f3L~#9^w=Mg/1EwAc@ 4Lm8Sl[|-v X;Z/,cY?V6\uU:x;<Qz0,e2rV QK mO4cA49Gax @ }*s70f#|]FDY(_I.A.wmaU? n5^\0l/Tj-9*Sh>' u8vK " , B _ p vqN*zJy3hwoMa4z^ F1gpP(_Q%(Vq)K[i_a_#|oT3O4),<) a8k`:/@8R@m[h@&i!NgQh'R{|v5|=p Oa1u"Zu M!\c")DWIVi  d ^  m  l   J ? F D|L4,6U+~3Z:"wv- O Zz{fjj%DJ|oqnDU'/wy$Y ,>1Mh!HG2G`qyM;6 kOTLzIhN%"[ !j+gVSb1 +\M(|Omt2tcLYce2}E@*g%!4P,f  V  & x u  : M  ~[/2Ey@o3x%~ |=6ET %EkL]sz eXpvg*_caZ=.4D7=i 2HH.ES DdC^ld$+  kq(]^OxpKCM;OEn`glU %'[Xa@ e M < |  =  $ 9 ; Q ? / I ;E~{orl|;!L"a?S@ Aq0A[ DMA<Jv(XPF !i]U a Kv.:vP R_? K&J[kwX-!  ZdGc0YU "~T3Q+dp('0=!5/P U  d * P a  Y |&$^wt.?VB5gp -"$P$f0Q #/ sDJ^T=D|{_W=t5{kT& 5. Bn~]jU izF ^;04*qosMB{mhTM5p]LmL? N T V V d n   <_,c9CU{"!qVZFB,=?OTH>bi#}=z ~=-/6&!-$RN[{gVTZjgZM9N @p Fcu,;43>KC3D"MM`VK+zkYrq'n79aA/jQk ( / V  @ L 2 L u  h  "xd !@EjkqGo^H/;"ES6//4y$wmF)(8@3%"(q#SK _bH?DYyV($"&:pXL+l1RPC5Bw BgkR]%CjWl`]q D[AZwM+'V@j(8;D+o S / l k 4 ]  ; _8NN} aF/Jk)]W hDwGhE!W/b AF1 ub2Dh 7 ?e&/!Sw6i ;[rw^ dkz#)b 9=.T&d\g ;mYoA L +\Yj+  r % g w # h ! Y uih+a{ Z^}&`j/k"S";#k'gzi`k p/^Z^BchA3%~p}rU5+VHnFV N-uIL U,0O\7 f-bv6%1;SxYcXe!%En?4z H O _  p=pMo_20Hk!QS In5 Ndkl*J4 ?vbVQ]nqY!Bt5y'v!AQ0,FxXYQXNAk!u$" z"4L+: zdnQcL   #o==e \4BkZg[*2+ ! ; 7  } R 4  }1xh n- :AV8aFTsMWn qh%`)!3r9[eXC4+7UmtHoBca oe xnx7s.>FHLMZ"I[ipqeF M}&I^3rj8=76_ N4\)U {"leF"Y_7  / 4 / "  z M C@ uw`(~# Js AF .yM[qFd@Q( +?VepyzdD! oE e.C_8|a># :O]l)|KQVwEEB/L\cR*Y4m.Qw]&yBi8 sWA95Db6ORc!Mu}jq*Yod\Hf)V|}d7T7`0REV72? ]6|a*|2q"AILJM?+N!m2ij-vKp6TAvu8DAy?(<!<d yG|VmgO7"h-2>xw 8|9Pg5?rI&YL[Hr1w1ujU4n>]n+b1*\KFvdK!WbPym8r? X9`bWXai>ZT%lKBLlzX)RFvH;)5BXd_Kfxl14y*|) el_ 1|4{| !H{M$bgk$3v!+=N_\N7iI`kP|kW8 #`#n'vL0RCH?DZ_V;[a8i/wB3v6[=2{ U[(/? `XXjiEo*Kf|uIZx&_!z.Fz"AB [PD" #1L%]^S6S!T(KrZ.{E j?;zbC*LvEJhYMDDM  ID;*C`jQ;n +M wO, 5^"ffPVF: uw!N:{1czlT6s)HjV\BBlS8n1$Aj#[_;_&q9m /LgqfT2UNcj: a+ @m$|<7x$sG1C/S a=h o*c'3?1;Ow)cOOK8('A`,hA=*rbbdLB15)DTbdYCc%x?{/j]S48.b"D "6\1 P.y:vMA6[~b:z9Xin*t?sjj'XLagv?>e?zo7}5<y!s'00=k2nY1!J| gAB2!0;? i)HkJ'mRko~}(Vt}.'oO+4 ?Modr-s`P?^ddoojT;;;+i3yF%gg ZI?4(&/:?9-7C_(aj.;6Ub;r/;;,|9r6m P>4AHJLNw(UtYC8/,:Y=xi8|pvpi`9 z6{'/(zK z-k=Yn=oZ u<y<'OA%S,{Mw=FuX/]lY=+)9:2/g~2*AK |$vgTOI< 0HoNQ?y(W^N)c8sSw[;s8F<*GN8'B{KbAF[x.vXg$2L-} aZ >a~uDcoP y#n3t"4jF- 1MfS5g=zDlI!+IafLq@~C t 1XV+g:8ZB} ^dCfP!c GXXOB8?FK1Nhs 8<;= 2Zs*S?2 2]3RBjx,w*wCgpg\E&9-Yc=t^`NdLD<74=^J*U(~1JZ <x/UtoP3w8xMZIu4kH3' Cm_deQ$^$]9v8LSH=)jE3cl|6HRdE_'+jgiB 78nB YEencTV]syd,6Dp`B{wZZB}fTJUo6bY.m [kb_ ?egVHVo{rg\M&+t#}L]}7hcH, $`-{RT<Dt1YLc=!Y}}j+;o< 5i;g`-i@.OkzrY2 qI*JFV-A6Vyd3ZH4R]0sSb.AU3s =)3FfH/^06tm*w:.&MB'}=0y$'-2>@8_!SL7//q6jCeH6 %J} H3z3 @VUA_ZF4(,00+&\6 1Eg)+pC.oF%  =w8AMTcg M r/XSD?[/<d`9Ko?[w8R!6N-FLOu`xQs7Q^0t/0"cp}*o`=N8{FX&kif1B1N<Ovk*<PR-T~G4P-?$GB"KXoZ & yJwixM/.L0b;v);'mA&BZ)$@5Dg;w#fS1V_S?"b7I3E[*H$55 fS5%_$&fNM<|8&O,U*YZ#.ad VwC o\ 'xsrI tqlhwMUj^jT=9bUwIXRALtWa WG5d'~g{qC \)(8 s MaxY^f_x{I:g=kZ{;np=m`(u - =}:ezH{ *bW"7,ow-fs'`plUTR]37DV4Pvi3F*]v\f1,=+\D2J="! |viH.4!@\i &k'^0[7s qc8ADl-T0fuujc yH<Al{7j~_ 'S Cx PQb1XAd&o)4L&DnDl.&363nU08^8YbudPeW ps e(dQ]x~@LP$OCWC_'Ko&]|RJq)}qO;sb"@FC(.vx8&>3XKGXA ]i] 4F9,/_rs.nFTh\+QB JdQ !^0@&b:b5W@9:8"{mX:xCtb1n6Lj8b! ( 9 `DYQa2s[>,';?(!Q1br2pHb&Uk<u#\7XC8x+IE>D719C.y/1b2DE: 5m~WN@g8`,>)X`kbWL(Po,~1uYC}@Z T}Q%85Dh:m3$&XGbrU \F d!Gs X;c FqI,7isoy~nWD=B? {{~PVv9lB-?bl# ),1Eq%=16Wq}ojv(lj'8=E_pk)JD/,Gk|vw/;v_JIXd_:i:#%,"xW#bJ&z}cB,+1@[vx4Qg/~T :IRf!a-NZL=H_^q\-SrNCN z2\a T8]\9lhn77cc/ rAK+0ARz!^' a-kt[:G%(yf!MM5;s1c-SKF!t:rRt.9zw#izt{V!vFG>jJ(ZwKJJ Hv@D8nwgYL.cHAT/`wE# <r,5b ?oZ&Y>FkaL dwm50Y~KE,8fWW2x O%^2AF7Cc %\;e"} 5tHb<26GX~5f KxEVqi*X#:b*;HZ'$b0g:F1rO8V`F0,DO_qLorkequcg :L[l|:pr2pH0#{sx[U,{\OUe{rfkvqZ>$ )V6d   -AS_itI{7@.pP*(<F@/D;v^D+vS5(+:CINm? !2QuAsN1$Z{g[V\YI) tFcO+R!GQkUDCHTe!a,dH{5r<He"`(8- o7:e +UQlRyFO nG0#(Fe-m Ty,vP3 o,ol .?\rL  N ^ON:AFME W(.~167rOT3UE3&!6;+])v>Nf,LjlHyH\)9^j Sy5;yo]?A#:QgmcK"\BkbT*^TfT+_5# *.-*0Em*rMx hIFYi"VyJ R MQi$W0xjEzk^dpwpd^q \3c<^j5m9mBfL]b; A QJ V6 &%0P{2nR,h%Kcq(W8HL@*wE\'_/AgT<wZHAACC<+:_:n2U'a -Ou-n *8BD>/! dN=0* }Ijf6W&gC"hF',>TzR*3A`!_%\ h3Z.*%3JRRMSheB-!o[GDe*l(Z:a' fD/,=_%Fa}7z S)f P+z_~aBBK-G{7W\%}j`n5qWQ_<B8\6dOL w'ud&4gi*v<{B 1]A>-EMO# m1d/udM6_)55]0{Dai5X&{kR@@ZU5,,n1y'gN a)>CFHIQUXU:{>i3W,{#|'Ffv*rdQ8.?LiI=yZ' d!^=/d"Zqidf\B:Tc!r:P0sW/rK/(Keh]Vz&JBo:xU(m+i 2JJ.wV;h4hEKiqC$yY1Gq"2\(^U-Oe|+|'/=a >jgH!|d4o: pCiI-Hi7  *NpG|2f})8X.iCm~vnssmQ+Z-rbA[, iB&tmu "?Z(Ogo{$]5Wx )>LU_q}h\L@==AB3 yV9c*o?qN5gB07Yu+ZQ-k2}&XAUcjptqfTA4 ^"m3vLRINveM0/NfIe,md@k\Fy7PVczpE b&Dn s$ywB i/[=6$5Y*KvbI$xs(^MK!/!`+WR>IDV{"x'xW96CLE3%3W|*h4<Y: f=%^6NWau}z|zb1d9.9p;W?|NE7z UnYB3{R1FI8Z4ex7R :l,S]6)S @mF'gM'n6l/c~[1v= `.7NxW:fF.+3?>0";\~*fK4g1d*EQY`jpuqpooiY;{[8hG h:vkd[@$  @r$Ndkq,In'Qiy #$g=~_9c@q=p`\kv,DSe)_&[=}@x(-* gP.yM$K|Ai0}M( t]SE=0 "Dk8b!hT)y,s^?{1ALSTL>#l;bxLQOt3OwinwygJ@CQn=_JAzRb b9yqAkt^=IX|#`I f{O&|`E>AEMRZfy F~?;2{Z c \ G/Lc{QZ \b|&4]}/g@=n5rBKR84l 8b,<HE,vFaP` x-P\qM3% 7RiwzHr&f97l#Jq 3Ws8LetwobY@*zP%nIo5 W&o: yhis} *Np,Sw*T<Tm0;2)q^L>0kKyR<(||}j][\k~$-9Pez)Pn;Uj|{iY?) dA~fL/|W@?9-!Eo 4c0Vw=l ,<MVY]pj>I2oV1Pc4ynfdo0cO@$o@<y1JbbtH z).ODlG!V& 5]T&fOC_RCzAbnP4 i)YqTNk&B}_A"eRVcz0[E,wVO7s96!Fb}^,`4u(]nGg+;o2 GxY&p8{XQ C{+q "(.377/'`<g)]y4Fp9X~hUD;>SWOESp&QM+d5Fr2Gi6859COZSLC=1yhN3 NuL&o4P zln{xph`RJVfE{TH} =c,;;3,3>HL@) h;X.zeF${{vja]Ycccabaacck2J_ +Hi.7206If|gDxphI u]J:'xX=% ! 'DayH$W+Ol$G\nr|sR9b3zN#R(}X7|D/Mi9`M&i=|$@d4PhznL#SVpCQ I ].X. *BZKw5}fBv ^<y M{`5 ROa GE_jO+E~B@%v"m4s V9t,8@>4&"%, Z*@n3X<_#i/|S2 ,;Ef5 C>~.j(k8n&31  wZC(e m'|=AW*Z3zaLIM]r1`&k.j(R)^0h ".3BMK:mY>?V$R+qS>#}pl}*Lp!R$T-Ha {l`XSL?&a< xogYM4z_K==D[runlr-8;DTt#1Bf 3@LXmsfd[P7u^Q?)mddbR8of[N>0+5?@NYfe\PKJQZm +Oy!Io.JeyHmzj^^dxmHrN)xL|JoI+ oM4+$))01/(!"/D\>h-a=o5z=l8HQRRY^c_P4}Qc4g7 e([pP-nWS^m~?l&imO|mL 5ai;X'|:_J c%Iy`K7" 2M\am]-hS ]SV*V| !'&"b3?LQaLb pK. <]xN)UA: IGw3X}j>SUtD {.L!T {/:Lg2vAy!\)X1G\uqN0yL\:b*~W0 $6AIM_{9^"Cd3Neyoi]D!{kT.{I~{}}}unp|"?N[i<d+Kox[OSccdS1|[;x^=) {]E2$  '?]&GnFo8q1ZiXZfrx{oP,d;uP)R$~]?rR8"  .=FDGRm:Xm G| 7n@ 5_$HXP?26<GQTM2|Ne)zNTjAwY6zy9i;k(iX8:`"Pr~zwjYJ5oH\[v=C}_H6!|QMj6^69h;_va@"Z(=;V|GzIw]J>56?GO[iy/y CkAW*j!NrCknN%f-L h6|6UsZF3) AsR#c6b/Z<cqcM=& Z3o: vO-\3# 6Qo $;U!?Wl~1Lbu}hB pM, ]2  sqw|rknqx"?\t Bq5KYnofdin> |S|_<r^D2  Av0T,Kd,Wv2Ufrqm]UTetmQ&nLdC j-hI(f@)%6IOM<4123Fe&NS+o U'\ )# aH%OT`Y1U%4Sz?wX$Td:c6IOIHJPUM;mM3R G}Au/jH'"O,SF _0tM:Vgplf[VVVTI5vA g.c!`+k,wIrgo~=v*[~>#m0Z:h .NgvxocSC;4//" yB a4Qa'`*iC$#+4H_x>s1n#\Dz;TojP9 _:jC&mKscWI1 !6CKRc{(Mp&6Om.<K\plVJ>.}S0 tN-~j`YUMFB=DN\hv0Pz(Jn >Zx|_Al>{X5s`OD4! (Gc7Qi&QKv "=Xo~t]MIIIB8( Z5r?o/sJ/ k\RKA656?IV]gy1jm[>: =8;0 Vv{/SEY[\1Rvl]4a=s S H 8  T g ,  D $jzyAoBJTGeTJhC!c~"=`Ul J j1]$*a^K{R 5Yr8B!& > 1 &qVW  - $  Z 0 K t0CWiuW7Vt_~W2$?-SXudQ[Xog?G,$WXmu- g ^ Rh}ZB#w)n" {4SD?: #47R&<$iPm&7}DP|@Di:%$[k3U# #  W M p  + q 6   ) N8y '|jO\k/ AjLIGm OMm0cw#x0}aJ\| D ` V ' 0 j u eOz 7 7@(`fD7[+0[CcM2s#k:<6S:&3+M*ksl57oR" V0j L = @?2 $   Qha]`tZh/4kR/6*`LN2hX^,K!0\(?]k1 P Z  t ^  Z uJq,4gH*X?hUeoIrO1|$9<{;"T. 7 U E A M r  i  I :/ gw [ P\Eh>$`{aUXJx!G! [z \  UKk 1 P M -  , APG?z6]0y!JK<P(R`" l HvA,/lf,-].`d}p0e2 S D 2 E d 3   l1,q/Z NK~Ql']* =!Z1U~sr!V5lWY\   n V ? _ i )    5DNpqekA#9jKS=>k8[>o\,%j@'iTV+2SY4u- &"p{NS A ( a  V ( T m 5 9 o+llR\q-72fk{+0KVF$@bL  87kS \]{3E?;rL m ` I F  X r 6 " + l%C>r+~5>upp+`zU`[ 8D8f-W2acS H  D O 5 { - |  m8 .bn:FBx2bS" 7F> ?oyli^Y %IYsc4Ek q  i ` . i  a[/q.RBFq} Ocr;+S 0' 7cFy)_Yc1o?1= ' A 0 c f N  x J  O B eOi `!n%Uiu"~=q&K 0<:& .h}Ic/i;7[N?L`z  D L '  F ~ # y   # c}q j$CU[gR#xa]H.YSXgs']EE`$Dzp({S _ w 5 F V ` O 2 > EPYXyL'Mv4|+PxU4 #.7*&X8nQGgx2!),l  .n:  D  8 J ,   o # N Lhp{_ ]oD8.)oLp=u;L 4(^4??+I.H^F  x { V & P / `kmj^:>!GWi78[yO"xX28 "O c*$rhanh  p +  4 ; 7 " 1 | # * Wz#T1hE@{5h k|K$`@rYTPMUpSy3Ub.:%lKh)h    c } W % r K  @ 9 Ml'qO3U-)D~8XjRRO@$gF,y3dhA}-?u*Oe6m|A)A?3;Rf ] v 9 c V-F@F[I@=oz{xoV3N9GJ6 S<>Pf<V Z @  3 1 ( 0 P | p   . i ,r4~[ j+MmhSlR6 uO |WbW`Z\-|xLY30Fn  - 1 t  " ? K 4  M _ 3 M 0O1#&(9]_$ fynsa: xYIE`9W/oL[zc4lc/B3 ( # t  V    T   , M }=  .X[V S?o<MMNt B3W$hGJ519  M + z   [ Y  U  xJEU%p*b\dW|_}QzDk: ,c.XI [p)ovNz u~  9  [  v K  . 7 g8A{Sv? XaJxw6iFLMDD^jKw r.:F$?iyd&=y   i ? P N 6  z . e ) PoG&2OW"v[A/:q`>$_!:mcl8s< *Ce?=qzfVh i U  9 _ { | L Q  ; t &$JcK\Hc[?7x2cE( #fAs[[.6ac*Jo- | , _ 1 i 7 m  ~ %  \!<J8k>$fAc qM5!n81blvIy.nT:>-RHe y W  6 W  ( y m  H <[F #l(n29,t |Fb1BuP~ c?y/%/gWmlF(4UE b % P w 8 e ' jo &D6G`-|,tFj5sv?oea"LC!-Nd^LAN;Z-F O x l =  m 6 X*>h"(os>BoMGJnWC>9:413Fr t*m VJ&>yyZ7zik  d  * (  x e b M  L r%L=~Av p9lZ]VMUYd7(.$|~;~Dw1bf^[leXZENan7B`% K b _ J 5  Rm/)A|F?&K;uTx_3rC UbnE422c76H~0\& ? G ? 6  S"hFg>t|PWFi +`+ADddp|q][t3DCmJA9&k039js0 L W p  "{H CMFG7!,=@YhI<2 _Ou W[O $g Yv7 } {  &j%Mc;S>_]e5ckn"qhmu}^qy9L,HO~z!bL.{. pNl / M Y J * r[ Ro~2UdF5>uV]o5yH"!7CRX|7|4nGC`_&sv8 Y4x /Ai~tN:ZauqYJCW[:3;DJJe$2`M/jtKpUT{hQ/!-1Tbu& J P 1 uR#]1H@d  JK>E]l4e?' 0U2u tnXD4v|{oN3*#` D s { _ 6 G]{%[ek\) rE5c&e$Gw9~'rPEK>>27 /AUlQHA h ;  t ]5Uuu:!tR>)9Bn*rR>1Bj`te\ =az27M/KD Z j G {=dg=ED} ~@B@`4r5":B=8AP[w,uH'RIEbcqp7| <X3Y}{t`@u5 YQbWS<4xi$s:Gkem7(aA974zf1p!4'5 z9\4g{tdPFCI?$J|2 L&28fQ"C !] Kjk}rX)3wUQ$LS wog9Qx1 ] V+ 7 &   ' B X b [ + M_w1gJ=hqW4wH;2H7d2j8&6[(Z [ ne\Q{'Iet\xR D i  N a1BJl8!YZg~[g@Q[i@)t`U_=a'x5Q<=xIRZ9 L B k u , caSW:>>pE ;1o:tS# Ii?. g1LPnwN[.(|n1n < A - , +  ;yB PTdwv-#Jq*p rI6.kY_0h Q" n3,bDBMPo3K:m"Kq{oZ?l>m &Rh!IOV} L Q U Y Y ? {J|xb.+"zq <#%|3`'+[<rRMVt$#Cwf-M H  : 9 &  i < w#[B$X~'{M[pR`MZV3"#8NanvKkH7$(ZAaF5L6rDR z m D  h>CdQ* xyVInE=wldewO%z+uiFY=(47#$;i+     r X S < K]`?)LiWgjM N k"y`J3 6M]m|6!o$w^TU^'!,"m:NJ&Nph:amV*/-BZ`sXe%fz]7~oky,e!},veBX{1s!^g"0>\qC\Jtp}EQ_^L5ahHoL/rC 'Fc \ |g^41]XQ4 {aL3V 4 \  c 7 Yf;>ALI4M7'/Ig>C ]>%0V[YYrnq| Rqt aj(/ Z n  : @ + ^  Y ~+@) j1fS]uPEqVG93@eE"z!:@2Gt - S0 kDu $ I l | w j K W!,p uj3#t0"34J]~{J}N) -T.ow,q_KHWsgWB$|Q-^I}Ek<&^0tr2?qMh$|6:wCF*Tdf)|}?";*%WvtocSh L1S=SNx J]"Q}K) qO?8887CWtYcPH-*%TEP1 m M D _ q r g P ; )  k,p d@O>6!|n(@oKu8$WM9qgB1aHw? | W ! tB1N.cY8 ~^[-FmF`-~YE>58>LTeVe]RQfm@f]g| `>#^ C v 1 t5X3puQ{Zw^^7sV$e; L/ok'6 ElW'fb3dnJ$sJ9QAUle^~ !Hu:\* K l  o G  SM2hkdF tpp/gJT^iTN\{ BA)Q;IX]U<#+XuUR d' F K ; , ' * . (   |Cm @;?`@C<!fLV t2iM&P+(e<U l c4H m%]e qN)% (SZS$vSNYlz|syQ!lE Z|NyW#YfDX"k:Uhu{skcN!j.z-g0MV)G"i{k[#>oc6S zmJ~aJ+iFZ@rr@P8 9=\m/h=k 1CT.O ,_GR a*:} DE;8% I t g * dK^a _:T+dsbAk9g3 #0?OfTZIk\>BNCVbf}YS * G \ _ U A &  B b;IH{6wZN E 'r2+u>hv C}:MV>z>gqbuR1H: Z=afjxfO h:-#D{a:u-;- X7xA3UZ1eC =o<q^Z4%PWG b=&%.gbWI'&sL w2=G { y"mmneN%Tq OUqs}OPszdha;Ew).a~P>ney!toD)6:4gK ~^->oU2jp./1s3"g Cm2Yyh<vZ)h&nB@L8E9?lc|B fA)*0Fk5Z2qx.{.%EH Q=E.B{,X{\;&KAmc xY_yLb#rGAnNKJC7:EJO]o&{N@EM|i:\u=S9 z], g"KN1i{$B,z.?SC  8vV|){,]v8vqz*sh/RDk MG&WqU)>['_Fu<,rk2s_A7q3qFFj*7@bE@BW#KsQ*%J. vr Q"X2H9+Qj>~^ke"7H]o~Wf?@F~#|8/ V_ U2G! f4 8q5G]?A%r 3Qur!^<(2~gJ+ 'V~ Bw.~[`*}1z|w.u x*o :Zq )5"{[5JnIQvw 8JDiSB=98K%Rzq@~]n D?CvoOl EP CxQ 7L]v.> z0xfVY$o `Go;K(D_g_=[rq|4^T y#kBy&k7~Q3""0Ngy}Zu2i4-q[*Q Y6u`j&4Ik 8[C\3y"Kv)eQVamrslkf^[e|-y'Op8X?_T!t W >y6r`x(eY@is*})p'i$i)ts{NO"l$V"7/_ o,iCu=T_^XZajq_E&n$pi6-v!q!k#l2h,vD \/(//$!Ei =x#VA][V;:AmV&U|uC a%i&lI l+>"J"xPpYAHl )215\2;[ X{: T =1| 9Iayt: `1q]Y2_0|1W 8x3vf[UWey!,8R[G+n']#`@|-j Y0oe@'jy3s8J[EBR ~M71,"tx(]A[:6h&Ij'z\6d7mvke_K@3_)h/K>q1N] _qEvpwa#kU;""b!rN;x+X=[rv]G3 r9Uk2X m2FN{? pbPHC@DJYhvC}1i_fF/b=n)W~+MouW?1) Sq@ xF t+q<z<o(b:'% B{L~&P3;[t%\] +^);GMJ>*`2lH( Ip5o<n+kC' Z3+@]~3b;v)m"Hq X=m 7Sv9^sndPLC?/" PnFp+J7QR ^3 ,W#T$Z2mIu=|2h =l)Pi|~tjh`U?$qI#k:{6~<x3gh@cH2 *R$W1r5p2p$Y F 3X{ 4@GFE>4+"V*a0BASK lAmV:  6VN%N{_K~FwS*Qox^5 ^3Y%`/s<yJ#hJ24Rs)^/U$Jk2Yz .Y6KWQJB;1y[/v\0g4_=znZ;!u_NHJSHA;@CMQ[al}2Fb/Y,Ii,Qv+@`vcF)bI/ Y/R {W8vdTHBA>91,())28Ib}8Zy,\)RFn +Li &&"{gJ$pW<D}X5l> fZQN7 2HdP+^U1T|5Rhw%0>FJ?+  _3}bL=*NxR$G mfaT<&Pz8[z#N|@dDt=Sdo{|W/|iN)IiH%f:cMCIZp2] >p$Camw"Qv9Shsl_K958?HA<6*iZYWO5 ~X8n@ rj]SC4" &*'! 5Nn(Sy #?b+@Sgv  uWB5&q[H;%wT<(s\F/%*).B[m.NdzBk"Jt<P]_UA(V~tjV:j:tM$ 4DKPVX]hw 7[vBq "3@Lb#*33/06CR_fW<  a3|lM%nL2s]B'//,.Gk3Vx =t3Qn  .CNI>84'  wP"|bG+ {S/xaN: ' )9EQZr%Ham}Bo-Ods|~mL)q\=$ yywpdJ%pX=*%2Kh~&-'*8U 4Tv%,@\we`dt}}p]E#zYB' r;tk{  ?)Bk=]wueUTbye="yV?654- yF .+ofl]QWr![K}Eqc7N&)#wCzWDCSi{dXe~3g.Kt   ,Pt{l]VWev{VZ2 l@%zkj9HG1 /Jq*48214Lx5HQJ/(@U^XG'v<  u8!3@B24ZeO'7QfqrgQ- .c-, ,HksXUn $.vllz`7 $1OfrcQ3y]C99?JXgu|g@'CQN>0 3gz 3;@3Aj9HCvtnK-a?11=DJF>4)9NOG628Nn &Kw6Tk{fXPPV^fjd\F+ oP* |U* ?\tvjt&2;IYy  7[wx];& /65 rpwx^8sdN5 '' $>Wo~zqr-+ 2Hd BTa[RE5! xy~c>dI68ASesz[@%+=ORL9 )Pq{iZWby :We`\QLKTc{\K>>IW_ZBt_UWelf`M?( (:>3 :WxiRIPmAk  {V4!'/5.iB 0Pw!Kv<W\YN=2.1<HSbpuuhZ@0${[6kXF953417CC>:7?Oc} 2Mr   9HQJ9& /?HJA3|[5z_E::BKPL?% 0Kavztv 2Mo~smkqthS+ta[_qmJ4('+1L[o}#/79?DKYj"('   rtxv[7{V4#)+& +43,(-CWx ",<GTd|  /ATbkrnbWKNWhw}dH-tQ+tN' dQFJ\q%'#!0@]2KYblu 22-'&'09Qosoqv{{qhZK3\9e=ocar !/76;;FYv2EPZak} &?Ub`R?0%%.?TedU6|wjU:gN9(  !  7Sjv{zxqmow"'*7ERg~%(q_QI;. }pbY[^[TH<8MZw?btwqjYL@9?Pf}rrr{qxdN:04AVisp_G'rbURU`ekaRB,'=M`lkd`^fu"<P^dfhjo| cI6)'$obXRTWWWH-#+++3:COcu!;Pg| 4BG>7/" yY5_E8/8AOQMB1! &1:AIUby '5DO]n "~iP;+nR@38@IG<0%%/89882&"*46@JR_mx -@Rh~ |xuy{|{rbTMC8."}ytpqof]UTMKKKLKIA5' !*/6BNVamv  (/:?CKV`hs}~qf]UKE=4-% }xvvvvsocN@4,()/6?BCCBDJXj{ "1C[oxhT?' pjiqx~yfQ6# "'(?Wr#;Rj |jQ. mVHAAC>4# 6Peu*7=<DK]t #*0," {qbWL=#vwusjZF-  &,+'%,6Ss-Gct~|sgehz|lb_^UKD;){le`YYUYbmzweM:+$+36:9=>BINQU`k!#'0;JS\fnuxjTD4* scL?75466/'# #06( ucUNNYh||uw}(:McloiaUPTWZbmw~|wlafl|zrkmooiZH2&!&" }tpngb^_gpxznh__jzwsgdft-:FJIFHN]k{r^TMRRVRF5! oZLCDHLNKE>50&  -9FKKF=47@JUcq (<IPX]aajuyhYNC?;;72'zgP=.$%07;8,$%3BLY`ggjdadl{)7??@=BIUcoyzeN?5.03.)#vf]VPMPPSWXVL@=1$').3-& {xxy{}}|wocUQS_t~{}$-.'!"2CVejf]O?.'#*<P`mtxtne\`hyue^RKKS_lqlYA*  wvx|jXPR_n 1>EB83-4ASdv~xvkfflv~{iVF=8;::80$}xvzz~xiWIAABLPY[^``c_ceu '467755=Rg}{m]O>8420) ~m[KA:99AIRTYOIB>>EO`oz} .<GQWUTXY]dq}f][YVTKC:0*$thhipxz~xofa`al #.DQUSKGA@<::@EPZ]_^XTTV\ccgmpvuk`PD=99=<96.$  !+041/(##'.8>FMVURF<2+&)38?AEA;6+$!&-6?@@4&   #*/..(',3?KV^c^XK@6413238:870+$ "+9DNPMGA:,! #((&1JbrvqhZOMOU\grz~ykZL>@AFMS[YVK?-  ,:@C@4+"&0@XpuhWLGOYfnppdVB3$#08BB;1 "" 2=?:0%-=M\`e]O=,&&/9AJKD6* !074,  #% #06:983(,4?DGC?72,(%)06:72+#'"  !#"  &% &3@FIHGB<=@IU]hjg\SD7.+*,37;91+   -383$ #9N[dfca]VWV^fq{xk]M?7203:BHNI?0    .885) "8HY`_TA4.*/8GR\\XM5  #+,+#  %)    19:- (5<B>9- '0/$ (:EOGA0  !%$   -;@8-*?QZYVL;0#&8DHE@.#-9ELQN?,"#   #+4;AA91.0:J^gi_PA97>=DGJT[YSI9-(,6=@86+!%-0.++',-2<HR`ddXNB?EM[dmlllh]RIEENZeidXH6,! $37982/48DQ^epuvqjaWVVZaklfcWQIA>8=?FLMI>2$  $,/0-(" %6EQTURGA>=9<>BDKMNL>4)!!.7>A<2&     *9<73*%!#%-6CJQRRK@;56>LV[]WTL=9-(%$%(+) "4:GNQPJ?8>CKU]adb_]VSMPVbpz~xiVE<752/-+%   (6=@A>94048HOZ_]VMHHFFKP[akli_UC7327:983' -;GLID>:66<DM\cdaSH?:;DNV\cdh`XM@>9?FNOLB0'/<GHD@64/15=IU_^ZK?5,+1=HT[]YSG=2,-2<DFG<-     *)120.+*(+2<FRX[[UTPQPPQQPRRKB<4'$!&(.))%&$  "(.4;<?BCHJNR[bhov~{nd\XTMLIGD:2(" |ustvxxxwwvxxxyx~'.49BEJSY_fiinpyzi]OD;72/*" }{yw{~ $*/67<AINQRQOJNRUW[[[acgigdhglmrsqnigcZRF?<981+$ #,022232356;;BEKNQOMLNPVZagjgha_XTNKJLMMLF><32/01.413*# $-6AJNRWZ]cgnu{vnge`]]]\XUQKD?977847743*#  +/6<?HR^lyyrlihkkmga_UK?4,#vkb^`_`\[URTPMKHOWbr*;HWalw~|qje^``YPI=-|kb^abfiojbYTNJOT`lv}}{vpnot '.5:;<=EKXft|qbRC2*%'),.( z~{wuz} !$+7CRW`aebcjns{zuniklmpke_UNE<<<??;<:3(xttvw{yvstrtsu} %09CMXagns}~~}{xsle_XMA8+  ~vjb_`^]YXQKIILMPUX\elsx$,9AIS]dltx{ti\OD93,%! zrkgdedb]ROH@=;>>GGPVZaglq| !+2:ALS\dovsdYNF?6,{l_XOOFB:840+%# !#%0:CKSYchlry *7GS_jou{zm_PA5){rjc^ZZ\__^_]YRPPR^fovz!.;CKV\dmt}|yuwvwsslbVJE<63-)! }yrqsz &)2=EQZ`acchinnrqvwxxwsroomsw{{}|vpbVSOMJJC=2& xvtuvwvqojcb`bdiq{ #.9DIPU^bjnx}yvutqh`SD4& wmcWRKIMJOMJJFIKMPV[bjr{(1@KV]afjns}yskeZI:+  sh]TQMLKHJKNNJGCFKTV_glsz #,4=ETYdkmtv|wqjaYPD6* slf_YUUW^aebZQLHKW^it~  '6DP^lsqnjlou|umjhijhbUE0 rh__cdintuuqje^`fs '8CNUWTRPTZht~sqnokgb[RH9* wpnru~ #$++/5<FP[dotssrpx|}pi[SIB:743,% |rd[SRPPT[]efmlcaXWam| ))*39DKWdptid^ZTKD9."zng`ZVTVTSNE<76?ENR[_efgfgjow+5;ABDKYkz{o^QD<=;>4( ~wx{~|yurmg_ZRR[et||rmhjktz  &((*05@KZkrvvqorv{|mh_XTNNMNI@6( uoihglrv{zvmcbelw'/:ENOSSPV^fs}zspigfd_ZSG6* }}ztprw%-4=@EFKJS^ir}}xnhjjkmlkgbXM>71,.,( ~||wyuz{  !%(,6=BJS\hlqsy}xrgbYVPJC=95-#zsrtvxxuqklijifghotywywss{&4@BJKMTX_goz}}xpfUI>:6/+! ungbabdiosqhe]]`gqx'2=HLOMNRVcoxzrmhkgdc^XSK?3(#{sljkt}&*3199<BER\gqy{{z{~sqrqpokka]VKD=:55460% {xxx|~ '3?HT[__ejmyvmjb__`\\TRHA6( ~snlkknpnnnnjfhip{ %.=GPX\cgls~xrhfa_c_WN@2& ysnpow{}xsld\]`gp| (:GNQVW\_grw|rgaa^bee`UG6) {somsuwyxwslfc_elw-:DGOQRVZbkx~tlca]ZZYUNE94' ~  ,5>DFJNRWafnz{xspnrrmplie_[UTQQNNNIC<2&   )+**-05>HPW`fgggddggjkorqqmhe_[XYZ\\_ZTOC94,,+'#  $+6AOX\``ab_bflsx|}}}yuvy~yrhbZSMJ@=1( }tnkkpnow{{z{xx{ '6BTaou|~z{}|{qf^RNIGC>8-#yslfilqvx~~ "-;IV`hikonrvx}~|uu{~}yukg]UNIGA;6* xyt}|~  %-:ANY_dheknqvy|}wqonrsrojkc_ZSNG@?=:71&  ,4?FNVY`ehinqtwtzxvutqqqprpqqmkfb_\TTQKIE;8.*  $+2;AKRW`cahknrptsttuvz{zzyzyxyvvstokd^UKD<5/'  ~xtorqrvwzxwzx}!)1:DKTZ_dgfmnuw~xurhcZSKB4-#~xsroqstxx|yusuu~!.;AKSY`egkot{~zwpmc[SH<3( }tnjedddchilooqsx &2>GNTX^bipx}vqib]UK@/$}|z~{||xusv| #0=DLQSRWZ_bgjhkhkjfghdgintuvsqomkmfhb\XQLB:/) $/4<?DFOPW^\a^cfjllklloqrwtqokoomie`ZUPKE=60*# !*2<>FJMSWXWZ\cfowvxy~xrf_ZVQKD=4-*# ,4<BDGOSX\befijionnquwx~}}ywrsjh`YTLC>61'! ||{z~ $-9>FJNPTU[`cglosw{|wog\VNGB@81,$}z|{}'07;>BBNSY[`a`_]`ahhprswuvtqrrmmife`[OJ>:6,*)&  #'+3;@DCDHEILMTX]_begihgecdbba_][WSNF@>:630.*%!  $)/4:?BHOSW[\adjoqsvuzxuyvvtojha]VQLIBE>:60,&   ).59=ACJJNSW\`dgioruvwuvstrnlge]XRMLEB=:40*($  ")-137:?CELPVZ[]_aehjknrproihceb^YSNIFDA<66..+&  #'-446;99=ADHNPV[bfhljigfgjhgc[[VOJD;:7552/+'  $+1:;>@@DGKKLQRWUWXYZY\[^]]ZWYVPMKHEB@<82-&  !$'./3469;BEKOU[`bbac_`]_^]WROLFCB>=<=97750,$!  #)-/27=@HMSU]`c`ccabfdgedcaZXSORMNJKMF@=71+%   #,-347=>BGKRX[\_ejkmjkniijhkgda]XTOJC@<982+&  "%,,036;=CELOWTVYWZTSSTUVUVTOMIFEE@B?<<;73-*(&#   '+18:?DEJNQOTSWYZWSRQNJMJLKLKJFEEBAAAA?;92*$   (-4:=DJMSVY]``ab^^ZXTTQPQNMJJCDABAABA?:5,*  $(-36;=EHNSVW[]^`a`\^ZXWYWUTONMKIFFGEDB?:3.($ %'15=CLTY`bfdeghlnrqqpnjihdfac``\ZUPLD;9.+'!  !%*,/4<@FP[bghlkijloonnlff_ZUQKLIHIE@<:3*%"  +/7=?@HFEHDEHIKKIGEDA@@B>BB?AB><:6511-+(  !)./25:=ACIKOMMMIEECFBHFFGFDDGCGFGFGGC>:5-)#  #(-037;?@JLRSSRQNLGFFJKKKKIIEC@BA@CD><8/*$   &).18<@EHNRSONNOMOPPSTWRTROJJFFFFA=:51("  !+056<>AFLQUYYWWVSLIEEFFGHEE@><<<;:9;;=81)!  "&*+-/37;BEFHHIGDAA??@@A??=9:;74630.*+'$  $)-/1///00654555676432589=;?<;43/.+((*%   '((')*14:@AGIJONMLKIKONOQOJGE><842421.'$ ),687:9<>CDHHJLIIFDCGGOQSTVSNIDB=<;6640)"  %-226678=?@HIIIEDACABBCFGGEA@8886220,*&! "#(*-347;:8:94869<<=:;===8:8552/-+&!  !"())./-.2/134;<<=<:9;;8<>976362/*&!    "&&+)026577;<<????><<9943/-+)&   !#%,+.049:==>>BDFJIMJOMKHD?97630.($!  !$%('+-.-/02588::778:;;@?@C=A@:720-+)%#  #%***,'(+-.155798653/,,*-.-.*(&   "&'.0332224227:=>@A@B=:843220.*)$! ")'**&&)*37<?@DDBB>>8;:;?>=93-)#  !  "'$()'.6:=DCGDGFFEFFGGJFFD?954///--+)'  "")*01:==EFHLKLKLKLIEGEB>;64/**')&#    "%+,0000/0226342201--,-*+*(&$%'&## !   "#&(),./3579<8;:753524352.*+('%$$#!   !!$$&(*/249==;<::86876:::87421*,'(%'#  !$%')+*1247;<;><;=:===@CDCA?=8764120.(%!  #(-266:=?AGHKLIMHICCBBA@AA?>;866131,,%$  $%+,0258<=;><=<;=;=<=>=?@><::65320+(&   &().-.003123458869::;98686979520+(&!!  #%+1256;8=<>>=>AABAB@B=@>@>??>??<:92/+'#!   '*.24;;?ACBGKLLLMMOPQQPRPQMOKGD=:852/'#%*367:;>;?AEGKLNPMNKJKJMNLOJIEA?:6623-+&  #)05;>@?@CCDGIGLKLIEGB>?>B@C>=:730*(($#!!  #(,/3335589=>>BB@@??<??ADBE@B?:52/-++)&!  &)*++,-147:<=?>B@CCFGFIKLLIGBA<;;7820+&  !'(+/357<?CDHFGHILMQOVVXWUVTPMKKEHA>:5-(#   &(..5<?@FKNQOSSURUW[\]]^ZZTVQPNKIGC>82+$  "'(+/6:?CFLMNOMMNOOQTTXYWYQQOIEGFBB;;1,'  !$('.-2489@>AAB@?AADGLMQSSQMLLIEHCC?<41)$!   ")*03565563269=?@EDCCEB@ABBBBB<:4.($"  "%+.-/01159?BEGIKLJIJMMRRSQRNHD<:8034.-)$  %'+-03067=>BFKORSRTSUVWWZ[[USPIC?:752/*&!   %+-11258:<?DEIKKMMOLNPTQTPPOHD?=842,,%#  $%),0378?CAFHILKNNMQQMRNMKHF@?9;752-(#    #''+/255799==?AECFFGEDEB><:750-+)"    ''+/0166:9>?ECFGGGFBC=@<<9::94//)%"$"!!  '+.37:;;@AELPTTXVUSPPQMQNMMIFA:82//+*+'!  !'*037=<=>BDFLNRVUTSQNJGGGFGDA=:60**&# !  "*,032538<=AFILKLIGC@ACADCC>;;5/+)('(&%$ !$%(++-048:?>CDCCAB?AAB@?><:862.-)()&%"  !%(.256:=<????BAB?EE@?=<;9;97952.+)#   $(+03;;@?AEDCFIKLOKJJFFAB@?>@;=7510,'&#  #'*049@AFFIJMNMQSTRVRPOKFDA@><<;66-+'$  !#(+.57==>BDDFFFIKKNNJJEFA?=;68543*(#  "$,,34557;<<=C@C=@><;:99;77820.*)&#   #$&(+-0258:;>??>??=;<<;<9;66321,.,'$"!  "'(+/027779<?ECEBDB=??>@<=;:952.+('#   %,,566;<>ADDFIJKLLGGFDDA?=>9783/(#"   %+057:9;99<<<?@>@>?;:87835424-*%#"   "$(./223132142445240-+(&$%"!!  ""'&&%'%%&&%&&'%&%&%&$$#"!!   !"#&&()'(+,-,-0,/0-1-,.--0/-*))##"  $"&)).0164486784778875430-,+,')%#   '&'++../025576775323321522.-+%##!  !$#&%)))..0/0/1,,)*'((())%     " !   !       !"! !!!  ! !!    " !"$#$$%#"$                                                                       psi-0.14/configure0000755000175000017500000016646611305557613012273 0ustar janjan#!/bin/sh # # Generated by qconf 1.5 ( http://delta.affinix.com/qconf/ ) # show_usage() { cat </dev/null` if echo $WHICH | grep 'shell built-in command' >/dev/null 2>&1; then WHICH=which elif [ -z "$WHICH" ]; then if which which >/dev/null 2>&1; then WHICH=which else for a in /usr/ucb /usr/bin /bin /usr/local/bin; do if [ -x $a/which ]; then WHICH=$a/which break; fi done fi fi if [ -z "$WHICH" ]; then OLD_IFS=$IFS IFS=: for a in $PATH; do if [ -x $a/$1 ]; then echo "$a/$1" IFS=$OLD_IFS export IFS HOME=$OLD_HOME export HOME return 0 fi done IFS=$OLD_IFS export IFS else a=`"$WHICH" "$1" 2>/dev/null` if [ ! -z "$a" -a -x "$a" ]; then echo "$a" HOME=$OLD_HOME export HOME return 0 fi fi HOME=$OLD_HOME export HOME return 1 } WHICH=which_command # find a make command if [ -z "$MAKE" ]; then MAKE= for mk in gmake make; do if $WHICH $mk >/dev/null 2>&1; then MAKE=`$WHICH $mk` break fi done if [ -z "$MAKE" ]; then echo "You don't seem to have 'make' or 'gmake' in your PATH." echo "Cannot proceed." exit 1 fi fi show_qt_info() { printf "Be sure you have a proper Qt 4.0 build environment set up. This means not\n" printf "just Qt, but also a C++ compiler, a make tool, and any other packages\n" printf "necessary for compiling C++ programs.\n" printf "\n" printf "If you are certain everything is installed, then it could be that Qt 4 is not\n" printf "being recognized or that a different version of Qt is being detected by\n" printf "mistake (for example, this could happen if \$QTDIR is pointing to a Qt 3\n" printf "installation). At least one of the following conditions must be satisfied:\n" printf "\n" printf " 1) --qtdir is set to the location of Qt\n" printf " 2) \$QTDIR is set to the location of Qt\n" printf " 3) QtCore is in the pkg-config database\n" printf " 4) qmake is in the \$PATH\n" printf "\n" printf "This script will use the first one it finds to be true, checked in the above\n" printf "order. #3 and #4 are the recommended options. #1 and #2 are mainly for\n" printf "overriding the system configuration.\n" printf "\n" } while [ $# -gt 0 ]; do optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` case "$1" in --prefix=*) PREFIX=$optarg shift ;; --bindir=*) BINDIR=$optarg shift ;; --libdir=*) LIBDIR=$optarg shift ;; --datadir=*) DATADIR=$optarg shift ;; --qtdir=*) EX_QTDIR=$optarg shift ;; --release) QC_RELEASE="Y" shift ;; --debug) QC_DEBUG="Y" shift ;; --no-separate-debug-info) QC_NO_SEPARATE_DEBUG_INFO="Y" shift ;; --separate-debug-info) QC_SEPARATE_DEBUG_INFO="Y" shift ;; --certstore-path=*) QC_CERTSTORE_PATH=$optarg shift ;; --disable-bundled-qca) QC_DISABLE_bundled_qca="Y" shift ;; --with-qca=*) QC_WITH_QCA=$optarg shift ;; --disable-openssl) QC_DISABLE_openssl="Y" shift ;; --with-openssl-inc=*) QC_WITH_OPENSSL_INC=$optarg shift ;; --with-openssl-lib=*) QC_WITH_OPENSSL_LIB=$optarg shift ;; --with-zlib-inc=*) QC_WITH_ZLIB_INC=$optarg shift ;; --with-zlib-lib=*) QC_WITH_ZLIB_LIB=$optarg shift ;; --enable-universal) QC_ENABLE_universal="Y" shift ;; --disable-qdbus) QC_DISABLE_qdbus="Y" shift ;; --disable-growl) QC_DISABLE_growl="Y" shift ;; --with-growl=*) QC_WITH_GROWL=$optarg shift ;; --disable-xss) QC_DISABLE_xss="Y" shift ;; --disable-aspell) QC_DISABLE_aspell="Y" shift ;; --with-aspell-inc=*) QC_WITH_ASPELL_INC=$optarg shift ;; --with-aspell-lib=*) QC_WITH_ASPELL_LIB=$optarg shift ;; --disable-enchant) QC_DISABLE_enchant="Y" shift ;; --verbose) QC_VERBOSE="Y" shift ;; --help) show_usage; exit ;; *) show_usage; exit ;; esac done PREFIX=${PREFIX:-/usr/local} BINDIR=${BINDIR:-$PREFIX/bin} LIBDIR=${LIBDIR:-$PREFIX/lib} DATADIR=${DATADIR:-$PREFIX/share} echo "Configuring Psi ..." if [ "$QC_VERBOSE" = "Y" ]; then echo echo PREFIX=$PREFIX echo BINDIR=$BINDIR echo LIBDIR=$LIBDIR echo DATADIR=$DATADIR echo EX_QTDIR=$EX_QTDIR echo QC_RELEASE=$QC_RELEASE echo QC_DEBUG=$QC_DEBUG echo QC_NO_SEPARATE_DEBUG_INFO=$QC_NO_SEPARATE_DEBUG_INFO echo QC_SEPARATE_DEBUG_INFO=$QC_SEPARATE_DEBUG_INFO echo QC_CERTSTORE_PATH=$QC_CERTSTORE_PATH echo QC_DISABLE_bundled_qca=$QC_DISABLE_bundled_qca echo QC_WITH_QCA=$QC_WITH_QCA echo QC_DISABLE_openssl=$QC_DISABLE_openssl echo QC_WITH_OPENSSL_INC=$QC_WITH_OPENSSL_INC echo QC_WITH_OPENSSL_LIB=$QC_WITH_OPENSSL_LIB echo QC_WITH_ZLIB_INC=$QC_WITH_ZLIB_INC echo QC_WITH_ZLIB_LIB=$QC_WITH_ZLIB_LIB echo QC_ENABLE_universal=$QC_ENABLE_universal echo QC_DISABLE_qdbus=$QC_DISABLE_qdbus echo QC_DISABLE_growl=$QC_DISABLE_growl echo QC_WITH_GROWL=$QC_WITH_GROWL echo QC_DISABLE_xss=$QC_DISABLE_xss echo QC_DISABLE_aspell=$QC_DISABLE_aspell echo QC_WITH_ASPELL_INC=$QC_WITH_ASPELL_INC echo QC_WITH_ASPELL_LIB=$QC_WITH_ASPELL_LIB echo QC_DISABLE_enchant=$QC_DISABLE_enchant echo fi printf "Verifying Qt 4 build environment ... " # run qmake -v and check version qmake_check_v4() { if [ -x "$1" ]; then if echo `$1 -v 2>&1` | grep "Qt version 4\." >/dev/null 2>&1; then return 0 elif [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: $1 not for Qt 4" fi fi return 1 } if [ "$QC_VERBOSE" = "Y" ]; then echo fi qm="" names="qmake-qt4 qmake4 qmake" # qt4 check: --qtdir if [ -z "$qm" ] && [ ! -z "$EX_QTDIR" ]; then for n in $names; do qstr=$EX_QTDIR/bin/$n if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via --qtdir" fi # qt4 check: QTDIR if [ -z "$qm" ] && [ ! -z "$QTDIR" ]; then for n in $names; do qstr=$QTDIR/bin/$n if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via \$QTDIR" fi # qt4 check: pkg-config if [ -z "$qm" ]; then str=`pkg-config QtCore --variable=exec_prefix 2>/dev/null` if [ ! -z "$str" ]; then for n in $names; do qstr=$str/bin/$n if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via pkg-config" fi # qt4 check: PATH if [ -z "$qm" ]; then for n in $names; do qstr=`$WHICH $n 2>/dev/null` if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via \$PATH" fi if [ -z "$qm" ]; then if [ "$QC_VERBOSE" = "Y" ]; then echo " -> fail" else echo "fail" fi printf "\n" printf "Reason: Unable to find the 'qmake' tool for Qt 4.\n" printf "\n" show_qt_info exit 1; fi if [ "$QC_VERBOSE" = "Y" ]; then echo qmake found in $qm fi # try to determine the active makespec defmakespec=$QMAKESPEC if [ -z "$defmakespec" ]; then if $WHICH readlink >/dev/null 2>&1; then READLINK=`$WHICH readlink` fi if [ ! -z "$READLINK" ]; then qt_mkspecsdir=`$qm -query QT_INSTALL_DATA`/mkspecs if [ -d "$qt_mkspecsdir" ] && [ -h "$qt_mkspecsdir/default" ]; then defmakespec=`$READLINK $qt_mkspecsdir/default` fi fi fi if [ "$QC_VERBOSE" = "Y" ]; then echo makespec is $defmakespec fi qm_spec="" # if the makespec is macx-xcode, force macx-g++ if [ "$defmakespec" = "macx-xcode" ]; then qm_spec=macx-g++ QMAKESPEC=$qm_spec export QMAKESPEC if [ "$QC_VERBOSE" = "Y" ]; then echo overriding makespec to $qm_spec fi fi gen_files() { cat >$1/modules.cpp <= 4.4.0 -----END QCMOD----- */ class qc_qt4 : public ConfObj { public: qc_qt4(Conf *c) : ConfObj(c) {} QString name() const { return "Qt >= 4.4.0"; } QString shortname() const { return "qt4"; } bool exec() { return(QT_VERSION >= 0x040400); } }; #line 1 "buildmodeapp.qcm" /* -----BEGIN QCMOD----- name: buildmodeapp section: project arg: release,Build with debugging turned off (default). arg: debug,Build with debugging turned on. arg: no-separate-debug-info,Do not store debug information in a separate file (default for mac). arg: separate-debug-info,Strip debug information into a separate .debug file (default for non-mac). -----END QCMOD----- arg: debug-and-release,Build two versions, with and without debugging turned on (mac only). */ #define QC_BUILDMODE bool qc_buildmode_release = false; bool qc_buildmode_debug = false; bool qc_buildmode_separate_debug_info = false; class qc_buildmodeapp : public ConfObj { public: qc_buildmodeapp(Conf *c) : ConfObj(c) {} QString name() const { return "buildmodeapp"; } QString shortname() const { return "buildmodeapp"; } // no output QString checkString() const { return QString(); } bool exec() { // first, parse out the options bool opt_release = false; bool opt_debug = false; bool opt_debug_and_release = false; bool opt_no_separate_debug_info = false; bool opt_separate_debug_info = false; if(conf->getenv("QC_RELEASE") == "Y") opt_release = true; if(conf->getenv("QC_DEBUG") == "Y") opt_debug = true; if(conf->getenv("QC_DEBUG_AND_RELEASE") == "Y") opt_debug_and_release = true; if(conf->getenv("QC_NO_SEPARATE_DEBUG_INFO") == "Y") opt_no_separate_debug_info = true; if(conf->getenv("QC_SEPARATE_DEBUG_INFO") == "Y") opt_separate_debug_info = true; bool staticmode = false; if(conf->getenv("QC_STATIC") == "Y") staticmode = true; #ifndef Q_OS_MAC if(opt_debug_and_release) { printf("\nError: The --debug-and-release option is for mac only.\n"); exit(1); } #endif // sanity check exclusive options int x; // build mode x = 0; if(opt_release) ++x; if(opt_debug) ++x; if(opt_debug_and_release) ++x; if(x > 1) { printf("\nError: Use only one of --release, --debug, or --debug-and-release.\n"); exit(1); } // debug info x = 0; if(opt_no_separate_debug_info) ++x; if(opt_separate_debug_info) ++x; if(x > 1) { printf("\nError: Use only one of --separate-debug-info or --no-separate-debug-info\n"); exit(1); } // now process the options if(opt_release) qc_buildmode_release = true; else if(opt_debug) qc_buildmode_debug = true; else if(opt_debug_and_release) { qc_buildmode_release = true; qc_buildmode_debug = true; } else // default qc_buildmode_release = true; if(opt_separate_debug_info) qc_buildmode_separate_debug_info = true; else if(opt_no_separate_debug_info) { // nothing to do } else // default { #ifndef Q_OS_MAC qc_buildmode_separate_debug_info = true; #endif } // make the string QStringList opts; QString other; if(qc_buildmode_release && qc_buildmode_debug) { opts += "debug_and_release"; opts += "build_all"; } else if(qc_buildmode_release) opts += "release"; else // qc_buildmode_debug opts += "debug"; if(qc_buildmode_separate_debug_info) { opts += "separate_debug_info"; other += "*-g++*:QMAKE_CFLAGS += -g\n"; other += "*-g++*:QMAKE_CXXFLAGS += -g\n"; } QString str = QString("CONFIG += ") + opts.join(" ") + '\n'; conf->addExtra(str); if(!other.isEmpty()) conf->addExtra(other); return true; } }; #line 1 "bundled-qca.qcm" /* -----BEGIN QCMOD----- name: Use bundled QCA -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_bundled_qca //---------------------------------------------------------------------------- class qc_bundled_qca : public ConfObj { public: qc_bundled_qca(Conf *c) : ConfObj(c) {} QString name() const { return "bundled QCA 2.0"; } QString shortname() const { return "bundled_qca"; } bool exec() { // FIXME: Check QCA version number if (QFile::exists("third-party/qca/qca")) { conf->addExtra("CONFIG += qca-static"); conf->addDefine("QCA_NO_PLUGINS"); return true; } else { return false; } } }; #line 1 "qca.qcm" /* -----BEGIN QCMOD----- name: QCA >= 2.0 arg: with-qca=[path],Specify path to QCA tree, mainly for building against an uninstalled QCA. -----END QCMOD----- */ // based on crypto.prf. any changes made to that file need to be tracked here. static QString internal_crypto_prf(const QString &incdir, const QString &libdir) { QString out = QString( "QCA_INCDIR = %1\n" "QCA_LIBDIR = %2\n" "\n" "CONFIG *= qt\n" "\n" "LINKAGE =\n" "\n" "# on mac, if qca was built as a framework, link against it\n" "mac: {\n" " framework_dir = \$\$QCA_LIBDIR\n" " exists(\$\$framework_dir/qca.framework) {\n" " #QMAKE_FRAMEWORKPATH *= \$\$framework_dir\n" " LIBS += -F\$\$framework_dir\n" " INCLUDEPATH += \$\$framework_dir/qca.framework/Headers\n" " LINKAGE = -framework qca\n" " }\n" "}\n" "\n" "# else, link normally\n" "isEmpty(LINKAGE) {\n" " INCLUDEPATH += \$\$QCA_INCDIR/QtCrypto\n" " LIBS += -L\$\$QCA_LIBDIR\n" " LINKAGE = -lqca\n" " CONFIG(debug, debug|release) {\n" " windows:LINKAGE = -lqcad\n" " mac:LINKAGE = -lqca_debug\n" " }\n" "}\n" "\n" "LIBS += \$\$LINKAGE\n" ).arg(incdir, libdir); return out; } //---------------------------------------------------------------------------- // qc_qca //---------------------------------------------------------------------------- class qc_qca : public ConfObj { public: qc_qca(Conf *c) : ConfObj(c) {} QString name() const { return "QCA >= 2.0"; } QString shortname() const { return "qca"; } // BEGIN PSI QString checkString() const { if(QFile::exists("third-party/qca/qca") && conf->getenv("QC_DISABLE_bundled_qca").isEmpty()) return ""; else return ConfObj::checkString(); } // END PSI bool exec() { // BEGIN PSI // Check if we have a bundled version if(QFile::exists("third-party/qca/qca") && conf->getenv("QC_DISABLE_bundled_qca").isEmpty()) return true; // END PSI // get the build mode #ifdef QC_BUILDMODE bool release = qc_buildmode_release; bool debug = qc_buildmode_debug; #else // else, default to just release mode bool release = true; bool debug = false; #endif // test for "crypto" feature and check qca version number QString qca_prefix, qca_incdir, qca_libdir, qca_crypto_prf; qca_prefix = conf->getenv("QC_WITH_QCA"); QString proextra; if(!qca_prefix.isEmpty()) { qca_incdir = qca_prefix + "/include"; qca_libdir = qca_prefix + "/lib"; qca_crypto_prf = internal_crypto_prf(qca_incdir, qca_libdir); proextra = "CONFIG += qt\n" "QT -= gui\n"; proextra += qca_crypto_prf; } else { proextra = "CONFIG += qt crypto\n" "QT -= gui\n"; } QString str = "#include \n" "\n" "int main()\n" "{\n" " unsigned long x = QCA_VERSION;\n" " if(x >= 0x020000 && x < 0x030000) return 0; else return 1;\n" "}\n"; if(release) { int ret; if(!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += release\n", &ret)) return false; if(ret != 0) return false; } if(debug) { int ret; if(!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += debug\n", &ret)) return false; if(ret != 0) return false; } if(!qca_prefix.isEmpty()) conf->addExtra(qca_crypto_prf); else conf->addExtra("CONFIG += crypto\n"); return true; } }; #line 1 "openssl.qcm" /* -----BEGIN QCMOD----- name: OpenSSL (bundled QCA only) arg: with-openssl-inc=[path],Path to OpenSSL include files (bundled QCA only) arg: with-openssl-lib=[path],Path to OpenSSL library files (bundled QCA only) -----END QCMOD----- */ class qc_openssl : public ConfObj { public: qc_openssl(Conf *c) : ConfObj(c) {} QString name() const { return "OpenSSL"; } QString shortname() const { return "openssl"; } QString checkString() const { if (!QFile::exists("third-party/qca/qca") || !conf->getenv("QC_DISABLE_bundled_qca").isEmpty()) return ""; else return ConfObj::checkString(); } bool exec() { if (!QFile::exists("third-party/qca/qca") || !conf->getenv("QC_DISABLE_bundled_qca").isEmpty() || !QFile::exists("third-party/qca/qca-ossl")) return false; #ifdef Q_OS_WIN QString ossl_inc = conf->getenv("QC_WITH_OPENSSL_INC"); if(ossl_inc.isEmpty()) return false; QString ossl_lib = conf->getenv("QC_WITH_OPENSSL_LIB"); if(ossl_lib.isEmpty()) return false; QStringList libnames; libnames += "-llibeay32 -lssleay32"; libnames += "-leay32 -lssl32"; libnames += "-leay32 " + ossl_lib + "/ssleay32.a"; bool success = false; QString libname_success; foreach(const QString &libname, libnames) { QString str = "#include\n" "int main()\n" "{\n" " unsigned long x = OPENSSL_VERSION_NUMBER;\n" " if(x >= 0x00907000) return 0; else return 1;\n" "}\n"; QString ext; QStringList incs; incs += ossl_inc; ext += QString("-L") + ossl_lib + " " + libname; int ret; if(conf->doCompileAndLink(str, incs, ext, QString(), &ret)) { success = true; libname_success = libname; if(ret == 0) conf->addDefine("OSSL_097"); break; } } if(!success) return false; conf->addIncludePath(ossl_inc); conf->addLib(QString("-L") + ossl_lib); conf->addLib(libname_success); conf->addDefine("HAVE_OPENSSL"); return true; #else QString inc, lib; QString s; bool kb = false; QString kbdir = "/usr/kerberos/include"; // Redhat 9? if(QFileInfo(kbdir).exists()) kb = true; s = conf->getenv("QC_WITH_OPENSSL_INC"); if(!s.isEmpty()) { if(!conf->checkHeader(s, "openssl/ssl.h")) return false; inc = s; } else { if(!conf->findHeader("openssl/ssl.h", QStringList(), &s)) return false; inc = s; } s = conf->getenv("QC_WITH_OPENSSL_LIB"); if(!s.isEmpty()) { if(!conf->checkLibrary(s, "ssl")) return false; lib = s; } else { if(!conf->findLibrary("ssl", &s)) return false; lib = s; } // is it at least openssl 0.9.7? QString str = "#include\n" "int main()\n" "{\n" " unsigned long x = OPENSSL_VERSION_NUMBER;\n" " if(x >= 0x00907000) return 0; else return 1;\n" "}\n"; QString ext; QStringList incs; if(!inc.isEmpty()) incs += inc; if(kb) incs += kbdir; if(!lib.isEmpty()) ext += QString("-L") + lib + " -lssl -lcrypto "; int ret; if(!conf->doCompileAndLink(str, incs, ext, QString(), &ret)) return false; if(ret == 0) conf->addDefine("OSSL_097"); if(!inc.isEmpty()) conf->addIncludePath(inc); if(kb) conf->addIncludePath(kbdir); if(!lib.isEmpty()) conf->addLib(QString("-L") + s); conf->addLib("-lssl -lcrypto"); conf->addDefine("HAVE_OPENSSL"); return true; #endif } }; #line 1 "zlib.qcm" /* -----BEGIN QCMOD----- name: zlib arg: with-zlib-inc=[path],Path to zlib include files arg: with-zlib-lib=[path],Path to zlib library files -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_zlib //---------------------------------------------------------------------------- class qc_zlib : public ConfObj { public: qc_zlib(Conf *c) : ConfObj(c) {} QString name() const { return "zlib"; } QString shortname() const { return "zlib"; } #ifdef Q_OS_WIN QString resultString() const { return "using bundled"; } #endif bool exec() { #ifdef Q_OS_WIN // HACK: on windows, always use psi's bundled zlib conf->addExtra("CONFIG += psi-zip"); return true; #else QString inc, lib; QString s; s = conf->getenv("QC_WITH_ZLIB_INC"); if(!s.isEmpty()) { if(!conf->checkHeader(s, "zlib.h")) return false; inc = s; } else { if(!conf->findHeader("zlib.h", QStringList(), &s)) return false; inc = s; } s = conf->getenv("QC_WITH_ZLIB_LIB"); if(!s.isEmpty()) { if(!conf->checkLibrary(s, "z")) return false; lib = s; } else { if(!conf->findLibrary("z", &s)) return false; lib = s; } if(!inc.isEmpty()) conf->addIncludePath(inc); if(!lib.isEmpty()) conf->addLib(QString("-L") + s); conf->addLib("-lz"); return true; #endif } }; #line 1 "universal.qcm" /* -----BEGIN QCMOD----- name: Mac OS X universal binary support -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_universal //---------------------------------------------------------------------------- class qc_universal : public ConfObj { public: qc_universal(Conf *c) : ConfObj(c) {} QString name() const { return "universal binary support"; } QString shortname() const { return "universal"; } QString checkString() const { return QString(); } bool exec() { #ifdef Q_WS_MAC conf->addExtra("CONFIG += qc_universal"); #endif return true; } }; #line 1 "certstore.qcm" /* -----BEGIN QCMOD----- name: certstore section: project arg: certstore-path=[path],Path to the SSL/X509 Certificate store file (bundled QCA only) -----END QCMOD----- */ class qc_certstore : public ConfObj { public: qc_certstore(Conf *c) : ConfObj(c) {} QString name() const { return "certstore"; } QString shortname() const { return "certstore"; } QString checkString() const { if (!QFile::exists("third-party/qca/qca") || !conf->getenv("QC_DISABLE_bundled_qca").isEmpty()) return ""; else return ConfObj::checkString(); } bool exec() { if (!QFile::exists("third-party/qca/qca") || !conf->getenv("QC_DISABLE_bundled_qca").isEmpty() || !QFile::exists("third-party/qca/qca-ossl")) { return true; } bundled = false; #if defined(Q_OS_WIN) || defined(Q_OS_MAC) // use built-in return true; #else QStringList pathsToTry; path = conf->getenv("QC_CERTSTORE_PATH"); if(!path.isEmpty()) { if(QFile::exists(path)) { QString certPathString = "QCA_SYSTEMSTORE_PATH=\\\\\\\\\\\\\"" + path + "\\\\\\\\\\\\\""; conf->addDefine(certPathString); return true; } return false; } // This is from Debian pathsToTry.append( QString("/etc/ssl/certs/ca-certificates.crt") ); // Fedora Core 2 uses these pathsToTry.append( QString("/usr/share/ssl/cert.pem") ); pathsToTry.append( QString("/usr/share/ssl/certs/ca-bundle.crt") ); // Fedora Core 5 changes to this pathsToTry.append( QString("/etc/pki/tls/cert.pem") ); for(int n = 0; n < pathsToTry.count(); ++n) { if(QFile::exists(pathsToTry[n])) { path = pathsToTry[n]; break; } } // fall back to bundled if(path.isEmpty()) { // --prefix=\$pwd ? if(QFile::exists(conf->getenv("PREFIX") + "/certs/rootcerts.pem")) path = "\$\$PREFIX/certs/rootcerts.pem"; else path = "\$\$DATADIR/psi/certs/rootcerts.pem"; QString extra = "qcasharedfiles.path = \$\$DATADIR/psi\n" "qcasharedfiles.files = third-party/qca/qca/certs\n" "INSTALLS += qcasharedfiles\n"; conf->addExtra(extra); bundled = true; } // Qt<4.2 workaround QString certPathString = "QCA_SYSTEMSTORE_PATH=\\\\\\\\\\\\\"" + path + "\\\\\\\\\\\\\""; conf->addDefine(certPathString); return true; #endif } QString resultString() const { #if defined(Q_OS_WIN) return "using Windows built-in"; #elif defined(Q_OS_MAC) return "using Mac built-in"; #else if(success) { if(bundled) return "using bundled"; else return path; } else return ConfObj::resultString(); #endif } private: QString path; bool bundled; }; #line 1 "qdbus.qcm" /* -----BEGIN QCMOD----- name: QDBUS -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_qdbus //---------------------------------------------------------------------------- class qc_qdbus : public ConfObj { public: qc_qdbus(Conf *c) : ConfObj(c) {} QString name() const { return "QDBUS"; } QString shortname() const { return "qdbus"; } bool exec() { if (!conf->getenv("QC_DISABLE_qdbus").isEmpty()) return false; // test for "qdbus" feature QString proextra = "CONFIG += qt qdbus\n" "QT -= gui\n"; QString str = "\n" "int main()\n" "{\n" " return 0;\n" "}\n"; int ret; if(!conf->doCompileAndLink(str, QStringList(), QString(), proextra, &ret)) return false; if(ret != 0) return false; conf->addExtra("CONFIG += dbus"); return true; } }; #line 1 "growl.qcm" /* -----BEGIN QCMOD----- name: Growl arg: with-growl=[path],Path to the Growl framework -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_growl //---------------------------------------------------------------------------- class qc_growl : public ConfObj { public: qc_growl(Conf *c) : ConfObj(c) {} QString name() const { return "Growl"; } QString shortname() const { return "growl"; } #ifndef Q_OS_MAC QString checkString() const { return QString(); } #endif // TODO: This should go into ConfObj bool checkFramework(const QString &path, const QString &name) { QString str = "int main()\n" "{\n" " return 0;\n" "}\n"; QString extra; if(!path.isEmpty()) extra += QString("-F") + path + ' '; extra += QString("-framework ") + name; if(!conf->doCompileAndLink(str, QStringList(), extra, "", NULL)) return false; return true; } // TODO: This should go into ConfObj void addFrameworkPath(const QString& str) { conf->addExtra("QMAKE_CXXFLAGS += -F" + str); conf->addLib("-F" + str); } bool exec() { #ifdef Q_OS_MAC QString growl_path = conf->getenv("QC_WITH_GROWL"); if(!checkFramework(growl_path, "Growl")) return false; if(!growl_path.isEmpty()) addFrameworkPath(growl_path); conf->addLib("-framework Growl"); conf->addDefine("HAVE_GROWL"); return true; #else return false; #endif } }; #line 1 "xss.qcm" /* -----BEGIN QCMOD----- name: the XScreenSaver extension -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_xss //---------------------------------------------------------------------------- class qc_xss : public ConfObj { public: qc_xss(Conf *c) : ConfObj(c) {} QString name() const { return "the XScreenSaver extension"; } QString shortname() const { return "xss"; } #ifdef Q_OS_WIN QString checkString() const { return QString(); } #endif bool exec() { #ifdef Q_OS_WIN // skip XSS support on windows return false; #else QString str = "#include\n" "#include\n" "#include\n" "\n" "int main()\n" "{\n" " XScreenSaverQueryExtension(NULL, NULL, NULL);\n" " return 0;\n" "}\n"; QString proextra = "CONFIG += x11\n"; if (!conf->doCompileAndLink(str, QStringList(), "-lXss", proextra, NULL)) { if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra, NULL)) { return false; } } else { conf->addLib("-lXss"); } conf->addDefine("HAVE_XSS"); return true; #endif } }; #line 1 "aspell.qcm" /* -----BEGIN QCMOD----- name: aspell arg: with-aspell-inc=[path],Path to Aspell include files arg: with-aspell-lib=[path],Path to Aspell library files -----END QCMOD----- */ #define QC_ASPELL bool qc_aspell_have = false; QStringList qc_aspell_defs; QStringList qc_aspell_incs; QStringList qc_aspell_libs; //---------------------------------------------------------------------------- // qc_aspell //---------------------------------------------------------------------------- class qc_aspell : public ConfObj { public: qc_aspell(Conf *c) : ConfObj(c) {} QString name() const { return "aspell"; } QString shortname() const { return "aspell"; } // no output QString checkString() const { return QString(); } bool exec() { // on mac, always use built-in spell check #ifdef Q_OS_MAC return false; #else qc_aspell_have = false; qc_aspell_defs.clear(); qc_aspell_incs.clear(); qc_aspell_libs.clear(); QString s; #ifdef Q_OS_WIN s = conf->getenv("QC_WITH_ASPELL_INC"); if(!s.isEmpty()) { if(!conf->checkHeader(s, "aspell.h")) { conf->debug("Aspell includes not found!"); return false; } qc_aspell_incs += s; } else return false; QString a_lib = conf->getenv("QC_WITH_ASPELL_LIB"); if(a_lib.isEmpty()) return false; QStringList libnames; libnames += "aspell-15"; libnames += "aspell"; bool success; QString libname_success; foreach(const QString &libname, libnames) { conf->debug(QString("Trying %1").arg(libname)); if(conf->checkLibrary(a_lib, libname)) { success = true; libname_success = libname; break; } } if(!success) return false; qc_aspell_defs += "HAVE_ASPELL"; qc_aspell_libs += QString("-L") + a_lib; qc_aspell_libs += QString("-l") + libname_success; qc_aspell_have = true; #else s = conf->getenv("QC_WITH_ASPELL_INC"); if(!s.isEmpty()) { if(!conf->checkHeader(s, "aspell.h")) { conf->debug("Aspell includes not found!"); return false; } qc_aspell_incs += s; } else { QStringList sl; sl += "/usr/include"; sl += "/usr/local/include"; sl += "/sw/include"; if(!conf->findHeader("aspell.h", sl, &s)) { conf->debug("Aspell includes not found!"); return false; } qc_aspell_incs += s; } s = conf->getenv("QC_WITH_ASPELL_LIB"); if(!s.isEmpty()) { if(!conf->checkLibrary(s, "aspell")) { conf->debug("Aspell libraries not found!"); return false; } qc_aspell_libs += QString("-L") + s; } else { if(!conf->findLibrary("aspell", &s)) { conf->debug("Aspell libraries not found!"); return false; } if (!s.isEmpty()) qc_aspell_libs += QString("-L") + s; } qc_aspell_defs += "HAVE_ASPELL"; qc_aspell_libs += "-laspell"; qc_aspell_have = true; #endif return true; #endif } }; #line 1 "enchant.qcm" /* -----BEGIN QCMOD----- name: enchant -----END QCMOD----- */ #define QC_ENCHANT bool qc_enchant_have = false; QStringList qc_enchant_defs; QStringList qc_enchant_incs; QStringList qc_enchant_libs; //---------------------------------------------------------------------------- // qc_enchant //---------------------------------------------------------------------------- class qc_enchant : public ConfObj { public: qc_enchant(Conf *c) : ConfObj(c) {} QString name() const { return "enchant"; } QString shortname() const { return "enchant"; } // no output QString checkString() const { return QString(); } bool exec() { // on mac, always use built-in spell check #ifdef Q_OS_MAC return false; #endif qc_enchant_have = false; qc_enchant_defs.clear(); qc_enchant_incs.clear(); qc_enchant_libs.clear(); QStringList incs; QString version, libs, other; if(!conf->findPkgConfig("enchant", VersionMin, "1.3.0", &version, &incs, &libs, &other)) return false; qc_enchant_defs += "HAVE_ENCHANT"; qc_enchant_incs += incs; qc_enchant_libs += libs; qc_enchant_have = true; return true; } }; #line 1 "spell.qcm" /* -----BEGIN QCMOD----- name: spellcheck engine -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_spell //---------------------------------------------------------------------------- class qc_spell : public ConfObj { public: QString engine; qc_spell(Conf *c) : ConfObj(c) {} QString name() const { return "spellcheck engine"; } QString shortname() const { return "spell"; } bool exec() { // on mac, always use built-in spell check #ifdef Q_OS_MAC engine = "using Mac built-in"; return true; #endif bool have = false; QStringList defs, incs, libs; #ifdef QC_ENCHANT if(!have && qc_enchant_have) { defs = qc_enchant_defs; incs = qc_enchant_incs; libs = qc_enchant_libs; engine = "enchant"; have = true; } #endif #ifdef QC_ASPELL if(!have && qc_aspell_have) { defs = qc_aspell_defs; incs = qc_aspell_incs; libs = qc_aspell_libs; engine = "aspell"; have = true; } #endif if(!have) return true; for(int n = 0; n < defs.count(); ++n) conf->addDefine(defs[n]); for(int n = 0; n < incs.count(); ++n) conf->addIncludePath(incs[n]); for(int n = 0; n < libs.count(); ++n) conf->addLib(libs[n]); return true; } QString resultString() const { if(!engine.isEmpty()) return engine; else return "no"; } }; #line 1 "recursiveprl.qcm" /* -----BEGIN QCMOD----- name: recursively generate prl files -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_recursiveprl //---------------------------------------------------------------------------- class qc_recursiveprl : public ConfObj { public: qc_recursiveprl(Conf *c) : ConfObj(c) {} QString name() const { return "recursively generate prl files"; } QString shortname() const { return "recursiveprl"; } QString checkString() const { return QString(); } bool exec() { QStringList args; args += "-prl"; args += "-r"; args += qc_getenv("QC_PROFILE"); conf->doCommand(conf->qmake_path, args); return true; } }; #line 1 "conf.qcm" /* -----BEGIN QCMOD----- name: Psi Configuration -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_conf //---------------------------------------------------------------------------- class qc_conf : public ConfObj { public: qc_conf(Conf *c) : ConfObj(c) {} QString name() const { return "Psi Configuration"; } QString shortname() const { return "conf"; } QString checkString() const { return QString(); } bool exec() { #ifdef Q_OS_WIN return true; #else conf->addExtra(QString("PSI_LIBDIR=%1/psi").arg(conf->getenv("LIBDIR"))); conf->addExtra(QString("PSI_DATADIR=%1/psi").arg(conf->getenv("DATADIR"))); QFile file("src/config.h"); if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) { QTextStream stream( &file ); stream << "#define PSI_LIBDIR \"" << conf->getenv("LIBDIR") << "/psi\"" << endl; stream << "#define PSI_DATADIR \"" << conf->getenv("DATADIR") << "/psi\"" << endl; } conf->addDefine("HAVE_CONFIG"); return true; #endif } }; EOT cat >$1/modules_new.cpp <required = true; o->disabled = false; o = new qc_buildmodeapp(conf); o->required = true; o->disabled = false; o = new qc_bundled_qca(conf); o->required = false; o->disabled = false; o = new qc_qca(conf); o->required = true; o->disabled = false; o = new qc_openssl(conf); o->required = false; o->disabled = false; o = new qc_zlib(conf); o->required = true; o->disabled = false; o = new qc_universal(conf); o->required = false; o->disabled = true; o = new qc_certstore(conf); o->required = true; o->disabled = false; o = new qc_qdbus(conf); o->required = false; o->disabled = false; o = new qc_growl(conf); o->required = false; o->disabled = false; o = new qc_xss(conf); o->required = false; o->disabled = false; o = new qc_aspell(conf); o->required = false; o->disabled = false; o = new qc_enchant(conf); o->required = false; o->disabled = false; o = new qc_spell(conf); o->required = true; o->disabled = false; o = new qc_recursiveprl(conf); o->required = true; o->disabled = false; o = new qc_conf(conf); o->required = true; o->disabled = false; EOT cat >$1/conf4.h < class Conf; enum VersionMode { VersionMin, VersionExact, VersionMax, VersionAny }; // ConfObj // // Subclass ConfObj to create a new configuration module. class ConfObj { public: Conf *conf; bool required; bool disabled; bool success; ConfObj(Conf *c); virtual ~ConfObj(); // long or descriptive name of what is being checked/performed // example: "KDE >= 3.3" virtual QString name() const = 0; // short name // example: "kde" virtual QString shortname() const = 0; // string to display during check // default: "Checking for [name] ..." virtual QString checkString() const; // string to display after check // default: "yes" or "no", based on result of exec() virtual QString resultString() const; // this is where the checking code goes virtual bool exec() = 0; }; // Conf // // Interact with this class from your ConfObj to perform detection // operations and to output configuration parameters. class Conf { public: bool debug_enabled; QString qmake_path; QString qmakespec; QString maketool; QString DEFINES; QString INCLUDEPATH; QString LIBS; QString extra; QList list; QMap vars; Conf(); ~Conf(); QString getenv(const QString &var); QString qvar(const QString &s); bool exec(); void debug(const QString &s); QString expandIncludes(const QString &inc); QString expandLibs(const QString &lib); int doCommand(const QString &s, QByteArray *out = 0); int doCommand(const QString &prog, const QStringList &args, QByteArray *out = 0); bool doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, const QString &proextra, int *retcode = 0); bool checkHeader(const QString &path, const QString &h); bool findHeader(const QString &h, const QStringList &ext, QString *inc); bool checkLibrary(const QString &path, const QString &name); bool findLibrary(const QString &name, QString *lib); QString findProgram(const QString &prog); bool findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname, QString *incpath, QString *libs); bool findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags); bool findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, QStringList *incs, QString *libs, QString *otherflags); void addDefine(const QString &str); void addLib(const QString &str); void addIncludePath(const QString &str); void addExtra(const QString &str); private: bool first_debug; friend class ConfObj; void added(ConfObj *o); }; #endif EOT cat >$1/conf4.cpp < #include class MocTestObject : public QObject { Q_OBJECT public: MocTestObject() {} }; QString qc_getenv(const QString &var) { char *p = ::getenv(var.toLatin1().data()); if(!p) return QString(); return QString(p); } QStringList qc_pathlist() { QStringList list; QString path = qc_getenv("PATH"); if(!path.isEmpty()) { #ifdef Q_OS_WIN list = path.split(';', QString::SkipEmptyParts); #else list = path.split(':', QString::SkipEmptyParts); #endif } #ifdef Q_OS_WIN list.prepend("."); #endif return list; } QString qc_findprogram(const QString &prog) { QString out; QStringList list = qc_pathlist(); for(int n = 0; n < list.count(); ++n) { QFileInfo fi(list[n] + '/' + prog); if(fi.exists() && fi.isExecutable()) { out = fi.filePath(); break; } #ifdef Q_OS_WIN // on windows, be sure to look for .exe if(prog.right(4).toLower() != ".exe") { fi = QFileInfo(list[n] + '/' + prog + ".exe"); if(fi.exists() && fi.isExecutable()) { out = fi.filePath(); break; } } #endif } return out; } QString qc_findself(const QString &argv0) { #ifdef Q_OS_WIN if(argv0.contains('\\\\')) #else if(argv0.contains('/')) #endif return argv0; else return qc_findprogram(argv0); } int qc_runcommand(const QString &command, QByteArray *out, bool showOutput) { QString fullcmd = command; if(!showOutput) { #ifdef Q_OS_WIN fullcmd += " 2>NUL"; #else fullcmd += " 2>/dev/null"; #endif } #ifdef Q_OS_WIN FILE *f = _popen(fullcmd.toLatin1().data(), "r"); #else FILE *f = popen(fullcmd.toLatin1().data(), "r"); #endif if(!f) return -1; if(out) out->clear(); while(1) { char c = (char)fgetc(f); if(feof(f)) break; if(out) out->append(c); if(showOutput) fputc(c, stdout); } #ifdef Q_OS_WIN int ret = _pclose(f); #else int ret = pclose(f); #endif if(ret == -1) return -1; return ret; } int qc_runprogram(const QString &prog, const QStringList &args, QByteArray *out, bool showOutput) { QString fullcmd = prog; QString argstr = args.join(" "); if(!argstr.isEmpty()) fullcmd += QString(" ") + argstr; return qc_runcommand(fullcmd, out, showOutput); // TODO: use QProcess once it is fixed /* QProcess process; if(showOutput) process.setReadChannelMode(ForwardedChannels); process.start(prog, args); process.waitForFinished(-1); return process.exitCode(); */ } bool qc_removedir(const QString &dirPath) { QDir dir(dirPath); if(!dir.exists()) return false; QStringList list = dir.entryList(); foreach(QString s, list) { if(s == "." || s == "..") continue; QFileInfo fi(dir.filePath(s)); if(fi.isDir()) { if(!qc_removedir(fi.filePath())) return false; } else { if(!dir.remove(s)) return false; } } QString dirName = dir.dirName(); if(!dir.cdUp()) return false; if(!dir.rmdir(dirName)) return false; return true; } void qc_splitcflags(const QString &cflags, QStringList *incs, QStringList *otherflags) { incs->clear(); otherflags->clear(); QStringList cflagsList = cflags.split(" "); for(int n = 0; n < cflagsList.count(); ++n) { QString str = cflagsList[n]; if(str.startsWith("-I")) { // we want everything except the leading "-I" incs->append(str.remove(0, 2)); } else { // we want whatever is left otherflags->append(str); } } } QString qc_escapeArg(const QString &str) { QString out; for(int n = 0; n < (int)str.length(); ++n) { if(str[n] == '-') out += '_'; else out += str[n]; } return out; } //---------------------------------------------------------------------------- // ConfObj //---------------------------------------------------------------------------- ConfObj::ConfObj(Conf *c) { conf = c; conf->added(this); required = false; disabled = false; success = false; } ConfObj::~ConfObj() { } QString ConfObj::checkString() const { return QString("Checking for %1 ...").arg(name()); } QString ConfObj::resultString() const { if(success) return "yes"; else return "no"; } //---------------------------------------------------------------------------- // qc_internal_pkgconfig //---------------------------------------------------------------------------- class qc_internal_pkgconfig : public ConfObj { public: QString pkgname, desc; VersionMode mode; QString req_ver; qc_internal_pkgconfig(Conf *c, const QString &_name, const QString &_desc, VersionMode _mode, const QString &_req_ver) : ConfObj(c) { pkgname = _name; desc = _desc; mode = _mode; req_ver = _req_ver; } QString name() const { return desc; } QString shortname() const { return pkgname; } bool exec() { QStringList incs; QString version, libs, other; if(!conf->findPkgConfig(pkgname, mode, req_ver, &version, &incs, &libs, &other)) return false; for(int n = 0; n < incs.count(); ++n) conf->addIncludePath(incs[n]); if(!libs.isEmpty()) conf->addLib(libs); //if(!other.isEmpty()) // conf->addExtra(QString("QMAKE_CFLAGS += %1\n").arg(other)); return true; } }; //---------------------------------------------------------------------------- // Conf //---------------------------------------------------------------------------- Conf::Conf() { // TODO: no more vars? //vars.insert("QMAKE_INCDIR_X11", new QString(X11_INC)); //vars.insert("QMAKE_LIBDIR_X11", new QString(X11_LIBDIR)); //vars.insert("QMAKE_LIBS_X11", new QString(X11_LIB)); //vars.insert("QMAKE_CC", CC); debug_enabled = false; } Conf::~Conf() { qDeleteAll(list); } void Conf::added(ConfObj *o) { list.append(o); } QString Conf::getenv(const QString &var) { return qc_getenv(var); } void Conf::debug(const QString &s) { if(debug_enabled) { if(first_debug) printf("\n"); first_debug = false; printf(" * %s\n", qPrintable(s)); } } bool Conf::exec() { for(int n = 0; n < list.count(); ++n) { ConfObj *o = list[n]; // if this was a disabled-by-default option, check if it was enabled if(o->disabled) { QString v = QString("QC_ENABLE_") + qc_escapeArg(o->shortname()); if(getenv(v) != "Y") continue; } // and the opposite? else { QString v = QString("QC_DISABLE_") + qc_escapeArg(o->shortname()); if(getenv(v) == "Y") continue; } bool output = true; QString check = o->checkString(); if(check.isEmpty()) output = false; if(output) { printf("%s", check.toLatin1().data()); fflush(stdout); } first_debug = true; bool ok = o->exec(); o->success = ok; if(output) { QString result = o->resultString(); if(!first_debug) printf(" -> %s\n", result.toLatin1().data()); else printf(" %s\n", result.toLatin1().data()); } if(!ok && o->required) { printf("\nError: need %s!\n", o->name().toLatin1().data()); return false; } } return true; } QString Conf::qvar(const QString &s) { return vars.value(s); } QString Conf::expandIncludes(const QString &inc) { return QString("-I") + inc; } QString Conf::expandLibs(const QString &lib) { return QString("-L") + lib; } int Conf::doCommand(const QString &s, QByteArray *out) { debug(QString("[%1]").arg(s)); int r = qc_runcommand(s, out, debug_enabled); debug(QString("returned: %1").arg(r)); return r; } int Conf::doCommand(const QString &prog, const QStringList &args, QByteArray *out) { QString fullcmd = prog; QString argstr = args.join(" "); if(!argstr.isEmpty()) fullcmd += QString(" ") + argstr; debug(QString("[%1]").arg(fullcmd)); int r = qc_runprogram(prog, args, out, debug_enabled); debug(QString("returned: %1").arg(r)); return r; } bool Conf::doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, const QString &proextra, int *retcode) { #ifdef Q_OS_WIN QDir tmp("qconftemp"); #else QDir tmp(".qconftemp"); #endif if(!tmp.mkdir("atest")) { debug("unable to create atest dir"); return false; } QDir dir(tmp.filePath("atest")); if(!dir.exists()) { debug("atest dir does not exist"); return false; } QString fname = dir.filePath("atest.cpp"); QString out = "atest"; QFile f(fname); if(!f.open(QFile::WriteOnly | QFile::Truncate)) { debug("unable to open atest.cpp for writing"); return false; } if(f.write(filedata.toLatin1()) == -1) { debug("error writing to atest.cpp"); return false; } f.close(); debug(QString("Wrote atest.cpp:\n%1").arg(filedata)); QString pro = QString( "CONFIG += console\n" "CONFIG -= qt app_bundle\n" "DESTDIR = \$\$PWD\n" "SOURCES += atest.cpp\n"); QString inc = incs.join(" "); if(!inc.isEmpty()) pro += "INCLUDEPATH += " + inc + '\n'; if(!libs.isEmpty()) pro += "LIBS += " + libs + '\n'; pro += proextra; fname = dir.filePath("atest.pro"); f.setFileName(fname); if(!f.open(QFile::WriteOnly | QFile::Truncate)) { debug("unable to open atest.pro for writing"); return false; } if(f.write(pro.toLatin1()) == -1) { debug("error writing to atest.pro"); return false; } f.close(); debug(QString("Wrote atest.pro:\n%1").arg(pro)); QString oldpath = QDir::currentPath(); QDir::setCurrent(dir.path()); bool ok = false; int r = doCommand(qmake_path, QStringList() << "atest.pro"); if(r == 0) { r = doCommand(maketool, QStringList()); if(r == 0) { ok = true; if(retcode) { QString runatest = out; #ifdef Q_OS_UNIX runatest.prepend("./"); #endif *retcode = doCommand(runatest, QStringList()); } } r = doCommand(maketool, QStringList() << "distclean"); if(r != 0) debug("error during atest distclean"); } QDir::setCurrent(oldpath); // cleanup //dir.remove("atest.pro"); //dir.remove("atest.cpp"); //tmp.rmdir("atest"); // remove whole dir since distclean doesn't always work qc_removedir(tmp.filePath("atest")); if(!ok) return false; return true; } bool Conf::checkHeader(const QString &path, const QString &h) { QFileInfo fi(path + '/' + h); if(fi.exists()) return true; return false; } bool Conf::findHeader(const QString &h, const QStringList &ext, QString *inc) { if(checkHeader("/usr/include", h)) { *inc = ""; return true; } QStringList dirs; dirs += "/usr/local/include"; dirs += ext; for(QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { if(checkHeader(*it, h)) { *inc = *it; return true; } } return false; } bool Conf::checkLibrary(const QString &path, const QString &name) { QString str = //"#include \n" "int main()\n" "{\n" //" printf(\"library checker running\\\\n\");\n" " return 0;\n" "}\n"; QString libs; if(!path.isEmpty()) libs += QString("-L") + path + ' '; libs += QString("-l") + name; if(!doCompileAndLink(str, QStringList(), libs, QString())) return false; return true; } bool Conf::findLibrary(const QString &name, QString *lib) { if(checkLibrary("", name)) { *lib = ""; return true; } if(checkLibrary("/usr/local/lib", name)) { *lib = "/usr/local/lib"; return true; } return false; } QString Conf::findProgram(const QString &prog) { return qc_findprogram(prog); } bool Conf::findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname, QString *incpath, QString *libs) { QString inc, lib; QString s; s = getenv(incvar); if(!s.isEmpty()) { if(!checkHeader(s, incname)) return false; inc = s; } else { if(!findHeader(incname, QStringList(), &s)) return false; inc = s; } s = getenv(libvar); if(!s.isEmpty()) { if(!checkLibrary(s, libname)) return false; lib = s; } else { if(!findLibrary(libname, &s)) return false; lib = s; } QString lib_out; if(!lib.isEmpty()) lib_out += QString("-L") + s; lib_out += QString("-l") + libname; *incpath = inc; *libs = lib_out; return true; } bool Conf::findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags) { QStringList args; QByteArray out; int ret; args += "--version"; ret = doCommand(path, args, &out); if(ret != 0) return false; QString version_out = QString::fromLatin1(out).trimmed(); args.clear(); args += "--libs"; ret = doCommand(path, args, &out); if(ret != 0) return false; QString libs_out = QString::fromLatin1(out).trimmed(); args.clear(); args += "--cflags"; ret = doCommand(path, args, &out); if(ret != 0) return false; QString cflags = QString::fromLatin1(out).trimmed(); QStringList incs_out, otherflags_out; qc_splitcflags(cflags, &incs_out, &otherflags_out); *version = version_out; *incs = incs_out; *libs = libs_out; *otherflags = otherflags_out.join(" "); return true; } bool Conf::findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, QStringList *incs, QString *libs, QString *otherflags) { QStringList args; QByteArray out; int ret; args += name; args += "--exists"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; if(mode != VersionAny) { args.clear(); args += name; if(mode == VersionMin) args += QString("--atleast-version=%1").arg(req_version); else if(mode == VersionMax) args += QString("--max-version=%1").arg(req_version); else args += QString("--exact-version=%1").arg(req_version); ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; } args.clear(); args += name; args += "--modversion"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; QString version_out = QString::fromLatin1(out).trimmed(); args.clear(); args += name; args += "--libs"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; QString libs_out = QString::fromLatin1(out).trimmed(); args.clear(); args += name; args += "--cflags"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; QString cflags = QString::fromLatin1(out).trimmed(); QStringList incs_out, otherflags_out; qc_splitcflags(cflags, &incs_out, &otherflags_out); *version = version_out; *incs = incs_out; *libs = libs_out; *otherflags = otherflags_out.join(" "); return true; } void Conf::addDefine(const QString &str) { if(DEFINES.isEmpty()) DEFINES = str; else DEFINES += QString(" ") + str; debug(QString("DEFINES += %1").arg(str)); } void Conf::addLib(const QString &str) { if(LIBS.isEmpty()) LIBS = str; else LIBS += QString(" ") + str; debug(QString("LIBS += %1").arg(str)); } void Conf::addIncludePath(const QString &str) { if(INCLUDEPATH.isEmpty()) INCLUDEPATH = str; else INCLUDEPATH += QString(" ") + str; debug(QString("INCLUDEPATH += %1").arg(str)); } void Conf::addExtra(const QString &str) { extra += str + '\n'; debug(QString("extra += %1").arg(str)); } //---------------------------------------------------------------------------- // main //---------------------------------------------------------------------------- #include "conf4.moc" #ifdef HAVE_MODULES # include"modules.cpp" #endif int main() { Conf *conf = new Conf; ConfObj *o; o = 0; #ifdef HAVE_MODULES # include"modules_new.cpp" #endif conf->debug_enabled = (qc_getenv("QC_VERBOSE") == "Y") ? true: false; if(conf->debug_enabled) printf(" -> ok\n"); else printf("ok\n"); QString confCommand = qc_getenv("QC_COMMAND"); QString proName = qc_getenv("QC_PROFILE"); conf->qmake_path = qc_getenv("QC_QMAKE"); conf->qmakespec = qc_getenv("QC_QMAKESPEC"); conf->maketool = qc_getenv("QC_MAKETOOL"); if(conf->debug_enabled) printf("conf command: [%s]\n", qPrintable(confCommand)); QString confPath = qc_findself(confCommand); if(confPath.isEmpty()) { printf("Error: cannot find myself; rerun with an absolute path\n"); return 1; } QString srcdir = QFileInfo(confPath).absolutePath(); QString builddir = QDir::current().absolutePath(); QString proPath = QDir(srcdir).filePath(proName); if(conf->debug_enabled) { printf("conf path: [%s]\n", qPrintable(confPath)); printf("srcdir: [%s]\n", qPrintable(srcdir)); printf("builddir: [%s]\n", qPrintable(builddir)); printf("profile: [%s]\n", qPrintable(proPath)); printf("qmake path: [%s]\n", qPrintable(conf->qmake_path)); printf("qmakespec: [%s]\n", qPrintable(conf->qmakespec)); printf("make tool: [%s]\n", qPrintable(conf->maketool)); printf("\n"); } bool success = false; if(conf->exec()) { QFile f("conf.pri"); if(!f.open(QFile::WriteOnly | QFile::Truncate)) { printf("Error writing %s\n", qPrintable(f.fileName())); return 1; } QString str; str += "# qconf\n\n"; QString var; var = qc_getenv("PREFIX"); if(!var.isEmpty()) str += QString("PREFIX = %1\n").arg(var); var = qc_getenv("BINDIR"); if(!var.isEmpty()) str += QString("BINDIR = %1\n").arg(var); var = qc_getenv("INCDIR"); if(!var.isEmpty()) str += QString("INCDIR = %1\n").arg(var); var = qc_getenv("LIBDIR"); if(!var.isEmpty()) str += QString("LIBDIR = %1\n").arg(var); var = qc_getenv("DATADIR"); if(!var.isEmpty()) str += QString("DATADIR = %1\n").arg(var); str += '\n'; if(qc_getenv("QC_STATIC") == "Y") str += "CONFIG += staticlib\n"; // TODO: don't need this? //str += "QT_PATH_PLUGINS = " + QString(qInstallPathPlugins()) + '\n'; if(!conf->DEFINES.isEmpty()) str += "DEFINES += " + conf->DEFINES + '\n'; if(!conf->INCLUDEPATH.isEmpty()) str += "INCLUDEPATH += " + conf->INCLUDEPATH + '\n'; if(!conf->LIBS.isEmpty()) str += "LIBS += " + conf->LIBS + '\n'; if(!conf->extra.isEmpty()) str += conf->extra; str += '\n'; QByteArray cs = str.toLatin1(); f.write(cs); f.close(); success = true; } QString qmake_path = conf->qmake_path; QString qmakespec = conf->qmakespec; delete conf; if(!success) return 1; // run qmake on the project file QStringList args; if(!qmakespec.isEmpty()) { args += "-spec"; args += qmakespec; } args += proPath; int ret = qc_runprogram(qmake_path, args, 0, true); if(ret != 0) return 1; return 0; } EOT cat >$1/conf4.pro </dev/null else $qm conf4.pro >/dev/null fi $MAKE clean >/dev/null 2>&1 $MAKE >../conf.log 2>&1 ) if [ "$?" != "0" ]; then rm -rf .qconftemp if [ "$QC_VERBOSE" = "Y" ]; then echo " -> fail" else echo "fail" fi printf "\n" printf "Reason: There was an error compiling 'conf'. See conf.log for details.\n" printf "\n" show_qt_info if [ "$QC_VERBOSE" = "Y" ]; then echo "conf.log:" cat conf.log fi exit 1; fi QC_COMMAND=$0 export QC_COMMAND QC_PROFILE=psi.pro export QC_PROFILE QC_QMAKE=$qm export QC_QMAKE QC_QMAKESPEC=$qm_spec export QC_QMAKESPEC QC_MAKETOOL=$MAKE export QC_MAKETOOL .qconftemp/conf ret="$?" if [ "$ret" = "1" ]; then rm -rf .qconftemp echo exit 1; else if [ "$ret" != "0" ]; then rm -rf .qconftemp if [ "$QC_VERBOSE" = "Y" ]; then echo " -> fail" else echo "fail" fi echo echo "Reason: Unexpected error launching 'conf'" echo exit 1; fi fi rm -rf .qconftemp echo echo "Good, your configure finished. Now run $MAKE." echo psi-0.14/.gitmodules0000644000175000017500000000023011305557613012511 0ustar janjan[submodule "iris"] path = iris url = git://git.psi-im.org/iris.git [submodule "src/libpsi"] path = src/libpsi url = git://git.psi-im.org/libpsi.git psi-0.14/qa/0000755000175000017500000000000011305557613010742 5ustar janjanpsi-0.14/qa/valgrind/0000755000175000017500000000000011305557613012550 5ustar janjanpsi-0.14/qa/valgrind/valgrind.pri0000644000175000017500000000134011305557613015070 0ustar janjanunix { # valgrind target (only shows valgrind output) VALGRIND_OPTIONS = -q --num-callers=40 --leak-check=full --show-reachable=yes --suppressions=$$PWD/valgrind.supp QMAKE_EXTRA_TARGETS += valgrind valgrind.depends = $$EXEC_TARGET valgrind.commands = valgrind $$VALGRIND_OPTIONS ./$$EXEC_TARGET | grep -E '==\d+==' # valgrind_supp target (generate suppressions) QMAKE_EXTRA_TARGETS += valgrind_supp valgrind_supp.depends = $$EXEC_TARGET valgrind_supp.commands = valgrind $$VALGRIND_OPTIONS --gen-suppressions=all ./$$EXEC_TARGET # callgrind profiling QMAKE_EXTRA_TARGETS += callgrind callgrind.depends = $$EXEC_TARGET callgrind.commands = valgrind --tool=callgrind --dump-instr=yes --collect-jumps=yes ./$$EXEC_TARGET } psi-0.14/qa/valgrind/valgrind.supp0000644000175000017500000025054711305557613015304 0ustar janjan{ Memcheck:Leak fun:_Znwj fun:_ZN6QBrush4initERK6QColorN2Qt10BrushStyleE fun:_ZN6QBrushC1EN2Qt11GlobalColorENS0_10BrushStyleE fun:_ZN13QPainterState4initEP8QPainter fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZN14Q3ListViewItem13paintBranchesEP8QPainterRK11QColorGroupiii fun:_ZN10Q3ListView18drawContentsOffsetEP8QPainteriiiiii fun:_ZN12Q3ScrollView18viewportPaintEventEP11QPaintEvent fun:_ZN12Q3ScrollView11eventFilterEP7QObjectP6QEvent fun:_ZN10Q3ListView11eventFilterEP7QObjectP6QEvent } { Memcheck:Leak fun:malloc fun:strdup obj:* obj:* fun:gethostbyname_r fun:gethostbyname fun:_ZN10NDnsWorker3runEv fun:_ZN14QThreadPrivate5startEPv fun:pthread_start_thread fun:clone } { Memcheck:Leak fun:malloc obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Alloc fun:FT_Realloc obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Load_Glyph fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZN9QTextLine13layout_helperEi fun:_ZN9QTextLine12setLineWidthEd fun:_ZN26QTextDocumentLayoutPrivate11layoutBlockERK10QTextBlockP13QLayoutStructiiS2_ fun:_ZN26QTextDocumentLayoutPrivate10layoutFlowEN10QTextFrame8iteratorEP13QLayoutStructii fun:_ZN26QTextDocumentLayoutPrivate11layoutFrameEP10QTextFrameiidd fun:_ZN26QTextDocumentLayoutPrivate11layoutFrameEP10QTextFrameii } { Memcheck:Leak fun:_Znwj fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZNK11QTextEngine5widthEii fun:_ZNK12QFontMetrics5widthERK7QStringi fun:_ZNK14Q3ListViewItem5widthERK12QFontMetricsPK10Q3ListViewi fun:_ZN10Q3ListView12widthChangedEPK14Q3ListViewItemi fun:_ZNK14Q3ListViewItem12widthChangedEi } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XimSetIMResourceList fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:_XEventsQueued fun:XEventsQueued fun:_ZN19QEventDispatcherX1113processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE fun:_ZN10QEventLoop13processEventsE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN5QMenu4execERK6QPointP7QAction fun:_ZN11Q3PopupMenu4execERK6QPointi } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:XDrawPoint fun:_ZN15QX11PaintEngine10drawPointsEPK7QPointFi fun:_ZN12QPaintEngine10drawPointsEPK6QPointi fun:_ZN15QX11PaintEngine10drawPointsEPK6QPointi fun:_ZN8QPainter10drawPointsEPK6QPointi } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:XRenderChangePicture fun:_Z18x11ClearClipRegionP9_XDisplayP4_XGCS2_m fun:_ZN15QX11PaintEngine9updatePenERK4QPen fun:_ZN15QX11PaintEngine11updateStateERK17QPaintEngineState fun:_ZN15QPainterPrivate11updateStateEP13QPainterState fun:_ZN8QPainter10drawPointsEPK6QPointi fun:_ZN8QPainter9drawPointEii } { Memcheck:Leak fun:_Znwj fun:_ZN4QPenC1ERK6QColor fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:_Znwj fun:_ZN6QBrush4initERK6QColorN2Qt10BrushStyleE fun:_ZN6QBrushC1ERK6QColorN2Qt10BrushStyleE fun:_ZN4QPenC1ERK6QColor fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:malloc fun:_Z7qMallocj fun:_ZN11QDataBufferI14qt_float_pointEC1Ei fun:_ZN15QPolygonClipperI14qt_float_pointS0_fEC1Ev fun:_ZN22QX11PaintEnginePrivateC1Ev fun:_ZN15QX11PaintEngineC1Ev fun:_ZNK7QPixmap11paintEngineEv fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:malloc fun:_Z7qMallocj fun:_ZN11QDataBufferI14qt_float_pointEC1Ei fun:_ZN15QPolygonClipperI14qt_float_pointS0_fEC1Ev fun:_ZN22QX11PaintEnginePrivateC1Ev fun:_ZN15QX11PaintEngineC1Ev fun:_ZNK7QPixmap11paintEngineEv fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:_Znwj fun:_ZNK7QPixmap11paintEngineEv fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:_Znwj fun:_ZN7QPixmap4initEiiNS_4TypeE fun:_ZN7QPixmapC1Ev fun:_ZN22QX11PaintEnginePrivateC1Ev fun:_ZN15QX11PaintEngineC1Ev fun:_ZNK7QPixmap11paintEngineEv fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:_Znwj fun:_ZN15QX11PaintEngineC1Ev fun:_ZNK7QPixmap11paintEngineEv fun:_ZN8QPainter5beginEP12QPaintDevice fun:_ZNK13QWindowsStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget fun:_ZNK15QPlastiqueStyle18drawComplexControlEN6QStyle14ComplexControlEPK19QStyleOptionComplexP8QPainterPK7QWidget } { Memcheck:Leak fun:_Znaj fun:_ZN9QHashData6rehashEi fun:_ZN9QHashData9mightGrowEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZNK11QTextEngine5widthEii fun:_ZNK12QFontMetrics5widthERK7QStringi } { Memcheck:Leak fun:malloc fun:_XrmInternalStringToQuark fun:XrmStringToQuark fun:_XlcGetLocaleDataBase fun:_XlcGetResource fun:_XomGenericOpenOM fun:XOpenOM fun:XCreateFontSet fun:_Z10getFontSetRK5QFont fun:_ZN16QXIMInputContext12createICDataEP7QWidget fun:_ZN16QXIMInputContext14setFocusWidgetEP7QWidget fun:_ZN14QWidgetPrivate17focusInputContextEv fun:_ZN7QWidget8setFocusEN2Qt11FocusReasonE fun:_ZN12QApplication15setActiveWindowEP7QWidget fun:_ZN12QApplication15x11ProcessEventEP7_XEvent fun:_ZN19QEventDispatcherX1113processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE fun:_ZN10QEventLoop13processEventsE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN16QCoreApplication4execEv } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:XCheckIfEvent fun:_ZN9QETWidget19translatePaintEventEPK7_XEvent fun:_ZN12QApplication15x11ProcessEventEP7_XEvent fun:_ZN19QEventDispatcherX1113processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE fun:_ZN10QEventLoop13processEventsE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN16QCoreApplication4execEv fun:_ZN12QApplication4execEv } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:_XSetClipRectangles fun:XSetClipRectangles fun:_Z16x11SetClipRegionP9_XDisplayP4_XGCS2_mRK7QRegion fun:_ZN15QX11PaintEngine16updateClipRegionERK7QRegionN2Qt13ClipOperationE fun:_ZN15QX11PaintEngine11updateStateERK17QPaintEngineState fun:_ZN15QPainterPrivate11updateStateEP13QPainterState fun:_ZN8QPainter11setClipPathERK12QPainterPathN2Qt13ClipOperationE fun:_ZN8QPainter11setClipRectERK6QRectFN2Qt13ClipOperationE fun:_ZN8QPainter11setClipRectERK5QRectN2Qt13ClipOperationE fun:_ZN6QLabel10paintEventEP11QPaintEvent fun:_ZN9QTipLabel10paintEventEP11QPaintEvent } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:XRenderCompositeText32 fun:_ZN15QX11PaintEngine12drawFreetypeERK7QPointFRK12QTextItemInt fun:_ZN15QX11PaintEngine12drawTextItemERK7QPointFRK9QTextItem fun:_ZN15QX11PaintEngine9drawMultiERK7QPointFRK12QTextItemInt fun:_ZN15QX11PaintEngine12drawTextItemERK7QPointFRK9QTextItem fun:_ZN8QPainter12drawTextItemERK7QPointFRK9QTextItem fun:_ZNK9QTextLine4drawEP8QPainterRK7QPointFPKN11QTextLayout11FormatRangeE fun:_ZNK11QTextLayout4drawEP8QPainterRK7QPointFRK7QVectorINS_11FormatRangeEERK6QRectF } { Memcheck:Leak fun:malloc fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget16updateMicroFocusEv fun:_ZN16QLineEditPrivate12finishChangeEibb fun:_ZN16QLineEditPrivate7setTextERK7QStringib fun:_ZN9QLineEdit7setTextERK7QString fun:_ZN9QComboBox15setCurrentIndexEi fun:_ZN16QComboBoxPrivate12rowsInsertedERK11QModelIndexii fun:_ZN9QComboBox11insertItemsEiRK11QStringList fun:_ZN9QComboBox16insertStringListERK11QStringListi } { Memcheck:Leak fun:malloc fun:_XlcDefaultMapModifiers fun:XSetLocaleModifiers fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget16updateMicroFocusEv fun:_ZN16QLineEditPrivate12finishChangeEibb fun:_ZN16QLineEditPrivate7setTextERK7QStringib fun:_ZN9QLineEdit7setTextERK7QString fun:_ZN9QComboBox15setCurrentIndexEi fun:_ZN16QComboBoxPrivate12rowsInsertedERK11QModelIndexii fun:_ZN9QComboBox11insertItemsEiRK11QStringList fun:_ZN9QComboBox16insertStringListERK11QStringListi } { Memcheck:Leak fun:malloc fun:_XimOpenIM fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget16updateMicroFocusEv fun:_ZN16QLineEditPrivate12finishChangeEibb fun:_ZN16QLineEditPrivate7setTextERK7QStringib fun:_ZN9QLineEdit7setTextERK7QString fun:_ZN9QComboBox15setCurrentIndexEi fun:_ZN16QComboBoxPrivate12rowsInsertedERK11QModelIndexii } { Memcheck:Leak fun:malloc fun:_Z7qMallocj fun:_ZN7QString7reallocEi fun:_ZN7QString6resizeEi fun:_ZN7QString8fromUtf8EPKci fun:_Z22qt_FcPatternToQFontDefP10_FcPatternRK8QFontDef fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:_ZN9QHashData12allocateNodeEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE10createNodeEjRKiRKS2_PP9QHashNodeIiS2_E fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZNK11QTextEngine5widthEii fun:_ZNK12QFontMetrics5widthERK7QStringi fun:_ZNK14Q3ListViewItem5widthERK12QFontMetricsPK10Q3ListViewi fun:_ZN10Q3ListView12widthChangedEPK14Q3ListViewItemi } { Memcheck:Leak fun:malloc obj:/usr/lib/libXcursor.so.1.0.2 obj:/usr/lib/libXcursor.so.1.0.2 fun:XcursorXcFileLoadImages fun:XcursorFileLoadImages fun:XcursorLibraryLoadImages fun:XcursorLibraryLoadCursor fun:_ZN11QCursorData6updateEv fun:_ZNK7QCursor6handleEv fun:_Z21qt_x11_enforce_cursorP7QWidget fun:_ZN14QWidgetPrivate10create_sysEmbb fun:_ZN7QWidget6createEmbb fun:_ZN14QWidgetPrivate4initEP7QWidget6QFlagsIN2Qt10WindowTypeEE fun:_ZN7QWidgetC2ER14QWidgetPrivatePS_6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XimSetICResourceList fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Leak fun:_Znwj fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZNK11QTextEngine5widthEii fun:_ZNK12QFontMetrics5widthERK7QStringi fun:_ZNK14Q3ListViewItem5widthERK12QFontMetricsPK10Q3ListViewi fun:_ZN10Q3ListView12widthChangedEPK14Q3ListViewItemi fun:_ZNK14Q3ListViewItem12widthChangedEi fun:_ZN14Q3ListViewItem7setTextEiRK7QString } { Memcheck:Leak fun:malloc fun:_ZN9QHashData12allocateNodeEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE10createNodeEjRKiRKS2_PP9QHashNodeIiS2_E fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT15minRightBearingEv fun:_ZNK13QFontEngineFT14minLeftBearingEv fun:_ZNK16QFontEngineMulti14minLeftBearingEv fun:_ZNK12QFontMetrics14minLeftBearingEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:_Znwj fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZNK11QTextEngine5widthEii fun:_ZNK12QFontMetrics5widthERK7QStringi fun:_ZNK12QMenuPrivate15calcActionRectsER4QMapIP7QAction5QRectER5QListIS2_E } { Memcheck:Leak fun:malloc fun:_ZN9QHashData12allocateNodeEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE10createNodeEjRKiRKS2_PP9QHashNodeIiS2_E fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZNK11QTextEngine5widthEii fun:_ZNK12QFontMetrics5widthERK7QStringi fun:_ZNK12QMenuPrivate15calcActionRectsER4QMapIP7QAction5QRectER5QListIS2_E } { Memcheck:Leak fun:_Znwj fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:_Z7qMallocj fun:_ZN11QVectorData6mallocEiiiPS_ fun:_ZN7QVectorIP11QFontEngineE7reallocEii fun:_ZN7QVectorIP11QFontEngineE6resizeEi fun:_ZN7QVectorIP11QFontEngineE4fillERKS1_i fun:_ZN16QFontEngineMultiC2Ei fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:_Znaj fun:_ZN9QHashData6rehashEi fun:_ZN9QHashData9mightGrowEv fun:_ZN5QHashImP7QWidgetE6insertERKmRKS1_ fun:_Z9qPRCreatePK7QWidgetm fun:_ZN14QWidgetPrivate13setParent_sysEP7QWidget6QFlagsIN2Qt10WindowTypeEE fun:_ZN7QWidget9setParentEPS_6QFlagsIN2Qt10WindowTypeEE fun:_ZN7QWidget9setParentEPS_ fun:_ZN10Q3DockArea14moveDockWindowEP12Q3DockWindowi fun:_ZN12Q3MainWindow14moveDockWindowEP12Q3DockWindowN2Qt4DockE fun:_ZN12Q3MainWindow13addDockWindowEP12Q3DockWindowN2Qt4DockEb fun:_ZN12Q3DockWindow4initEv fun:_ZN12Q3DockWindowC2ENS_5PlaceEP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEEb fun:_ZN9Q3ToolBarC2ERK7QStringP12Q3MainWindowP7QWidgetbPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:_Z7qMallocj fun:_ZN10QByteArray7reallocEi fun:_ZN10QByteArrayaSEPKc fun:_Z7face_idP10_FcPattern fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:XCopyArea fun:_ZN19QWidgetBackingStore12copyToScreenERK7QRegionP7QWidgetRK6QPointb fun:_ZN19QWidgetBackingStore12copyToScreenERK7QRegionP7QWidgetRK6QPointb fun:_ZN19QWidgetBackingStore11cleanRegionERK7QRegionP7QWidgetb fun:_Z19qt_syncBackingStoreP7QWidget fun:_ZN7QWidget5eventEP6QEvent fun:_ZN15QAbstractButton5eventEP6QEvent fun:_ZN11QToolButton5eventEP6QEvent fun:_ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent fun:_ZN12QApplication6notifyEP7QObjectP6QEvent fun:_ZN14PsiApplication6notifyEP7QObjectP6QEvent fun:_ZN16QCoreApplication9sendEventEP7QObjectP6QEvent fun:_ZN16QCoreApplication16sendPostedEventsEP7QObjecti fun:_ZN16QCoreApplication16sendPostedEventsEv fun:_ZN19QEventDispatcherX1113processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE fun:_ZN10QEventLoop13processEventsE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN16QCoreApplication4execEv fun:_ZN12QApplication4execEv } { Memcheck:Leak fun:realloc obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Realloc fun:FT_CMap_New obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Open_Face fun:FT_New_Face fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:_Znwj fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT15minRightBearingEv fun:_ZNK13QFontEngineFT14minLeftBearingEv fun:_ZNK16QFontEngineMulti14minLeftBearingEv fun:_ZNK12QFontMetrics14minLeftBearingEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XimSetIMResourceList fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget7destroyEbb } { Memcheck:Leak fun:_Znwj fun:_Z13getEngineDataPK12QFontPrivateRKN10QFontCache3KeyE fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:_dl_map_object_deps obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen obj:/usr/lib/libX11.so.6.2.0 fun:_XNoticeCreateBitmap fun:XCreatePixmap fun:XCreateBitmapFromData fun:_ZN7QBitmap9fromImageERK6QImage6QFlagsIN2Qt19ImageConversionFlagEE fun:_ZNK7QPixmap4maskEv fun:_ZN14QWidgetPrivate17setWindowIcon_sysEb fun:_ZN7QWidget13setWindowIconERK5QIcon } { Memcheck:Leak fun:malloc obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Alloc fun:FT_Open_Face fun:FT_New_Face fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:_Znwj fun:_ZNK7QString13latin1_helperEv fun:_ZNK7QString6latin1Ev } { Memcheck:Leak fun:calloc fun:pthread_setspecific fun:_ZN14QThreadPrivate16setCurrentThreadEP7QThread fun:_ZN23QCoreApplicationPrivateC2ERiPPc fun:_ZN19QApplicationPrivateC1ERiPPcN12QApplication4TypeE fun:_ZN12QApplicationC2ERiPPcb } { Memcheck:Leak fun:malloc fun:_ZN9QHashData12allocateNodeEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE10createNodeEjRKiRKS2_PP9QHashNodeIiS2_E fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZN9QTextLine13layout_helperEi fun:_ZN9QTextLine12setLineWidthEd fun:_Z14qt_format_textRK5QFontRK6QRectFiRK7QStringPS2_iPiiP8QPainter fun:_ZNK12QFontMetrics12boundingRectERK5QRectiRK7QStringiPi fun:_ZNK12QFontMetrics12boundingRectEiiiiiRK7QStringiPi fun:_ZNK13QLabelPrivate12sizeForWidthEi fun:_ZNK6QLabel15minimumSizeHintEv fun:_ZNK6QLabel8sizeHintEv fun:_ZN7QWidget10adjustSizeEv fun:_ZNK11QMessageBox8sizeHintEv fun:_ZN7QWidget10adjustSizeEv fun:_ZN7QWidget10setVisibleEb fun:_ZN7QDialog10setVisibleEb } { Memcheck:Leak fun:malloc fun:strdup fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC2ERiPPcb } { Memcheck:Leak fun:_Znwj fun:_ZN9QHashData13detach_helperEPFvPNS_4NodeEPvEi fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE13detach_helperEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE6detachEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT15minRightBearingEv fun:_ZNK13QFontEngineFT14minLeftBearingEv fun:_ZNK16QFontEngineMulti14minLeftBearingEv fun:_ZNK12QFontMetrics14minLeftBearingEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:_Znwj fun:_ZN9QHashData13detach_helperEPFvPNS_4NodeEPvEi fun:_ZN5QHashI15QFreetypeFaceIdP13QFreetypeFaceE13detach_helperEv fun:_ZN5QHashI15QFreetypeFaceIdP13QFreetypeFaceE6detachEv fun:_ZN5QHashI15QFreetypeFaceIdP13QFreetypeFaceE6insertERKS0_RKS2_ fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:_ZN9QHashData12allocateNodeEv fun:_ZN5QHashI15QFreetypeFaceIdP13QFreetypeFaceE10createNodeEjRKS0_RKS2_PP9QHashNodeIS0_S2_E fun:_ZN5QHashI15QFreetypeFaceIdP13QFreetypeFaceE6insertERKS0_RKS2_ fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC2ERiPPcb } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC2ERiPPcb } { Memcheck:Leak fun:malloc obj:/usr/lib/libXcursor.so.1.0.2 obj:/usr/lib/libXcursor.so.1.0.2 fun:XcursorXcFileLoadImages fun:XcursorFileLoadImages fun:XcursorLibraryLoadImages fun:XcursorLibraryLoadCursor fun:XcursorTryShapeBitmapCursor fun:_XTryShapeBitmapCursor fun:XCreatePixmapCursor fun:_ZN11QCursorData6updateEv fun:_ZNK7QCursor6handleEv fun:_Z21qt_x11_enforce_cursorP7QWidget fun:_ZN7QWidget9setCursorERK7QCursor fun:_ZN24Q3DockWindowResizeHandle14setOrientationEN2Qt11OrientationE fun:_ZN24Q3DockWindowResizeHandleC1EN2Qt11OrientationEP7QWidgetP12Q3DockWindowPKc fun:_ZN12Q3DockWindow4initEv fun:_ZN12Q3DockWindowC2ENS_5PlaceEP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEEb fun:_ZN9Q3ToolBarC2ERK7QStringP12Q3MainWindowP7QWidgetbPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:_ZN9QHashData12allocateNodeEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEE10createNodeEjRKiRKS2_PP9QHashNodeIiS2_E fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZN9QTextLine13layout_helperEi fun:_ZN9QTextLine12setLineWidthEd fun:_Z14qt_format_textRK5QFontRK6QRectFiRK7QStringPS2_iPiiP8QPainter fun:_ZNK12QFontMetrics12boundingRectERK5QRectiRK7QStringiPi fun:_ZNK12QFontMetrics12boundingRectEiiiiiRK7QStringiPi } { Memcheck:Leak fun:_Znwj fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZN9QTextLine13layout_helperEi fun:_ZN9QTextLine12setLineWidthEd fun:_Z14qt_format_textRK5QFontRK6QRectFiRK7QStringPS2_iPiiP8QPainter fun:_ZNK12QFontMetrics12boundingRectERK5QRectiRK7QStringiPi fun:_ZNK12QFontMetrics12boundingRectEiiiiiRK7QStringiPi } { Memcheck:Leak fun:_Znaj fun:_ZN9QHashData6rehashEi fun:_ZN9QHashData9mightGrowEv fun:_ZN5QHashI15QFreetypeFaceIdP13QFreetypeFaceE6insertERKS0_RKS2_ fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:_Znaj fun:_ZN9QHashData6rehashEi fun:_ZN9QHashData9mightGrowEv fun:_ZN5QHashIiPN13QFontEngineFT5GlyphEEixERKi fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK16QFontEngineMulti12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_Z11basic_shapeP11QShaperItem fun:_ZNK11QTextEngine9shapeTextEi fun:_ZNK11QTextEngine5shapeEi fun:_ZN9QTextLine13layout_helperEi fun:_ZN9QTextLine12setLineWidthEd fun:_Z14qt_format_textRK5QFontRK6QRectFiRK7QStringPS2_iPiiP8QPainter fun:_ZNK12QFontMetrics12boundingRectERK5QRectiRK7QStringiPi fun:_ZNK12QFontMetrics12boundingRectEiiiiiRK7QStringiPi } { Memcheck:Leak fun:malloc obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Alloc fun:FT_New_GlyphSlot fun:FT_Open_Face fun:FT_New_Face fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Param clone(child_tidptr) fun:clone fun:clone } { Memcheck:Param write(buf) fun:pthread_key_delete fun:_Z41__static_initialization_and_destruction_0ii obj:/usr/local/lib/libstdc++.so.6.0.7 obj:/usr/local/lib/libstdc++.so.6.0.7 fun:_dl_fini fun:exit fun:__libc_start_main } { Memcheck:Leak fun:malloc fun:_XlcDefaultMapModifiers fun:XSetLocaleModifiers fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget7destroyEbb } { Memcheck:Leak fun:malloc fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget7destroyEbb } { Memcheck:Leak fun:_Znwj fun:_ZN18QMessageBoxPrivate4initEiii fun:_ZN11QMessageBoxC1ERK7QStringS2_NS_4IconEiiiP7QWidget6QFlagsIN2Qt10WindowTypeEE fun:_Z7textBoxP7QWidgetN11QMessageBox4IconERK7QStringS5_S5_S5_S5_ii fun:_ZN11QMessageBox11informationEP7QWidgetRK7QStringS4_S4_S4_S4_ii } { Memcheck:Leak fun:malloc fun:_XimOpenIM fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget7destroyEbb } { Memcheck:Leak fun:_Znwj fun:_Z9qPRCreatePK7QWidgetm fun:_ZN14QWidgetPrivate13setParent_sysEP7QWidget6QFlagsIN2Qt10WindowTypeEE fun:_ZN7QWidget9setParentEPS_6QFlagsIN2Qt10WindowTypeEE fun:_ZN7QWidget9setParentEPS_ fun:_ZN10Q3DockArea14moveDockWindowEP12Q3DockWindowi fun:_ZN12Q3MainWindow14moveDockWindowEP12Q3DockWindowN2Qt4DockE fun:_ZN12Q3MainWindow13addDockWindowEP12Q3DockWindowN2Qt4DockEb fun:_ZN12Q3DockWindow4initEv fun:_ZN12Q3DockWindowC2ENS_5PlaceEP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEEb fun:_ZN9Q3ToolBarC2ERK7QStringP12Q3MainWindowP7QWidgetbPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:XextCreateExtension fun:XInput_find_display fun:_XiGetExtensionVersion fun:XGetExtensionVersion fun:_Z17isXInputSupportedP9_XDisplay fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:XmbTextListToTextProperty fun:_Z14qstring_to_xtpRK7QString fun:_ZN14QWidgetPrivate18setWindowTitle_sysERK7QString fun:_ZN14QWidgetPrivate21setWindowTitle_helperERK7QString fun:_ZN7QWidget14setWindowTitleERK7QString } { Memcheck:Leak fun:malloc fun:FT_New_Memory fun:FT_Init_FreeType fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XimSetLocalIMDefaults fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcOpenConverter fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Leak fun:calloc fun:_XlcOpenConverter fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Leak fun:malloc fun:_XlcOpenConverter fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcOpenConverter fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject } { Memcheck:Leak fun:realloc fun:_XlcResolveLocaleName obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XrmInternalStringToQuark fun:XrmPermStringToQuark fun:XrmInitialize fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcOpenConverter fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget7destroyEbb } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XimSetLocalIMDefaults fun:_XimLocalOpenIM fun:_XimOpenIM fun:XOpenIM fun:_ZN16QXIMInputContext10create_ximEv fun:xim_create_callback fun:_XimRegisterIMInstantiateCallback fun:XRegisterIMInstantiateCallback fun:_ZN16QXIMInputContextC1Ev fun:_ZN20QInputContextFactory6createERK7QStringP7QObject fun:_ZNK12QApplication12inputContextEv fun:_ZN7QWidget12inputContextEv fun:_ZN7QWidget7destroyEbb } { Memcheck:Leak fun:_Znwj fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv fun:_ZN10Q3ListView4initEv fun:_ZN10Q3ListViewC2EP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Leak fun:malloc fun:IceAuthFileName fun:_IceGetPoValidAuthIndices fun:IceOpenConnection fun:SmcOpenConnection fun:_ZN15QSessionManagerC1EP12QApplicationR7QStringS3_ fun:_ZN19QApplicationPrivate10initializeEv fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC2ERiPPcb } { Memcheck:Leak fun:_Znwj fun:_ZN5QFontC1ERK7QStringiib fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC2ERiPPcb } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:_XReply fun:XGetWindowProperty fun:_ZNK14QDesktopWidget17availableGeometryEi fun:_ZNK14QDesktopWidget17availableGeometryEPK7QWidget } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:XFlush fun:_ZN7QWidget9setCursorERK7QCursor fun:_ZN24Q3DockWindowResizeHandle14setOrientationEN2Qt11OrientationE fun:_ZN24Q3DockWindowResizeHandleC1EN2Qt11OrientationEP7QWidgetP12Q3DockWindowPKc fun:_ZN12Q3DockWindow4initEv fun:_ZN12Q3DockWindowC2ENS_5PlaceEP7QWidgetPKc6QFlagsIN2Qt10WindowTypeEEb fun:_ZN9Q3ToolBarC2ERK7QStringP12Q3MainWindowP7QWidgetbPKc6QFlagsIN2Qt10WindowTypeEE } { Memcheck:Param writev(vector[...]) obj:/lib/libc-2.3.6.so fun:writev obj:/usr/lib/libX11.so.6.2.0 fun:_X11TransWritev fun:_XSend obj:/usr/lib/libX11.so.6.2.0 fun:XPutImage fun:_ZN7QPixmap9fromImageERK6QImage6QFlagsIN2Qt19ImageConversionFlagEE fun:_ZN12QPaintEngine9drawImageERK6QRectFRK6QImageS2_6QFlagsIN2Qt19ImageConversionFlagEE fun:_ZN15QPainterPrivate11draw_helperERK12QPainterPathNS_13DrawOperationE } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:_XEventsQueued fun:XEventsQueued fun:_ZN19QEventDispatcherX1113processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE fun:_ZN10QEventLoop13processEventsE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE fun:_ZN16QCoreApplication4execEv fun:_ZN12QApplication4execEv } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:realloc obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Realloc fun:FT_GlyphLoader_CheckPoints obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Load_Glyph fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE } { Memcheck:Leak fun:malloc fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:_Znwj fun:_ZN13QFontEngineFTC1EP10_FcPatternRK8QFontDefi fun:_ZN18QFontEngineMultiFT10loadEngineEi fun:_ZN18QFontEngineMultiFTC1EP10_FcFontSetiRK8QFontDef fun:_Z6loadFcPK12QFontPrivateiRK8QFontDef fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei fun:_ZNK12QFontPrivate15engineForScriptEi fun:_ZNK12QFontMetrics6heightEv } { Memcheck:Leak fun:malloc obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Alloc fun:FT_Realloc obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 obj:/usr/lib/libfreetype.so.6.3.8 fun:FT_Load_Glyph fun:_ZNK13QFontEngineFT9loadGlyphEjNS_11GlyphFormatE fun:_ZNK13QFontEngineFT14recalcAdvancesEiP12QGlyphLayout6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT12stringToCMapEPK5QChariP12QGlyphLayoutPi6QFlagsIN11QTextEngine10ShaperFlagEE fun:_ZNK13QFontEngineFT15minRightBearingEv fun:_ZNK13QFontEngineFT14minLeftBearingEv fun:_ZNK16QFontEngineMulti14minLeftBearingEv fun:_ZNK12QFontMetrics14minLeftBearingEv } { Memcheck:Leak fun:calloc obj:/lib/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString fun:_Z17createReadHandlerP9QIODeviceRK10QByteArray } { Memcheck:Leak fun:malloc fun:expand_dynamic_string_token fun:_dl_map_object obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString fun:_Z17createReadHandlerP9QIODeviceRK10QByteArray } { Memcheck:Leak fun:calloc fun:_dl_check_map_versions obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString fun:_Z17createReadHandlerP9QIODeviceRK10QByteArray } { Memcheck:Param write(buf) fun:write fun:_X11TransWrite obj:/usr/lib/libX11.so.6.2.0 fun:_XReply fun:XSync fun:XCloseDisplay fun:_Z10qt_cleanupv fun:_ZN12QApplicationD1Ev } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcAddCT obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcAddCharSet fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcCreateDefaultCharSet fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcSetConverter fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcCreateDefaultCharSet fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcCreateLocaleDataBase obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:_XlcCreateDefaultCharSet fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 fun:_XrmInternalStringToQuark fun:XrmPermStringToQuark fun:XrmInitialize fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Param writev(vector[...]) obj:/lib/libc-2.3.6.so obj:/usr/X11R6/lib/libX11.so.6.2 fun:_X11TransWritev fun:_XSend obj:/usr/X11R6/lib/libX11.so.6.2 fun:XPutImage fun:XCreateBitmapFromData fun:_ZN7QBitmap9fromImageERK6QImage6QFlagsIN2Qt19ImageConversionFlagEE } { Memcheck:Leak fun:_Znwj fun:_ZN7QObjectC2EPS_ fun:_ZN14QImageIOPluginC2EP7QObject } { Memcheck:Leak fun:_Znwj fun:qt_plugin_instance fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc fun:_dl_map_object_deps obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc fun:_dl_map_object fun:openaux fun:_dl_catch_error fun:_dl_map_object_deps obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc fun:decompose_rpath fun:cache_rpath fun:_dl_map_object fun:openaux fun:_dl_catch_error fun:_dl_map_object_deps obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { FontConfig leaks Memcheck:Leak fun:*alloc fun:Fc* } { More FontConfig Leaks Memcheck:Leak fun:*alloc obj:/usr/lib/libfontconfig.so.1.0.4 } { Memcheck:Leak fun:*alloc fun:_dl_new_object fun:_dl_map_object_from_fd fun:_dl_map_object } { Memcheck:Leak fun:malloc obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XrmInternalStringToQuark fun:XrmPermStringToQuark fun:XrmInitialize fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:IceRegisterForProtocolSetup } { Memcheck:Leak fun:*alloc obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC } { Memcheck:Leak fun:_Znwj fun:_ZN26QAbstractFileEngineHandlerC2Ev fun:_ZN26QResourceFileEngineHandlerC1Ev } { Memcheck:Leak fun:malloc fun:FcBlanksCreate obj:/usr/lib/libfontconfig.so.1.0.4 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 fun:XML_ParseBuffer } { Memcheck:Leak fun:calloc obj:/lib/libdl-2.3.6.so fun:dlopen obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcDynamicLoad fun:_XOpenLC } { Memcheck:Leak fun:realloc obj:/usr/lib/libfontconfig.so.1.0.4 fun:FcNameParseCharSet fun:FcNameParse obj:/usr/lib/libfontconfig.so.1.0.4 fun:FcGlobalCacheScanDir fun:FcDirScanConfig fun:FcConfigBuildFonts fun:FcInitLoadConfigAndFonts fun:FcInit } { Memcheck:Leak fun:malloc fun:_XrmInternalStringToQuark fun:XrmPermStringToQuark fun:XrmInitialize fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:realloc fun:_Z8qReallocPvj fun:_ZN9QListData7reallocEi fun:_ZN9QListData7prependEv fun:_ZN5QListIP26QAbstractFileEngineHandlerE7prependERKS1_ fun:_ZN26QAbstractFileEngineHandlerC2Ev fun:_ZN26QResourceFileEngineHandlerC1Ev fun:_Z21resource_file_handlerv fun:_Z22qt_force_resource_initv fun:_Z41__static_initialization_and_destruction_0ii } { Memcheck:Leak fun:malloc fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault } { Memcheck:Leak fun:malloc fun:FcFontSetCreate fun:FcConfigCreate fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:FcConfigCreate fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:FcStrCopyFilename fun:FcConfigSetCache fun:FcConfigCreate fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:FcStrSetCreate fun:FcConfigCreate fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:realloc obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:realloc obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:strdup fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:realloc fun:FcBlanksAdd obj:/usr/lib/libfontconfig.so.1.0.4 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 fun:XML_ParseBuffer fun:FcConfigParseAndLoad fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:XextCreateExtension fun:XInput_find_display fun:_XiGetExtensionVersion fun:XGetExtensionVersion fun:_Z17isXInputSupportedP9_XDisplay fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:strdup fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:IceAuthFileName fun:_IceGetPoValidAuthIndices fun:IceOpenConnection fun:SmcOpenConnection fun:_ZN15QSessionManagerC1EP12QApplicationR7QStringS3_ fun:_ZN19QApplicationPrivate10initializeEv fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc obj:/usr/lib/libfontconfig.so.1.0.4 fun:FcStrSetAddFilename fun:FcConfigAddConfigDir fun:FcConfigAddDir obj:/usr/lib/libfontconfig.so.1.0.4 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 fun:XML_ParseBuffer fun:FcConfigParseAndLoad fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:expand_dynamic_string_token fun:_dl_map_object obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:_XlcAddCharSet fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:FcStrCopyFilename fun:FcStrSetAddFilename fun:FcConfigAddConfigDir fun:FcConfigAddDir obj:/usr/lib/libfontconfig.so.1.0.4 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 obj:/usr/lib/libexpat.so.0.5.0 fun:XML_ParseBuffer fun:FcConfigParseAndLoad fun:FcInitLoadConfig fun:FcInitLoadConfigAndFonts fun:FcInit fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:_XlcCreateDefaultCharSet fun:_XlcAddCT fun:_XlcInitCTInfo obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:calloc fun:pthread_setspecific fun:_ZN14QThreadPrivate16setCurrentThreadEP7QThread fun:_ZN23QCoreApplicationPrivateC2ERiPPc fun:_ZN19QApplicationPrivateC1ERiPPcN12QApplication4TypeE fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:calloc fun:_dl_check_map_versions obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:_dl_map_object_deps obj:/lib/libc-2.3.6.so fun:_dl_catch_error fun:_dl_open obj:/lib/libdl-2.3.6.so fun:_dl_catch_error obj:/lib/libdl-2.3.6.so fun:dlopen obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Leak fun:malloc fun:_XlcSetConverter fun:_XlcInitCTInfo obj:/usr/X11R6/lib/libX11.so.6.2 obj:/usr/X11R6/lib/libX11.so.6.2 fun:_XlcCreateLC fun:_XlcDefaultLoader fun:_XlcDynamicLoad fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/X11R6/lib/libX11.so.6.2 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm fun:_ZN19QApplicationPrivate9constructEv fun:_ZN12QApplicationC1ERiPPc } { Memcheck:Addr4 obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:__libc_dlopen_mode obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so fun:iconv_open } { Memcheck:Cond obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:__libc_dlopen_mode obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so fun:iconv_open } { Memcheck:Cond obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:__libc_dlopen_mode obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so fun:iconv_open } { Memcheck:Cond obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString fun:_Z17createReadHandlerP9QIODeviceRK10QByteArray fun:_ZN19QImageReaderPrivate11initHandlerEv } { Memcheck:Cond obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Cond obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:_Znwj fun:_Z12systemLocalev fun:_Z13systemPrivatev fun:_Z14defaultPrivatev fun:_ZN7QLocaleC1Ev fun:_ZN19QResourceFileEngineC1ERK7QString fun:_ZNK26QResourceFileEngineHandler6createERK7QString fun:_ZN19QAbstractFileEngine6createERK7QString } { Memcheck:Leak fun:_Znwj fun:_ZN11QThreadData7currentEv fun:_ZN7QThread13currentThreadEv } { Memcheck:Leak fun:malloc fun:XextCreateExtension fun:XInput_find_display fun:_XiGetExtensionVersion fun:XGetExtensionVersion fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:calloc obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc fun:strdup fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc fun:XauFileName fun:XauGetBestAuthByAddr fun:_X11TransConnectDisplay fun:XOpenDisplay fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:malloc fun:IceAuthFileName fun:_IceGetPoValidAuthIndices fun:IceOpenConnection fun:SmcOpenConnection fun:_ZN15QSessionManagerC1EP12QApplicationR7QStringS3_ } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm } { Memcheck:Leak fun:_Znwj fun:_ZN11QThreadData7currentEv fun:_ZN7QThread13currentThreadEv fun:_ZN23QCoreApplicationPrivateC2ERiPPc fun:_ZN19QApplicationPrivateC1ERiPPcN12QApplication4TypeE } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:_Znwj fun:_ZN14QLocalePrivate19updateSystemPrivateEv fun:_Z13systemPrivatev fun:_Z14defaultPrivatev fun:_ZN7QLocaleC1Ev fun:_ZN19QResourceFileEngineC1ERK7QString fun:_ZNK26QResourceFileEngineHandler6createERK7QString fun:_ZN19QAbstractFileEngine6createERK7QString } { Memcheck:Leak fun:_Znwj fun:_ZN14QWaitConditionC1Ev fun:_ZN14QThreadPrivateC1EP11QThreadData fun:_ZN14QAdoptedThreadC1EP11QThreadData fun:_ZN11QThreadData7currentEv fun:_ZN7QThread13currentThreadEv } { Memcheck:Leak fun:_Znwj fun:_ZN14QAdoptedThreadC1EP11QThreadData fun:_ZN11QThreadData7currentEv fun:_ZN7QThread13currentThreadEv fun:_ZN23QCoreApplicationPrivateC2ERiPPc } { Memcheck:Leak fun:_Znwj fun:_ZN6QMutexC1ENS_13RecursionModeE fun:_ZN11QThreadDataC1Ev fun:_ZN11QThreadData7currentEv } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:malloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString } { Memcheck:Leak fun:realloc obj:/usr/lib/libX11.so.6.2.0 obj:/usr/lib/libX11.so.6.2.0 fun:_XlcCreateLC fun:_XlcUtf8Loader fun:_XOpenLC fun:_XrmInitParseInfo obj:/usr/lib/libX11.so.6.2.0 fun:XrmGetStringDatabase fun:XGetDefault fun:_Z11getXDefaultPKcS0_Pi } { Memcheck:Leak fun:calloc obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString fun:_Z17createReadHandlerP9QIODeviceRK10QByteArray } { Memcheck:Leak fun:malloc obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv fun:_ZNK14QFactoryLoader8instanceERK7QString fun:_Z17createReadHandlerP9QIODeviceRK10QByteArray } { Memcheck:Leak fun:memalign fun:posix_memalign obj:/usr/lib/libglib-2.0.so.0.1000.3 fun:g_slice_alloc fun:g_ptr_array_sized_new fun:g_ptr_array_new fun:g_main_context_new fun:g_main_context_default } { Memcheck:Leak fun:calloc fun:g_malloc0 fun:g_main_context_new fun:g_main_context_default } { Memcheck:Leak fun:calloc obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libc-2.3.6.so obj:/lib/ld-2.3.6.so fun:_dl_open obj:/lib/tls/i686/cmov/libdl-2.3.6.so obj:/lib/ld-2.3.6.so obj:/lib/tls/i686/cmov/libdl-2.3.6.so fun:dlopen fun:_ZN15QLibraryPrivate8load_sysEv fun:_ZN15QLibraryPrivate4loadEv fun:_ZN15QLibraryPrivate10loadPluginEv }psi-0.14/qa/oldtest/0000755000175000017500000000000011305557613012420 5ustar janjanpsi-0.14/qa/oldtest/unittest.pri0000644000175000017500000000306611305557613015020 0ustar janjan# helpers to reduce the size of unittest projects unittest { TEMPLATE = app CONFIG += qtestlib console debug qt CONFIG -= app_bundle } windows { # otherwise we would get 'unresolved external _WinMainCRTStartup' # when compiling with MSVC MOC_DIR = _moc OBJECTS_DIR = _obj UI_DIR = _ui RCC_DIR = _rcc } !windows { MOC_DIR = .moc OBJECTS_DIR = .obj UI_DIR = .ui RCC_DIR = .rcc } mac:app_bundle { EXEC_TARGET = $${TARGET}.app/Contents/MacOS/$${TARGET} } else { EXEC_TARGET = $$TARGET } # run target (TODO: Make it work on Windows too) QMAKE_EXTRA_TARGETS += run run.depends = $$EXEC_TARGET run.commands = PSIDATADIR=~/.psi-test ./$$EXEC_TARGET unix { # gdb target QMAKE_EXTRA_TARGETS += gdb gdb.depends = $$EXEC_TARGET mac { QT_FRAMEWORK_VERSION = 4 QT_FRAMEWORKS = QtCore QtXml QtNetwork QtGui QtSql FRAMEWORK = \$(QTDIR)/lib/\$\${f}.framework/Versions/$$QT_FRAMEWORK_VERSION/\$\${f} gdb.commands += \ for f in $$QT_FRAMEWORKS; do \ install_name_tool -id "$$FRAMEWORK" "$$FRAMEWORK""_debug"; \ install_name_tool -change "$$FRAMEWORK" "$$FRAMEWORK""_debug" "./$$EXEC_TARGET"; \ done; } gdb.commands += PSIDATADIR=~/.psi-test gdb ./$$EXEC_TARGET mac { gdb.commands += ; \ for f in $$QT_FRAMEWORKS; do \ install_name_tool -id "$$FRAMEWORK""_debug" "$$FRAMEWORK""_debug"; \ install_name_tool -change "$$FRAMEWORK""_debug" "$$FRAMEWORK" "./$$EXEC_TARGET"; \ done; } } mac { # xcode target QMAKE_EXTRA_TARGETS += xcode xcode.depends = Makefile xcode.commands = ${QMAKE} -spec macx-xcode -o $$TARGET } psi-0.14/qa/oldtest/tests.txt0000644000175000017500000000035311305557613014324 0ustar janjan# This file contains a relative path to each unittest # directory on separate line. ../src/tools/iconset/unittest ../src/widgets/unittest/iconaction ../src/widgets/unittest/richtext ../src/unittest/psiiconset ../src/unittest/psipopup psi-0.14/qa/oldtest/unittest.pro0000644000175000017500000000047011305557613015022 0ustar janjan# WARNING! All changes made in this file will be lost! TEMPLATE = subdirs SUBDIRS += \ ../src/tools/iconset/unittest \ ../src/widgets/unittest/iconaction \ ../src/widgets/unittest/richtext \ ../src/unittest/psiiconset \ ../src/unittest/psipopup QMAKE_EXTRA_TARGETS += check check.commands = sh ./checkall psi-0.14/qa/oldtest/update.rb0000644000175000017500000000176411305557613014237 0ustar janjan#! /usr/bin/env ruby # This script is used to update auto-generated # files named 'checkall' and 'unittest.pro'. # get list of path names tests = File.new('tests.txt').readlines.find_all { |i| i =~ /^[^#]/ }.collect { |i| i.chomp } # this string is used to indicate the file is auto-generated WARNING = "WARNING! All changes made in this file will be lost!" # generate 'checkall' script File::open('checkall', 'w') do |f| f << "#!/bin/bash\n" f << "# #{WARNING}\n" f << "basedir=`pwd`\n" f << "do_make() {\n" f << " if test ! -e Makefile; then qmake; fi\n" f << " make check\n" f << "}\n" f << tests.collect { |dir| "cd #{dir} && do_make && cd $basedir" }.join(" && \\\n") + "\n" end # generate project file File::open('unittest.pro', 'w') do |f| f << "# #{WARNING}\n" f << "TEMPLATE = subdirs\n\n" f << "SUBDIRS += \\\n" f << tests.collect { |dir| "\t#{dir}" }.join(" \\\n") + "\n" f << "\n" f << "QMAKE_EXTRA_TARGETS += check\n" f << "check.commands = sh ./checkall\n" end psi-0.14/qa/oldtest/checkall0000644000175000017500000000071711305557613014116 0ustar janjan#!/bin/bash # WARNING! All changes made in this file will be lost! basedir=`pwd` do_make() { if test ! -e Makefile; then qmake; fi make check } cd ../src/tools/iconset/unittest && do_make && cd $basedir && \ cd ../src/widgets/unittest/iconaction && do_make && cd $basedir && \ cd ../src/widgets/unittest/richtext && do_make && cd $basedir && \ cd ../src/unittest/psiiconset && do_make && cd $basedir && \ cd ../src/unittest/psipopup && do_make && cd $basedir psi-0.14/qa/guitest/0000755000175000017500000000000011305557613012426 5ustar janjanpsi-0.14/qa/guitest/guitest.h0000644000175000017500000000027311305557613014265 0ustar janjan#ifndef GUITEST_H #define GUITEST_H #include #include class GUITest { public: virtual ~GUITest() { } virtual bool run() = 0; virtual QString name() = 0; }; #endif psi-0.14/qa/guitest/guitestmanager.cpp0000644000175000017500000000130311305557613016146 0ustar janjan#include #include "guitestmanager.h" GUITestManager::GUITestManager() { } GUITestManager* GUITestManager::instance() { if (!instance_) { instance_ = new GUITestManager(); } return instance_; } void GUITestManager::registerTest(GUITest* test) { tests_ += test; } bool GUITestManager::runTest(const QString& name) { foreach(GUITest* test, tests_) { if (test->name() == name) { return test->run(); } } qWarning() << "Test not found: " << name; return false; } QStringList GUITestManager::getTestNames() const { QStringList test_names; foreach(GUITest* test, tests_) { test_names += test->name(); } return test_names; } GUITestManager* GUITestManager::instance_ = NULL; psi-0.14/qa/guitest/guitest.cpp0000644000175000017500000000105211305557613014614 0ustar janjan#include #include #include #include "guitestmanager.h" int main(int argc, char** argv) { if (argc < 2) { std::cerr << "Usage: " << argv[0] << " " << std::endl << std::endl; std::cerr << "The following tests are available: " << std::endl; foreach(QString test, GUITestManager::instance()->getTestNames()) { std::cerr << " " << (std::string) test << std::endl; } return -1; } QApplication a(argc, argv); if (GUITestManager::instance()->runTest(argv[1])) { return a.exec(); } return 0; } psi-0.14/qa/guitest/guitestmanager.h0000644000175000017500000000056511305557613015624 0ustar janjan#ifndef GUITESTMANAGER_H #define GUITESTMANAGER_H #include #include "guitest.h" class GUITestManager { public: static GUITestManager* instance(); void registerTest(GUITest* test); bool runTest(const QString& name); QStringList getTestNames() const; private: GUITestManager(); static GUITestManager* instance_; QList tests_; }; #endif psi-0.14/qa/guitest/guitest.pro0000644000175000017500000000050211305557613014631 0ustar janjanCONFIG -= app_bundle MOC_DIR = ../../src/.moc OBJECTS_DIR = ../../src/.obj UI_DIR = ../../src/.ui CONFIG += pep DEFINES += QT_STATICPLUGIN include(../../conf.pri) include(../../src/src.pri) SOURCES += \ guitest.cpp \ guitestmanager.cpp include(../../src/privacy/guitest/guitest.pri) QMAKE_CLEAN += ${QMAKE_TARGET} psi-0.14/psi.qrc0000644000175000017500000000040011305557613011635 0ustar janjan README COPYING options/default.xml options/windows.xml options/macosx.xml options/newprofile.xml psi-0.14/psi.qc0000644000175000017500000000144111305557613011461 0ustar janjan Psi psi.pro psi qcm psi-0.14/.gitignore0000644000175000017500000000146111305557613012333 0ustar janjan/Makefile /conf.log /conf.pri /tmtags /psi ._* .DS_Store .AppleDouble :2e_* *.swp qrc_* *.moc *.o *.pdb ui_* moc_* mocinclude.tmp release/ debug/ Makefile.Release Makefile.Debug third-party/qca/.moc third-party/qca/_moc third-party/qca/.obj third-party/qca/_obj third-party/qca/libqca_psi.a third-party/qca/Makefile src/.moc src/_moc src/.obj src/_obj src/.rcc src/_rcc src/.ui src/_ui src/Makefile src/config.h src/psi.app src/psi src/capabilities/unittest/Makefile src/unittest/Makefile src/utilities/unittest/Makefile src/AutoUpdater/guitest/Makefile src/AutoUpdater/guitest/testapp-2.0/Makefile src/AutoUpdater/guitest/testapp-2.0/testapp.app src/AutoUpdater/guitest/testapp-2.0/testapp-2.0.zip src/AutoUpdater/guitest/testapp/Makefile src/AutoUpdater/guitest/testapp/testapp.app src/plugins/*/*/Makefile checker psi-0.14/README0000644000175000017500000002235211305560070011214 0ustar janjanPsi 0.14 -------- Date: November 7th, 2009 Maintainers: Justin Karneges (2001-2004, 2009-current) justin@affinix.com http://psi-im.org/ Kevin Smith (2004-2009) kismith@psi-im.org http://www.kismith.co.uk/ For installation or compiling instructions, see the INSTALL file. This program is licensed under the GNU General Public License. See the COPYING file for more information. Known Issues ------------ The following are known issues with this release: Issues with Qt 4.5.0: Hang on exit, hang when using GnuPG. Issues with QCA <2.0.2 + Qt 4.5: Hang on exit. Issues with qca-gnupg <2.0.0-beta3 + Qt 4.5: Hang when using GnuPG. Notes ----- - QCA -- * QCA 2.x is required to build Psi: a version is bundled with Psi. * The qca-ossl and qca-gnupg plugins are desirable for full functionality of Psi. - Voice Calling -- * The PsiMedia 1.0.x plugin and the qca-ossl plugin are needed to activate the voice calling feature. Source and builds of PsiMedia can be found at: http://delta.affinix.com/psimedia/ On Windows, place gstprovider.dll into the base directory. On Mac, place libgstprovider.dylib into Psi.app/Contents/plugins On Linux, place libgstprovider.so into LIBDIR/psi/plugins - Upgrading to 0.12 -- * During the upgrade process, the old config.xml configuration file will be imported into the new option.xml format. Neither file should now be edited by hand, since all options are exposed in the options window. Config.xml can be safely removed once the upgrade is complete. - GnuPG tips -- * Always use the latest version of GnuPG. * On Windows, use a native build instead of one based on cygwin, and make sure it is properly installed in the registry. * Ensure 'gpg' actually works, by testing it from the command-line. * You must have a public and secret keyring. Psi cannot operate without them, and they must be there when you start it. Changes ------- New in 0.14 - Added color options to the chat window. - Can now specify a reason for kick/ban in groupchat. - Improved User Info window, to show more fields and photo view/save. - Support for Enchant as an alternative to Aspell. - Commandline interface now supports choosing profile and setting status. - D-BUS interface now supports setting status and indicating sleep/wake. - Fixed voice calling compatibility bugs with Pidgin and Empathy. - Various other minor improvements and bugfixes. New in 0.13 - Voice calls (Jingle RTP). - Basic XMPP URI handler. - Ability to permanently trust certificates at connect time. - Mini command system (Ctrl+7 in chat window). - Various bugfixes. New in 0.12.1 - Bugfix for DOS vulnerability in the file transfer code. Thanks to Jesus Olmos (jolmos@isecauditors.com) New in 0.12 - Multi-user chat windows now join one on one chat windows and can be opened in tabbed form, either sharing a window, or seperately. - The roster search has been updated, and now triggers a filter when typing into the roster window. - An XML ringbuffer is now used, allowing access to already received XML in the XML console. - When resolving a name for new contacts, the full name is now used if the nick name is missing from the vcard. - Auto-connect on wake is now an independent option. - MUCs can now be bookmarked, and auto-joined. - The old config.xml file has been dropped in favour of the new options.xml format - all options in Psi can now be configured from the Advanced options pane (no more hand-editing of config files is required). - Vcard avatars are now transmitted for the benefit of legacy clients and servers not supporting PEP. - A new diagnostics group is available in the help menu, to allow debugging problems with the QCA security layer. - Launching several instances of the same profile on Windows and Unices with DBUS now behaves more sensibly. - On X11, the taskbar should now flash on new messages for compliant window managers. New in 0.11 - Reworked account registration process (including proper support for XEP-0077 (In-band registration)) - Finished support for XEP-0004 (Data Forms) by supporting forms in messages. (thanks to Roelof Naude) - Added support for XEP-0070 (Verifying HTTP Requests via XMPP). Thanks to Maciej Niedzielski. - Customizable shortcuts (thanks to Ephraim) - System-wide shortcuts - Added spell checking (thanks to Ephraim). Currently only aspell is supported. - Added option to automatically set the resource (using the hostname) - Added new default Stellar3 iconset - Added support for XEP-138 (Stream Compression) - Added support for using XEP-33 (Extended Stanza Addressing) to multicast messages to multiple users. Use option.enable-multicasting to enable it. - Added 'Show status message' toggle. There is a hidden option to put status messages under the nickname (at the cost of 2 extra pixels when no status message is shown) - Support for Bookmark Storage (XEP-0048), where bookmarked conferences are auto-joined. No UI is provided for creating bookmarks (yet). - Better error messages, including error condition mappings (XEP-0086) - Support dynamically changing priority - Improved PGP error messages - Hiding the deprecated protocol selector for service discovery by default. Use option.ui.show-deprecated.service-discovery.protocol-selector to re-enable it. - New options system (see options.xml) - Receiving support for vCard-Based Avatars (XEP-0153) - Support for Multi-User-Chat (XEP-0045) - Preliminary support for User Nickname (XEP-0172) - Preliminary support for Roster Item Exchange (XEP-0144) - Psi now uses the Qt4(>=4.3) and QCA2 libraries, replacing the Qt3 and QCA1 requirements. - "Privacy List" support in the account dialog. - Support for XEP-0050 (Ad-hoc commands) - Preliminary support for XEP-0163 (Personal Eventing Protocol) - Preliminary support for XEP-0146 (Remote Controlling Clients) - Large parts of the codebase have been restructured. - Fixed a chat room bug where subject/topic changes were not shown. - Mac OS X builds are now universal binaries, supporting the new Intel based Macs. - Support for XEP-85 (Chat State Notifications). - Support for XEP-0115 (Entity Capabilities). - There is now a config.xml option to make some windows use the brushed metal theme on Mac OS X. - Window opacity support is now present for all three supported platforms. - Fixed Unicode URL opening bug #510 - Auto-reconnect accounts on wakeup - Copy-pasting with emoticons now works - Fixed issue #263 where emoticons would disappear in a reply or quote - History index is rebuilt faster - Configure toolbars merged into main preferences dialog - Moving tooltips - MingW32 compiler support (Coupled with the open source Qt4 Windows library this now allows completely free building of Psi on Windows) Description ----------- Psi is a capable Jabber client aimed at experienced users. Its design goals are simplicity and stability. Psi is highly portable and runs on Windows, Unix/X11, and Mac OS X. The interface is very ICQ-like. Alerts appear in the contact list when events are received, and things like subscriptions requests appear as "system messages" (ICQ users know these well). Even "Chats" are queued in the contact list. Also, chats are "remembered" by default, so that you don't have to keep a bunch of windows open for each person. Just close the chat window. If you open it again it will all be there. Psi is minimal but powerful. There are keybindings for just about everything, Unicode is supported throughout, and contacts are cached offline. Security is also a major consideration, and Psi provides it for both client-to-server (SSL) and client-to-client (GnuPG). How you can help ---------------- Comments -------- We like comments, even (especially) if they are a simple thanks. Bug reports ----------- If you want to help us out, please file a bug report on our forum at http://forum.psi-im.org/forum/2 for release versions, or email us a bug report to the development mailing list for development builds, details at: http://lists.affinix.com/listinfo.cgi/psi-devel-affinix.com Please be as descriptive as possible and tell us what exactly you were doing at the time something went wrong. If possible, send us a stack backtrace. Wishes ------ We can't possibly know what everyone wants, so we appreciate all feature requests. These can be submitted to http://forum.psi-im.org/forum/4 Porting ------- Psi should be very portable. Please e-mail us first if you want to port Psi to another platform. Graphics -------- There are many ways to contribute to the Psi project, if you think you can do a better job with any of the Psi graphics, then go right ahead! Sound ----- Same goes for sound. Start mixing! Programming ----------- Patches are welcome. External tools would be useful as well, like Licq conversion utilities (iconsets, message history, etc). Get to work! Packaging --------- Want to make an RPM or something? Financial --------- You can send a paypal gift if you'd like, to donate@psi-im.org Have fun, -The Psi team psi-0.14/certs/0000755000175000017500000000000011305557613011461 5ustar janjanpsi-0.14/certs/startcom_ca.crt0000644000175000017500000000344211305557613014475 0ustar janjan-----BEGIN CERTIFICATE----- MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0 Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0 OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x 18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5 yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/ YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1 ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p 00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb cCOxgN8aIDjnfg== -----END CERTIFICATE----- psi-0.14/certs/README0000644000175000017500000000075411305557613012347 0ustar janjanThis directory contains the SSL certificates shipped with psi. The files should be in PEM format, and should have the extension '.crt' or '.pem'. Please use PSIDATADIR/certs for local additions. Default value of PSIDATADIR: Linux, MacOS X and other Unices ~/.psi/ Windows NT, 2000, XP and Server 2003 %UserProfile%\PsiData\ (usually C:\Documents and Settings\username\PsiData ) Windows 95, 98 and Me %ProgramFiles%\Psi\PsiData\ (usually C:\Program Files\Psi\PsiData ) psi-0.14/certs/startcom_ca_new.crt0000644000175000017500000000531011305557613015342 0ustar janjan-----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- psi-0.14/doc/0000755000175000017500000000000011305557613011106 5ustar janjanpsi-0.14/doc/doxygen.header.html0000644000175000017500000000047611305557613014707 0ustar janjan $title psi-0.14/doc/build-win.txt0000644000175000017500000000425211305557613013544 0ustar janjanRequirements ------------ * You need Qt 4.4 or higher to build Psi. Just download and install the MingW32 self-installer. All the instructions below are performed from within the Qt command prompt (found in the Start menu) * You need QCA 2.0 and the QCA OpenSSL plugin, which you can get at http://delta.affinix.com/qca/ Instructions on how to build these packages can be found below. * If you want to use the QCA OpenSSL plugin on Windows, you will need to download and install the OpenSSL package from http://www.openssl.org/related/binaries.html The 'Building QCA' and 'Building QCA the OpenSSL plugin' sections can be skipped by downloading the sources of these packages, and unpackaging them in third-party/qca (see the INSTALL file for the exact location of each package). Then, uncomment the 'CONFIG += qca-static' in conf_windows.pri. Building QCA ------------ * Edit crypto_win.prf and change the QCA_PATH to the dir where you unpacked QCA. Then, change -lqca to -lqca2. * Copy crypto_win.prf to the mkspecs/features subdir of your Qt dir, and rename it to crypto.prf. * In the src/ dir, run the following commands: qmake mingw32-make * Copy lib/qca2.dll to your system dir (e.g. \Windows\System32) Building the QCA OpenSSL plugin ------------------------------- * Go to the dir where you unpacked OpenSSL. In the lib\MingW subdir of that dir, copy the files ssleay32.a and libeay32.a to ssleay32.lib and libeay32.lib respectively. * Edit qca-openssl.pro, and change the OPENSSL_PREFIX in the windows section to point to the dir where you installed OpenSSL (e.g. C:/OpenSSL). Change -L$$OPENSSL_PREFIX/lib into -L$$OPENSSL_PREFIX/lib/MingW. * Run the following commands: qmake mingw32-make Building Psi ------------ * Edit src/src.pro in the Psi tree, and remove the line CONFIG += debug. * From the toplevel dir in your tree, run the following commands: qmake mingw32-make * There should now be a binary psi.exe in src/release. Packaging Psi ------------- To package everything up into a self-containing dir, edit win32/Makefile to reflect your local setup, and run mingw32-make -C win32 This should make a dir win32/psi with all the necessary files. psi-0.14/doc/Doxyfile.public0000644000175000017500000002451611305557613014101 0ustar janjan# Doxyfile 1.4.5 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = Psi PROJECT_NUMBER = OUTPUT_DIRECTORY = doc/api/public CREATE_SUBDIRS = no OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 5 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = . FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM \ *.PY RECURSIVE = YES EXCLUDE = _darcs/ \ third-party/ \ iris/libidn/ \ iris/irisnet/ \ iris/irisnet/jdns \ iris/example \ src/tools/tunecontroller/plugins/winamp/third-party \ src/tools/iconset/unittest \ src/tools/optionstree/optionstreeviewtest \ src/tools/zip/minizip \ src/unittest \ src/widgets/private/ \ src/widgets/unittest/ \ doc/ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */.ui/* \ */.moc/* \ moc_* EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = . HTML_FILE_EXTENSION = .html HTML_HEADER = doc/doxygen.header.html HTML_FOOTER = doc/doxygen.footer.html HTML_STYLESHEET = doc/doxygen.css HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = YES psi-0.14/doc/build-unix.txt0000644000175000017500000000376211305557613013737 0ustar janjanRequirements ------------ * You need Qt 4.4 or higher to build Psi. If a packaged version of Qt is not available for your OS (or if you want debug symbols in your Qt libraries), you will need to build and install Qt 4.4 yourself. See the Qt instructions to find out how to do this. * You need QCA 2.0 and the QCA OpenSSL plugin, which you can get at http://delta.affinix.com/qca/ Instructions on how to build these packages can be found below. The 'Building QCA' and 'Building QCA the OpenSSL plugin' sections can be skipped by downloading the sources of these packages, and unpackaging them in third-party/qca (see the INSTALL file for the exact location of each package). Building QCA ------------ After unpacking the QCA sources, run the following command: ./configure --prefix=/usr/local/qca2 If configure cannot find your Qt4 library, use the --qtdir option to specify the path to Qt (e.g. /usr/share/qt4), or make sure that the qmake binary for Qt4 occurs first in your PATH. If something else goes wrong, use the --verbose option to get more information on the configuration process. After QCA configured, run make make install To be able to run applications using QCA2, you will need to add /usr/local/qca2/lib to /etc/ld.so.conf and run ldconfig, or add /usr/local/qca2/lib to your LD_LIBRARY_PATH. Building the QCA OpenSSL plugin ------------------------------- After unpacking the QCA OpenSSL plugin's sources, run the following commands ./configure make make install See above on how to troubleshoot configure problems. Building the QCA GnuPG plugin ------------------------------- After unpacking the QCA GnuPG plugin's sources, run the following commands ./configure make make install See above on how to troubleshoot configure problems. Building Psi ------------ From the toplevel Psi source dir, run the following commands: ./configure --prefix=/usr/local/psi make make install This should configure, build, and install Psi. See above on how to troubleshoot configure problems. psi-0.14/doc/build-mac.txt0000644000175000017500000000167311305557613013513 0ustar janjanBuilding Psi on Mac OS X ------------------------ To simply compile Psi, the same instructions apply as for other *nix platforms: 1. First, configure the build using the 'configure' script, optionally adding parameters to specify where to find certain dependencies: ./configure 2. Build the binary: make After this, the built binary 'psi.app' will be available in src/. For more details, check 'doc/build-unix.txt'. To make a distributable copy of your binary, do the following: 1. As above, use configure to configure the build 2. Alter the first lines of 'mac/Makefile' to reflect your setting 3. Run 'make -C mac/'. This will create a distributable binary 'Psi.app' in 'mac/disk/'. 4. (OPTIONAL) Create a DMG image by running 'make -C mac/ dmg'. This will create a 'Psi-.dmg' file in 'mac/'. You can create your own DMG template to make the resulting DMG look different. For more instructions on this, see 'mac/Makefile'. psi-0.14/doc/doxygen.footer.html0000644000175000017500000000041711305557613014750 0ustar janjan
Generated on $datetime for $projectname by doxygen $doxygenversion
psi-0.14/doc/Makefile0000644000175000017500000000024111305557613012543 0ustar janjan.PHONY: all all: .PHONY: api_public api_public: cd .. && doxygen doc/Doxyfile.public .PHONY: api_private api_private: cd .. && doxygen doc/Doxyfile.private psi-0.14/doc/Doxyfile.private0000644000175000017500000002457611305557613014303 0ustar janjan# Doxyfile 1.4.5 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = Psi PROJECT_NUMBER = OUTPUT_DIRECTORY = doc/api/private CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 5 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = . FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM \ *.PY RECURSIVE = YES EXCLUDE = _darcs/ \ third-party/ \ iris/libidn/ \ iris/irisnet/ \ iris/irisnet/jdns \ iris/example \ src/tools/tunecontroller/plugins/winamp/third-party \ src/tools/iconset/unittest \ src/tools/optionstree/optionstreeviewtest \ src/tools/zip/minizip \ src/unittest \ src/widgets/private/ \ src/widgets/unittest/ \ doc/ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */.ui/* \ */.moc/* \ moc_* EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = YES STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = NO USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = . HTML_FILE_EXTENSION = .html HTML_HEADER = doc/doxygen.header.html HTML_FOOTER = doc/doxygen.footer.html HTML_STYLESHEET = doc/doxygen.css HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = YES psi-0.14/doc/doxygen.css0000644000175000017500000002064011305557613013277 0ustar janjanBODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { font-family: Geneva, Arial, Helvetica, sans-serif; } BODY,TD { font-size: 90%; } H1 { text-align: center; font-size: 160%; } H2 { font-size: 120%; } H3 { font-size: 100%; } CAPTION { font-weight: bold } DIV.qindex { width: 100%; background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } DIV.navpath { width: 100%; background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } DIV.navtab { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } TD.navtab { font-size: 70%; } A.qindex { text-decoration: none; font-weight: bold; color: #1A419D; } A.qindex:visited { text-decoration: none; font-weight: bold; color: #1A419D } A.qindex:hover { text-decoration: none; background-color: #ddddff; } A.qindexHL { text-decoration: none; font-weight: bold; background-color: #6666cc; color: #ffffff; border: 1px double #9295C2; } A.qindexHL:hover { text-decoration: none; background-color: #6666cc; color: #ffffff; } A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } A.el { text-decoration: none; font-weight: bold } A.elRef { font-weight: bold } A.code:link { text-decoration: none; font-weight: normal; color: #0000FF } A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF } A.codeRef:link { font-weight: normal; color: #0000FF } A.codeRef:visited { font-weight: normal; color: #0000FF } A:hover { text-decoration: none; background-color: #f2f2ff } DL.el { margin-left: -1cm } .fragment { font-family: monospace, fixed; font-size: 95%; } PRE.fragment { border: 1px solid #CCCCCC; background-color: #f5f5f5; margin-top: 4px; margin-bottom: 4px; margin-left: 2px; margin-right: 8px; padding-left: 6px; padding-right: 6px; padding-top: 4px; padding-bottom: 4px; } DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold; } DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } BODY { background: white; color: black; margin-right: 20px; margin-left: 20px; } TD.indexkey { background-color: #e8eef2; font-weight: bold; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px; border: 1px solid #CCCCCC; } TD.indexvalue { background-color: #e8eef2; font-style: italic; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px; border: 1px solid #CCCCCC; } TR.memlist { background-color: #f0f0f0; } P.formulaDsp { text-align: center; } IMG.formulaDsp { } IMG.formulaInl { vertical-align: middle; } SPAN.keyword { color: #008000 } SPAN.keywordtype { color: #604020 } SPAN.keywordflow { color: #e08000 } SPAN.comment { color: #800000 } SPAN.preprocessor { color: #806020 } SPAN.stringliteral { color: #002080 } SPAN.charliteral { color: #008080 } SPAN.vhdldigit { color: #ff00ff } SPAN.vhdlchar { color: #000000 } SPAN.vhdlkeyword { color: #700070 } SPAN.vhdllogic { color: #ff0000 } .mdescLeft { padding: 0px 8px 4px 8px; font-size: 80%; font-style: italic; background-color: #FAFAFA; border-top: 1px none #E0E0E0; border-right: 1px none #E0E0E0; border-bottom: 1px none #E0E0E0; border-left: 1px none #E0E0E0; margin: 0px; } .mdescRight { padding: 0px 8px 4px 8px; font-size: 80%; font-style: italic; background-color: #FAFAFA; border-top: 1px none #E0E0E0; border-right: 1px none #E0E0E0; border-bottom: 1px none #E0E0E0; border-left: 1px none #E0E0E0; margin: 0px; } .memItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memItemRight { padding: 1px 8px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplItemRight { padding: 1px 8px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplParams { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; color: #606060; background-color: #FAFAFA; font-size: 80%; } .search { color: #003399; font-weight: bold; } FORM.search { margin-bottom: 0px; margin-top: 0px; } INPUT.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } TD.tiny { font-size: 75%; } a { color: #1A41A8; } a:visited { color: #2A3798; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid #84b0c7; } TH.dirtab { background: #e8eef2; font-weight: bold; } HR { height: 1px; border: none; border-top: 1px solid black; } /* Style for detailed member documentation */ .memtemplate { font-size: 80%; color: #606060; font-weight: normal; margin-left: 3px; } .memnav { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } .memitem { padding: 4px; background-color: #eef3f5; border-width: 1px; border-style: solid; border-color: #dedeee; -moz-border-radius: 8px 8px 8px 8px; } .memname { white-space: nowrap; font-weight: bold; } .memdoc{ padding-left: 10px; } .memproto { background-color: #d5e1e8; width: 100%; border-width: 1px; border-style: solid; border-color: #84b0c7; font-weight: bold; -moz-border-radius: 8px 8px 8px 8px; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; } .paramname { color: #602020; font-style: italic; white-space: nowrap; } /* End Styling for detailed member documentation */ /* for the tree view */ .ftvtree { font-family: sans-serif; margin:0.5em; } .directory { font-size: 9pt; font-weight: bold; } .directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } .directory > h3 { margin-top: 0; } .directory p { margin: 0px; white-space: nowrap; } .directory div { display: none; margin: 0px; } .directory img { vertical-align: -30%; } psi-0.14/COPYING0000644000175000017500000003677211305557613011413 0ustar janjan As a special exception, the copyright holder(s) give permission to link this program with the Qt Library (commercial or non-commercial edition), and distribute the resulting executable, without including the source code for the Qt library in the source distribution. As a special exception, the copyright holder(s) give permission to link this program with any other library, and distribute the resulting executable, without including the source code for the library in the source distribution, provided that the library interfaces with this program only via the following plugin interfaces: 1. The Qt Plugin APIs, only as authored by Trolltech 2. The QCA Plugin API, only as authored by Justin Karneges GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS psi-0.14/l10n.pro0000644000175000017500000000047311305557613011641 0ustar janjanTEMPLATE = subdirs CONFIG += ordered include(conf.pri) windows:include(conf_windows.pri) # configure iris unix:system("echo \"include(../src/conf_iris.pri)\" > iris/conf.pri") windows:system("echo include(../src/conf_iris.pri) > iris\\conf.pri") SUBDIRS += \ third-party/qca \ iris \ src psi-0.14/third-party/0000755000175000017500000000000011305557613012610 5ustar janjanpsi-0.14/third-party/qca/0000755000175000017500000000000011305557613013354 5ustar janjanpsi-0.14/third-party/qca/qca-ossl.pri0000644000175000017500000000011711305557613015611 0ustar janjanSOURCES += $$PWD/qca-ossl/qca-ossl.cpp windows { LIBS += -lgdi32 -lwsock32 } psi-0.14/third-party/qca/qca-ossl/0000755000175000017500000000000011305557613015076 5ustar janjanpsi-0.14/third-party/qca/qca-ossl/qca-ossl.cpp0000644000175000017500000047400211305557613017333 0ustar janjan/* * Copyright (C) 2004-2007 Justin Karneges * Copyright (C) 2004-2006 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef OSSL_097 // comment this out if you'd rather use openssl 0.9.6 #define OSSL_097 #endif using namespace QCA; namespace opensslQCAPlugin { //---------------------------------------------------------------------------- // Util //---------------------------------------------------------------------------- static SecureArray bio2buf(BIO *b) { SecureArray buf; while(1) { SecureArray block(1024); int ret = BIO_read(b, block.data(), block.size()); if(ret <= 0) break; block.resize(ret); buf.append(block); if(ret != 1024) break; } BIO_free(b); return buf; } static QByteArray bio2ba(BIO *b) { QByteArray buf; while(1) { QByteArray block(1024, 0); int ret = BIO_read(b, block.data(), block.size()); if(ret <= 0) break; block.resize(ret); buf.append(block); if(ret != 1024) break; } BIO_free(b); return buf; } static BigInteger bn2bi(BIGNUM *n) { SecureArray buf(BN_num_bytes(n) + 1); buf[0] = 0; // positive BN_bn2bin(n, (unsigned char *)buf.data() + 1); return BigInteger(buf); } static BIGNUM *bi2bn(const BigInteger &n) { SecureArray buf = n.toArray(); return BN_bin2bn((const unsigned char *)buf.data(), buf.size(), NULL); } static SecureArray dsasig_der_to_raw(const SecureArray &in) { DSA_SIG *sig = DSA_SIG_new(); const unsigned char *inp = (const unsigned char *)in.data(); d2i_DSA_SIG(&sig, &inp, in.size()); SecureArray part_r(20); SecureArray part_s(20); memset(part_r.data(), 0, 20); memset(part_s.data(), 0, 20); unsigned char *p = (unsigned char *)part_r.data(); BN_bn2bin(sig->r, p); p = (unsigned char *)part_s.data(); BN_bn2bin(sig->s, p); SecureArray result; result.append(part_r); result.append(part_s); DSA_SIG_free(sig); return result; } static SecureArray dsasig_raw_to_der(const SecureArray &in) { if(in.size() != 40) return SecureArray(); DSA_SIG *sig = DSA_SIG_new(); SecureArray part_r(20); SecureArray part_s(20); memcpy(part_r.data(), in.data(), 20); memcpy(part_s.data(), in.data() + 20, 20); sig->r = BN_bin2bn((const unsigned char *)part_r.data(), part_r.size(), NULL); sig->s = BN_bin2bn((const unsigned char *)part_s.data(), part_s.size(), NULL); int len = i2d_DSA_SIG(sig, NULL); SecureArray result(len); unsigned char *p = (unsigned char *)result.data(); i2d_DSA_SIG(sig, &p); DSA_SIG_free(sig); return result; } static int passphrase_cb(char *buf, int size, int rwflag, void *u) { Q_UNUSED(buf); Q_UNUSED(size); Q_UNUSED(rwflag); Q_UNUSED(u); return 0; } /*static bool is_basic_constraint(const ConstraintType &t) { bool basic = false; switch(t.known()) { case DigitalSignature: case NonRepudiation: case KeyEncipherment: case DataEncipherment: case KeyAgreement: case KeyCertificateSign: case CRLSign: case EncipherOnly: case DecipherOnly: basic = true; break; case ServerAuth: case ClientAuth: case CodeSigning: case EmailProtection: case IPSecEndSystem: case IPSecTunnel: case IPSecUser: case TimeStamping: case OCSPSigning: break; } return basic; } static Constraints basic_only(const Constraints &list) { Constraints out; for(int n = 0; n < list.count(); ++n) { if(is_basic_constraint(list[n])) out += list[n]; } return out; } static Constraints ext_only(const Constraints &list) { Constraints out; for(int n = 0; n < list.count(); ++n) { if(!is_basic_constraint(list[n])) out += list[n]; } return out; }*/ // logic from Botan /*static Constraints find_constraints(const PKeyContext &key, const Constraints &orig) { Constraints constraints; if(key.key()->type() == PKey::RSA) constraints += KeyEncipherment; if(key.key()->type() == PKey::DH) constraints += KeyAgreement; if(key.key()->type() == PKey::RSA || key.key()->type() == PKey::DSA) { constraints += DigitalSignature; constraints += NonRepudiation; } Constraints limits = basic_only(orig); Constraints the_rest = ext_only(orig); if(!limits.isEmpty()) { Constraints reduced; for(int n = 0; n < constraints.count(); ++n) { if(limits.contains(constraints[n])) reduced += constraints[n]; } constraints = reduced; } constraints += the_rest; return constraints; }*/ static void try_add_name_item(X509_NAME **name, int nid, const QString &val) { if(val.isEmpty()) return; QByteArray buf = val.toLatin1(); if(!(*name)) *name = X509_NAME_new(); X509_NAME_add_entry_by_NID(*name, nid, MBSTRING_ASC, (unsigned char *)buf.data(), buf.size(), -1, 0); } static X509_NAME *new_cert_name(const CertificateInfo &info) { X509_NAME *name = 0; // FIXME support multiple items of each type try_add_name_item(&name, NID_commonName, info.value(CommonName)); try_add_name_item(&name, NID_countryName, info.value(Country)); try_add_name_item(&name, NID_localityName, info.value(Locality)); try_add_name_item(&name, NID_stateOrProvinceName, info.value(State)); try_add_name_item(&name, NID_organizationName, info.value(Organization)); try_add_name_item(&name, NID_organizationalUnitName, info.value(OrganizationalUnit)); return name; } static void try_get_name_item(X509_NAME *name, int nid, const CertificateInfoType &t, CertificateInfo *info) { int loc; loc = -1; while ((loc = X509_NAME_get_index_by_NID(name, nid, loc)) != -1) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); QByteArray cs((const char *)data->data, data->length); info->insert(t, QString::fromLatin1(cs)); } } static void try_get_name_item_by_oid(X509_NAME *name, const QString &oidText, const CertificateInfoType &t, CertificateInfo *info) { ASN1_OBJECT *oid = OBJ_txt2obj( oidText.toLatin1().data(), 1); // 1 = only accept dotted input if(!oid) return; int loc; loc = -1; while ((loc = X509_NAME_get_index_by_OBJ(name, oid, loc)) != -1) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); QByteArray cs((const char *)data->data, data->length); info->insert(t, QString::fromLatin1(cs)); qDebug() << "oid: " << oidText << ", result: " << cs; } ASN1_OBJECT_free(oid); } static CertificateInfo get_cert_name(X509_NAME *name) { CertificateInfo info; try_get_name_item(name, NID_commonName, CommonName, &info); try_get_name_item(name, NID_countryName, Country, &info); try_get_name_item_by_oid(name, QString("1.3.6.1.4.1.311.60.2.1.3"), IncorporationCountry, &info); try_get_name_item(name, NID_localityName, Locality, &info); try_get_name_item_by_oid(name, QString("1.3.6.1.4.1.311.60.2.1.1"), IncorporationLocality, &info); try_get_name_item(name, NID_stateOrProvinceName, State, &info); try_get_name_item_by_oid(name, QString("1.3.6.1.4.1.311.60.2.1.2"), IncorporationState, &info); try_get_name_item(name, NID_organizationName, Organization, &info); try_get_name_item(name, NID_organizationalUnitName, OrganizationalUnit, &info); // legacy email { CertificateInfo p9_info; try_get_name_item(name, NID_pkcs9_emailAddress, EmailLegacy, &p9_info); QList emails = info.values(Email); QMapIterator it(p9_info); while(it.hasNext()) { it.next(); if(!emails.contains(it.value())) info.insert(Email, it.value()); } } return info; } static X509_EXTENSION *new_subject_key_id(X509 *cert) { X509V3_CTX ctx; X509V3_set_ctx_nodb(&ctx); X509V3_set_ctx(&ctx, NULL, cert, NULL, NULL, 0); X509_EXTENSION *ex = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, (char *)"hash"); return ex; } static X509_EXTENSION *new_basic_constraints(bool ca, int pathlen) { BASIC_CONSTRAINTS *bs = BASIC_CONSTRAINTS_new(); bs->ca = (ca ? 1: 0); bs->pathlen = ASN1_INTEGER_new(); ASN1_INTEGER_set(bs->pathlen, pathlen); X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, 1, bs); // 1 = critical BASIC_CONSTRAINTS_free(bs); return ex; } static void get_basic_constraints(X509_EXTENSION *ex, bool *ca, int *pathlen) { BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ex); *ca = (bs->ca ? true: false); if(bs->pathlen) *pathlen = ASN1_INTEGER_get(bs->pathlen); else *pathlen = 0; BASIC_CONSTRAINTS_free(bs); } enum ConstraintBit { Bit_DigitalSignature = 0, Bit_NonRepudiation = 1, Bit_KeyEncipherment = 2, Bit_DataEncipherment = 3, Bit_KeyAgreement = 4, Bit_KeyCertificateSign = 5, Bit_CRLSign = 6, Bit_EncipherOnly = 7, Bit_DecipherOnly = 8 }; static QByteArray ipaddress_string_to_bytes(const QString &) { return QByteArray(4, 0); } static GENERAL_NAME *new_general_name(const CertificateInfoType &t, const QString &val) { GENERAL_NAME *name = 0; switch(t.known()) { case Email: { QByteArray buf = val.toLatin1(); ASN1_IA5STRING *str = M_ASN1_IA5STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_EMAIL; name->d.rfc822Name = str; break; } case URI: { QByteArray buf = val.toLatin1(); ASN1_IA5STRING *str = M_ASN1_IA5STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_URI; name->d.uniformResourceIdentifier = str; break; } case DNS: { QByteArray buf = val.toLatin1(); ASN1_IA5STRING *str = M_ASN1_IA5STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_DNS; name->d.dNSName = str; break; } case IPAddress: { QByteArray buf = ipaddress_string_to_bytes(val); ASN1_OCTET_STRING *str = ASN1_OCTET_STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_IPADD; name->d.iPAddress = str; break; } case XMPP: { QByteArray buf = val.toUtf8(); ASN1_UTF8STRING *str = ASN1_UTF8STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); ASN1_TYPE *at = ASN1_TYPE_new(); at->type = V_ASN1_UTF8STRING; at->value.utf8string = str; OTHERNAME *other = OTHERNAME_new(); other->type_id = OBJ_txt2obj("1.3.6.1.5.5.7.8.5", 1); // 1 = only accept dotted input other->value = at; name = GENERAL_NAME_new(); name->type = GEN_OTHERNAME; name->d.otherName = other; break; } default: break; } return name; } static void try_add_general_name(GENERAL_NAMES **gn, const CertificateInfoType &t, const QString &val) { if(val.isEmpty()) return; GENERAL_NAME *name = new_general_name(t, val); if(name) { if(!(*gn)) *gn = sk_GENERAL_NAME_new_null(); sk_GENERAL_NAME_push(*gn, name); } } static X509_EXTENSION *new_cert_subject_alt_name(const CertificateInfo &info) { GENERAL_NAMES *gn = 0; // FIXME support multiple items of each type try_add_general_name(&gn, Email, info.value(Email)); try_add_general_name(&gn, URI, info.value(URI)); try_add_general_name(&gn, DNS, info.value(DNS)); try_add_general_name(&gn, IPAddress, info.value(IPAddress)); try_add_general_name(&gn, XMPP, info.value(XMPP)); if(!gn) return 0; X509_EXTENSION *ex = X509V3_EXT_i2d(NID_subject_alt_name, 0, gn); sk_GENERAL_NAME_pop_free(gn, GENERAL_NAME_free); return ex; } static GENERAL_NAME *find_next_general_name(GENERAL_NAMES *names, int type, int *pos) { int temp = *pos; GENERAL_NAME *gn = 0; *pos = -1; for(int n = temp; n < sk_GENERAL_NAME_num(names); ++n) { GENERAL_NAME *i = sk_GENERAL_NAME_value(names, n); if(i->type == type) { gn = i; *pos = n; break; } } return gn; } static void try_get_general_name(GENERAL_NAMES *names, const CertificateInfoType &t, CertificateInfo *info) { switch(t.known()) { case Email: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_EMAIL, &pos); if (pos != -1) { QByteArray cs((const char *)ASN1_STRING_data(gn->d.rfc822Name), ASN1_STRING_length(gn->d.rfc822Name)); info->insert(t, QString::fromLatin1(cs)); ++pos; } } break; } case URI: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_URI, &pos); if (pos != -1) { QByteArray cs((const char *)ASN1_STRING_data(gn->d.uniformResourceIdentifier), ASN1_STRING_length(gn->d.uniformResourceIdentifier)); info->insert(t, QString::fromLatin1(cs)); ++pos; } } break; } case DNS: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_DNS, &pos); if (pos != -1) { QByteArray cs((const char *)ASN1_STRING_data(gn->d.dNSName), ASN1_STRING_length(gn->d.dNSName)); info->insert(t, QString::fromLatin1(cs)); ++pos; } } break; } case IPAddress: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_IPADD, &pos); if (pos != -1) { ASN1_OCTET_STRING *str = gn->d.iPAddress; QByteArray buf((const char *)ASN1_STRING_data(str), ASN1_STRING_length(str)); QString out; // IPv4 (TODO: handle IPv6) if(buf.size() == 4) { out = "0.0.0.0"; } else break; info->insert(t, out); ++pos; } } break; } case XMPP: { int pos = 0; while( pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_OTHERNAME, &pos); if (pos != -1) { OTHERNAME *other = gn->d.otherName; if(!other) break; ASN1_OBJECT *obj = OBJ_txt2obj("1.3.6.1.5.5.7.8.5", 1); // 1 = only accept dotted input if(OBJ_cmp(other->type_id, obj) != 0) break; ASN1_OBJECT_free(obj); ASN1_TYPE *at = other->value; if(at->type != V_ASN1_UTF8STRING) break; ASN1_UTF8STRING *str = at->value.utf8string; QByteArray buf((const char *)ASN1_STRING_data(str), ASN1_STRING_length(str)); info->insert(t, QString::fromUtf8(buf)); ++pos; } } break; } default: break; } } static CertificateInfo get_cert_alt_name(X509_EXTENSION *ex) { CertificateInfo info; GENERAL_NAMES *gn = (GENERAL_NAMES *)X509V3_EXT_d2i(ex); try_get_general_name(gn, Email, &info); try_get_general_name(gn, URI, &info); try_get_general_name(gn, DNS, &info); try_get_general_name(gn, IPAddress, &info); try_get_general_name(gn, XMPP, &info); GENERAL_NAMES_free(gn); return info; } static X509_EXTENSION *new_cert_key_usage(const Constraints &constraints) { ASN1_BIT_STRING *keyusage = 0; for(int n = 0; n < constraints.count(); ++n) { int bit = -1; switch(constraints[n].known()) { case DigitalSignature: bit = Bit_DigitalSignature; break; case NonRepudiation: bit = Bit_NonRepudiation; break; case KeyEncipherment: bit = Bit_KeyEncipherment; break; case DataEncipherment: bit = Bit_DataEncipherment; break; case KeyAgreement: bit = Bit_KeyAgreement; break; case KeyCertificateSign: bit = Bit_KeyCertificateSign; break; case CRLSign: bit = Bit_CRLSign; break; case EncipherOnly: bit = Bit_EncipherOnly; break; case DecipherOnly: bit = Bit_DecipherOnly; break; default: break; } if(bit != -1) { if(!keyusage) keyusage = ASN1_BIT_STRING_new(); ASN1_BIT_STRING_set_bit(keyusage, bit, 1); } } if(!keyusage) return 0; X509_EXTENSION *ex = X509V3_EXT_i2d(NID_key_usage, 1, keyusage); // 1 = critical ASN1_BIT_STRING_free(keyusage); return ex; } static Constraints get_cert_key_usage(X509_EXTENSION *ex) { Constraints constraints; int bit_table[9] = { DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertificateSign, CRLSign, EncipherOnly, DecipherOnly }; ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ex); for(int n = 0; n < 9; ++n) { if(ASN1_BIT_STRING_get_bit(keyusage, n)) constraints += ConstraintType((ConstraintTypeKnown)bit_table[n]); } ASN1_BIT_STRING_free(keyusage); return constraints; } static X509_EXTENSION *new_cert_ext_key_usage(const Constraints &constraints) { EXTENDED_KEY_USAGE *extkeyusage = 0; for(int n = 0; n < constraints.count(); ++n) { int nid = -1; // TODO: don't use known/nid, and instead just use OIDs switch(constraints[n].known()) { case ServerAuth: nid = NID_server_auth; break; case ClientAuth: nid = NID_client_auth; break; case CodeSigning: nid = NID_code_sign; break; case EmailProtection: nid = NID_email_protect; break; case IPSecEndSystem: nid = NID_ipsecEndSystem; break; case IPSecTunnel: nid = NID_ipsecTunnel; break; case IPSecUser: nid = NID_ipsecUser; break; case TimeStamping: nid = NID_time_stamp; break; case OCSPSigning: nid = NID_OCSP_sign; break; default: break; } if(nid != -1) { if(!extkeyusage) extkeyusage = sk_ASN1_OBJECT_new_null(); ASN1_OBJECT *obj = OBJ_nid2obj(nid); sk_ASN1_OBJECT_push(extkeyusage, obj); } } if(!extkeyusage) return 0; X509_EXTENSION *ex = X509V3_EXT_i2d(NID_ext_key_usage, 0, extkeyusage); // 0 = not critical sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free); return ex; } static Constraints get_cert_ext_key_usage(X509_EXTENSION *ex) { Constraints constraints; EXTENDED_KEY_USAGE *extkeyusage = (EXTENDED_KEY_USAGE *)X509V3_EXT_d2i(ex); for(int n = 0; n < sk_ASN1_OBJECT_num(extkeyusage); ++n) { ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(extkeyusage, n); int nid = OBJ_obj2nid(obj); if(nid == NID_undef) continue; // TODO: don't use known/nid, and instead just use OIDs int t = -1; switch(nid) { case NID_server_auth: t = ServerAuth; break; case NID_client_auth: t = ClientAuth; break; case NID_code_sign: t = CodeSigning; break; case NID_email_protect: t = EmailProtection; break; case NID_ipsecEndSystem: t = IPSecEndSystem; break; case NID_ipsecTunnel: t = IPSecTunnel; break; case NID_ipsecUser: t = IPSecUser; break; case NID_time_stamp: t = TimeStamping; break; case NID_OCSP_sign: t = OCSPSigning; break; }; if(t == -1) continue; constraints.append(ConstraintType((ConstraintTypeKnown)t)); } sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free); return constraints; } static X509_EXTENSION *new_cert_policies(const QStringList &policies) { STACK_OF(POLICYINFO) *pols = 0; for(int n = 0; n < policies.count(); ++n) { QByteArray cs = policies[n].toLatin1(); ASN1_OBJECT *obj = OBJ_txt2obj(cs.data(), 1); // 1 = only accept dotted input if(!obj) continue; if(!pols) pols = sk_POLICYINFO_new_null(); POLICYINFO *pol = POLICYINFO_new(); pol->policyid = obj; sk_POLICYINFO_push(pols, pol); } if(!pols) return 0; X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0, pols); // 0 = not critical sk_POLICYINFO_pop_free(pols, POLICYINFO_free); return ex; } static QStringList get_cert_policies(X509_EXTENSION *ex) { QStringList out; STACK_OF(POLICYINFO) *pols = (STACK_OF(POLICYINFO) *)X509V3_EXT_d2i(ex); for(int n = 0; n < sk_POLICYINFO_num(pols); ++n) { POLICYINFO *pol = sk_POLICYINFO_value(pols, n); QByteArray buf(128, 0); OBJ_obj2txt((char *)buf.data(), buf.size(), pol->policyid, 1); // 1 = only accept dotted input out += QString::fromLatin1(buf); } sk_POLICYINFO_pop_free(pols, POLICYINFO_free); return out; } static QByteArray get_cert_subject_key_id(X509_EXTENSION *ex) { ASN1_OCTET_STRING *skid = (ASN1_OCTET_STRING *)X509V3_EXT_d2i(ex); QByteArray out((const char *)ASN1_STRING_data(skid), ASN1_STRING_length(skid)); ASN1_OCTET_STRING_free(skid); return out; } // If you get any more crashes in this code, please provide a copy // of the cert to bradh AT frogmouth.net static QByteArray get_cert_issuer_key_id(X509_EXTENSION *ex) { AUTHORITY_KEYID *akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ex); QByteArray out; if (akid->keyid) out = QByteArray((const char *)ASN1_STRING_data(akid->keyid), ASN1_STRING_length(akid->keyid)); AUTHORITY_KEYID_free(akid); return out; } static Validity convert_verify_error(int err) { // TODO: ErrorExpiredCA Validity rc; switch(err) { case X509_V_ERR_CERT_REJECTED: rc = ErrorRejected; break; case X509_V_ERR_CERT_UNTRUSTED: rc = ErrorUntrusted; break; case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_CRL_SIGNATURE_FAILURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: rc = ErrorSignatureFailed; break; case X509_V_ERR_INVALID_CA: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: rc = ErrorInvalidCA; break; case X509_V_ERR_INVALID_PURPOSE: // note: not used by store verify rc = ErrorInvalidPurpose; break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: rc = ErrorSelfSigned; break; case X509_V_ERR_CERT_REVOKED: rc = ErrorRevoked; break; case X509_V_ERR_PATH_LENGTH_EXCEEDED: rc = ErrorPathLengthExceeded; break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_NOT_YET_VALID: case X509_V_ERR_CRL_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: rc = ErrorExpired; break; case X509_V_ERR_APPLICATION_VERIFICATION: case X509_V_ERR_OUT_OF_MEM: case X509_V_ERR_UNABLE_TO_GET_CRL: case X509_V_ERR_CERT_CHAIN_TOO_LONG: default: rc = ErrorValidityUnknown; break; } return rc; } EVP_PKEY *qca_d2i_PKCS8PrivateKey(const SecureArray &in, EVP_PKEY **x, pem_password_cb *cb, void *u) { PKCS8_PRIV_KEY_INFO *p8inf; // first try unencrypted form BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(bi, NULL); BIO_free(bi); if(!p8inf) { X509_SIG *p8; // now try encrypted form bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); p8 = d2i_PKCS8_bio(bi, NULL); BIO_free(bi); if(!p8) return NULL; // get passphrase char psbuf[PEM_BUFSIZE]; int klen; if(cb) klen = cb(psbuf, PEM_BUFSIZE, 0, u); else klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); if(klen <= 0) { PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ); X509_SIG_free(p8); return NULL; } // decrypt it p8inf = PKCS8_decrypt(p8, psbuf, klen); X509_SIG_free(p8); if(!p8inf) return NULL; } EVP_PKEY *ret = EVP_PKCS82PKEY(p8inf); PKCS8_PRIV_KEY_INFO_free(p8inf); if(!ret) return NULL; if(x) { if(*x) EVP_PKEY_free(*x); *x = ret; } return ret; } class opensslHashContext : public HashContext { public: opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) : HashContext(p, type) { m_algorithm = algorithm; EVP_DigestInit( &m_context, m_algorithm ); } ~opensslHashContext() { EVP_MD_CTX_cleanup(&m_context); } void clear() { EVP_MD_CTX_cleanup(&m_context); EVP_DigestInit( &m_context, m_algorithm ); } void update(const MemoryRegion &a) { EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() ); } MemoryRegion final() { SecureArray a( EVP_MD_size( m_algorithm ) ); EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 ); return a; } Provider::Context *clone() const { return new opensslHashContext(*this); } protected: const EVP_MD *m_algorithm; EVP_MD_CTX m_context; }; class opensslPbkdf1Context : public KDFContext { public: opensslPbkdf1Context(const EVP_MD *algorithm, Provider *p, const QString &type) : KDFContext(p, type) { m_algorithm = algorithm; EVP_DigestInit( &m_context, m_algorithm ); } Provider::Context *clone() const { return new opensslPbkdf1Context( *this ); } SymmetricKey makeKey(const SecureArray &secret, const InitializationVector &salt, unsigned int keyLength, unsigned int iterationCount) { /* from RFC2898: Steps: 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output "derived key too long" and stop. */ if ( keyLength > (unsigned int)EVP_MD_size( m_algorithm ) ) { std::cout << "derived key too long" << std::endl; return SymmetricKey(); } /* 2. Apply the underlying hash function Hash for c iterations to the concatenation of the password P and the salt S, then extract the first dkLen octets to produce a derived key DK: T_1 = Hash (P || S) , T_2 = Hash (T_1) , ... T_c = Hash (T_{c-1}) , DK = Tc<0..dkLen-1> */ // calculate T_1 EVP_DigestUpdate( &m_context, (unsigned char*)secret.data(), secret.size() ); EVP_DigestUpdate( &m_context, (unsigned char*)salt.data(), salt.size() ); SecureArray a( EVP_MD_size( m_algorithm ) ); EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 ); // calculate T_2 up to T_c for ( unsigned int i = 2; i <= iterationCount; ++i ) { EVP_DigestInit( &m_context, m_algorithm ); EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() ); EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 ); } // shrink a to become DK, of the required length a.resize(keyLength); /* 3. Output the derived key DK. */ return a; } protected: const EVP_MD *m_algorithm; EVP_MD_CTX m_context; }; class opensslPbkdf2Context : public KDFContext { public: opensslPbkdf2Context(Provider *p, const QString &type) : KDFContext(p, type) { } Provider::Context *clone() const { return new opensslPbkdf2Context( *this ); } SymmetricKey makeKey(const SecureArray &secret, const InitializationVector &salt, unsigned int keyLength, unsigned int iterationCount) { SecureArray out(keyLength); PKCS5_PBKDF2_HMAC_SHA1( (char*)secret.data(), secret.size(), (unsigned char*)salt.data(), salt.size(), iterationCount, keyLength, (unsigned char*)out.data() ); return out; } protected: }; class opensslHMACContext : public MACContext { public: opensslHMACContext(const EVP_MD *algorithm, Provider *p, const QString &type) : MACContext(p, type) { m_algorithm = algorithm; HMAC_CTX_init( &m_context ); } void setup(const SymmetricKey &key) { HMAC_Init_ex( &m_context, key.data(), key.size(), m_algorithm, 0 ); } KeyLength keyLength() const { return anyKeyLength(); } void update(const MemoryRegion &a) { HMAC_Update( &m_context, (unsigned char *)a.data(), a.size() ); } void final(MemoryRegion *out) { SecureArray sa( EVP_MD_size( m_algorithm ), 0 ); HMAC_Final(&m_context, (unsigned char *)sa.data(), 0 ); HMAC_CTX_cleanup(&m_context); *out = sa; } Provider::Context *clone() const { return new opensslHMACContext(*this); } protected: HMAC_CTX m_context; const EVP_MD *m_algorithm; }; //---------------------------------------------------------------------------- // EVPKey //---------------------------------------------------------------------------- // note: this class squelches processing errors, since QCA doesn't care about them class EVPKey { public: enum State { Idle, SignActive, SignError, VerifyActive, VerifyError }; EVP_PKEY *pkey; EVP_MD_CTX mdctx; State state; bool raw_type; SecureArray raw; EVPKey() { pkey = 0; raw_type = false; state = Idle; } EVPKey(const EVPKey &from) { pkey = from.pkey; CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); state = Idle; } ~EVPKey() { reset(); } void reset() { if(pkey) EVP_PKEY_free(pkey); pkey = 0; raw.clear (); raw_type = false; } void startSign(const EVP_MD *type) { state = SignActive; if(!type) { raw_type = true; raw.clear (); } else { raw_type = false; EVP_MD_CTX_init(&mdctx); if(!EVP_SignInit_ex(&mdctx, type, NULL)) state = SignError; } } void startVerify(const EVP_MD *type) { state = VerifyActive; if(!type) { raw_type = true; raw.clear (); } else { EVP_MD_CTX_init(&mdctx); if(!EVP_VerifyInit_ex(&mdctx, type, NULL)) state = VerifyError; } } void update(const MemoryRegion &in) { if(state == SignActive) { if (raw_type) raw += in; else if(!EVP_SignUpdate(&mdctx, in.data(), (unsigned int)in.size())) state = SignError; } else if(state == VerifyActive) { if (raw_type) raw += in; else if(!EVP_VerifyUpdate(&mdctx, in.data(), (unsigned int)in.size())) state = VerifyError; } } SecureArray endSign() { if(state == SignActive) { SecureArray out(EVP_PKEY_size(pkey)); unsigned int len = out.size(); if (raw_type) { if (pkey->type == EVP_PKEY_RSA) { if(RSA_private_encrypt (raw.size(), (unsigned char *)raw.data(), (unsigned char *)out.data(), pkey->pkey.rsa, RSA_PKCS1_PADDING) == -1) { state = SignError; return SecureArray (); } } else if (pkey->type == EVP_PKEY_DSA) { state = SignError; return SecureArray (); } else { state = SignError; return SecureArray (); } } else { if(!EVP_SignFinal(&mdctx, (unsigned char *)out.data(), &len, pkey)) { state = SignError; return SecureArray(); } } out.resize(len); state = Idle; return out; } else return SecureArray(); } bool endVerify(const SecureArray &sig) { if(state == VerifyActive) { if (raw_type) { SecureArray out(EVP_PKEY_size(pkey)); int len = 0; if (pkey->type == EVP_PKEY_RSA) { if((len = RSA_public_decrypt (sig.size(), (unsigned char *)sig.data(), (unsigned char *)out.data (), pkey->pkey.rsa, RSA_PKCS1_PADDING)) == -1) { state = VerifyError; return false; } } else if (pkey->type == EVP_PKEY_DSA) { state = VerifyError; return false; } else { state = VerifyError; return false; } out.resize (len); if (out != raw) { state = VerifyError; return false; } } else { if(EVP_VerifyFinal(&mdctx, (unsigned char *)sig.data(), (unsigned int)sig.size(), pkey) != 1) { state = VerifyError; return false; } } state = Idle; return true; } else return false; } }; //---------------------------------------------------------------------------- // MyDLGroup //---------------------------------------------------------------------------- // IETF primes from Botan const char* IETF_1024_PRIME = "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" "FFFFFFFF FFFFFFFF"; const char* IETF_2048_PRIME = "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"; const char* IETF_4096_PRIME = "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" "FFFFFFFF FFFFFFFF"; // JCE seeds from Botan const char* JCE_512_SEED = "B869C82B 35D70E1B 1FF91B28 E37A62EC DC34409B"; const int JCE_512_COUNTER = 123; const char* JCE_768_SEED = "77D0F8C4 DAD15EB8 C4F2F8D6 726CEFD9 6D5BB399"; const int JCE_768_COUNTER = 263; const char* JCE_1024_SEED = "8D515589 4229D5E6 89EE01E6 018A237E 2CAE64CD"; const int JCE_1024_COUNTER = 92; static QByteArray dehex(const QString &hex) { QString str; for(int n = 0; n < hex.length(); ++n) { if(hex[n] != ' ') str += hex[n]; } return hexToArray(str); } static BigInteger decode(const QString &prime) { QByteArray a(1, 0); // 1 byte of zero padding a.append(dehex(prime)); return BigInteger(SecureArray(a)); } static QByteArray decode_seed(const QString &hex_seed) { return dehex(hex_seed); } class DLParams { public: BigInteger p, q, g; }; static bool make_dlgroup(const QByteArray &seed, int bits, int counter, DLParams *params) { int ret_counter; DSA *dsa = DSA_generate_parameters(bits, (unsigned char *)seed.data(), seed.size(), &ret_counter, NULL, NULL, NULL); if(!dsa) return false; if(ret_counter != counter) return false; params->p = bn2bi(dsa->p); params->q = bn2bi(dsa->q); params->g = bn2bi(dsa->g); DSA_free(dsa); return true; } static bool get_dlgroup(const BigInteger &p, const BigInteger &g, DLParams *params) { params->p = p; params->q = BigInteger(0); params->g = g; return true; } class DLGroupMaker : public QThread { Q_OBJECT public: DLGroupSet set; bool ok; DLParams params; DLGroupMaker(DLGroupSet _set) { set = _set; } ~DLGroupMaker() { wait(); } virtual void run() { if(set == DSA_512) ok = make_dlgroup(decode_seed(JCE_512_SEED), 512, JCE_512_COUNTER, ¶ms); else if(set == DSA_768) ok = make_dlgroup(decode_seed(JCE_768_SEED), 768, JCE_768_COUNTER, ¶ms); else if(set == DSA_1024) ok = make_dlgroup(decode_seed(JCE_1024_SEED), 1024, JCE_1024_COUNTER, ¶ms); else if(set == IETF_1024) ok = get_dlgroup(decode(IETF_1024_PRIME), 2, ¶ms); else if(set == IETF_2048) ok = get_dlgroup(decode(IETF_2048_PRIME), 2, ¶ms); else if(set == IETF_4096) ok = get_dlgroup(decode(IETF_4096_PRIME), 2, ¶ms); else ok = false; } }; class MyDLGroup : public DLGroupContext { Q_OBJECT public: DLGroupMaker *gm; bool wasBlocking; DLParams params; bool empty; MyDLGroup(Provider *p) : DLGroupContext(p) { gm = 0; empty = true; } MyDLGroup(const MyDLGroup &from) : DLGroupContext(from.provider()) { gm = 0; empty = true; } ~MyDLGroup() { delete gm; } virtual Provider::Context *clone() const { return new MyDLGroup(*this); } virtual QList supportedGroupSets() const { QList list; list += DSA_512; list += DSA_768; list += DSA_1024; list += IETF_1024; list += IETF_2048; list += IETF_4096; return list; } virtual bool isNull() const { return empty; } virtual void fetchGroup(DLGroupSet set, bool block) { params = DLParams(); empty = true; gm = new DLGroupMaker(set); wasBlocking = block; if(block) { gm->run(); gm_finished(); } else { connect(gm, SIGNAL(finished()), SLOT(gm_finished())); gm->start(); } } virtual void getResult(BigInteger *p, BigInteger *q, BigInteger *g) const { *p = params.p; *q = params.q; *g = params.g; } private slots: void gm_finished() { bool ok = gm->ok; if(ok) { params = gm->params; empty = false; } if(wasBlocking) delete gm; else gm->deleteLater(); gm = 0; if(!wasBlocking) emit finished(); } }; //---------------------------------------------------------------------------- // RSAKey //---------------------------------------------------------------------------- class RSAKeyMaker : public QThread { Q_OBJECT public: RSA *result; int bits, exp; RSAKeyMaker(int _bits, int _exp, QObject *parent = 0) : QThread(parent), result(0), bits(_bits), exp(_exp) { } ~RSAKeyMaker() { wait(); if(result) RSA_free(result); } virtual void run() { RSA *rsa = RSA_generate_key(bits, exp, NULL, NULL); if(!rsa) return; result = rsa; } RSA *takeResult() { RSA *rsa = result; result = 0; return rsa; } }; class RSAKey : public RSAContext { Q_OBJECT public: EVPKey evp; RSAKeyMaker *keymaker; bool wasBlocking; bool sec; RSAKey(Provider *p) : RSAContext(p) { keymaker = 0; sec = false; } RSAKey(const RSAKey &from) : RSAContext(from.provider()), evp(from.evp) { keymaker = 0; sec = from.sec; } ~RSAKey() { delete keymaker; } virtual Provider::Context *clone() const { return new RSAKey(*this); } virtual bool isNull() const { return (evp.pkey ? false: true); } virtual PKey::Type type() const { return PKey::RSA; } virtual bool isPrivate() const { return sec; } virtual bool canExport() const { return true; } virtual void convertToPublic() { if(!sec) return; // extract the public key into DER format int len = i2d_RSAPublicKey(evp.pkey->pkey.rsa, NULL); SecureArray result(len); unsigned char *p = (unsigned char *)result.data(); i2d_RSAPublicKey(evp.pkey->pkey.rsa, &p); p = (unsigned char *)result.data(); // put the DER public key back into openssl evp.reset(); RSA *rsa; #ifdef OSSL_097 rsa = d2i_RSAPublicKey(NULL, (const unsigned char **)&p, result.size()); #else rsa = d2i_RSAPublicKey(NULL, (unsigned char **)&p, result.size()); #endif evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(evp.pkey, rsa); sec = false; } virtual int bits() const { return EVP_PKEY_bits(evp.pkey); } virtual int maximumEncryptSize(EncryptionAlgorithm alg) const { RSA *rsa = evp.pkey->pkey.rsa; if(alg == EME_PKCS1v15) return RSA_size(rsa) - 11 - 1; else // oaep return RSA_size(rsa) - 41 - 1; } virtual SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) { RSA *rsa = evp.pkey->pkey.rsa; SecureArray buf = in; int max = maximumEncryptSize(alg); if(buf.size() > max) buf.resize(max); SecureArray result(RSA_size(rsa)); int pad; if(alg == EME_PKCS1v15) pad = RSA_PKCS1_PADDING; else // oaep pad = RSA_PKCS1_OAEP_PADDING; int ret = RSA_public_encrypt(buf.size(), (unsigned char *)buf.data(), (unsigned char *)result.data(), rsa, pad); if(ret < 0) return SecureArray(); result.resize(ret); return result; } virtual bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) { RSA *rsa = evp.pkey->pkey.rsa; SecureArray result(RSA_size(rsa)); int pad; if(alg == EME_PKCS1v15) pad = RSA_PKCS1_PADDING; else // oaep pad = RSA_PKCS1_OAEP_PADDING; int ret = RSA_private_decrypt(in.size(), (unsigned char *)in.data(), (unsigned char *)result.data(), rsa, pad); if(ret < 0) return false; result.resize(ret); *out = result; return true; } virtual void startSign(SignatureAlgorithm alg, SignatureFormat) { const EVP_MD *md = 0; if(alg == EMSA3_SHA1) md = EVP_sha1(); else if(alg == EMSA3_MD5) md = EVP_md5(); else if(alg == EMSA3_MD2) md = EVP_md2(); else if(alg == EMSA3_RIPEMD160) md = EVP_ripemd160(); else if(alg == EMSA3_Raw) { // md = 0 } evp.startSign(md); } virtual void startVerify(SignatureAlgorithm alg, SignatureFormat) { const EVP_MD *md = 0; if(alg == EMSA3_SHA1) md = EVP_sha1(); else if(alg == EMSA3_MD5) md = EVP_md5(); else if(alg == EMSA3_MD2) md = EVP_md2(); else if(alg == EMSA3_RIPEMD160) md = EVP_ripemd160(); else if(alg == EMSA3_Raw) { // md = 0 } evp.startVerify(md); } virtual void update(const MemoryRegion &in) { evp.update(in); } virtual QByteArray endSign() { return evp.endSign().toByteArray(); } virtual bool endVerify(const QByteArray &sig) { return evp.endVerify(sig); } virtual void createPrivate(int bits, int exp, bool block) { evp.reset(); keymaker = new RSAKeyMaker(bits, exp, !block ? this : 0); wasBlocking = block; if(block) { keymaker->run(); km_finished(); } else { connect(keymaker, SIGNAL(finished()), SLOT(km_finished())); keymaker->start(); } } virtual void createPrivate(const BigInteger &n, const BigInteger &e, const BigInteger &p, const BigInteger &q, const BigInteger &d) { evp.reset(); RSA *rsa = RSA_new(); rsa->n = bi2bn(n); rsa->e = bi2bn(e); rsa->p = bi2bn(p); rsa->q = bi2bn(q); rsa->d = bi2bn(d); if(!rsa->n || !rsa->e || !rsa->p || !rsa->q || !rsa->d) { RSA_free(rsa); return; } evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(evp.pkey, rsa); sec = true; } virtual void createPublic(const BigInteger &n, const BigInteger &e) { evp.reset(); RSA *rsa = RSA_new(); rsa->n = bi2bn(n); rsa->e = bi2bn(e); if(!rsa->n || !rsa->e) { RSA_free(rsa); return; } evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(evp.pkey, rsa); sec = false; } virtual BigInteger n() const { return bn2bi(evp.pkey->pkey.rsa->n); } virtual BigInteger e() const { return bn2bi(evp.pkey->pkey.rsa->e); } virtual BigInteger p() const { return bn2bi(evp.pkey->pkey.rsa->p); } virtual BigInteger q() const { return bn2bi(evp.pkey->pkey.rsa->q); } virtual BigInteger d() const { return bn2bi(evp.pkey->pkey.rsa->d); } private slots: void km_finished() { RSA *rsa = keymaker->takeResult(); if(wasBlocking) delete keymaker; else keymaker->deleteLater(); keymaker = 0; if(rsa) { evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(evp.pkey, rsa); sec = true; } if(!wasBlocking) emit finished(); } }; //---------------------------------------------------------------------------- // DSAKey //---------------------------------------------------------------------------- class DSAKeyMaker : public QThread { Q_OBJECT public: DLGroup domain; DSA *result; DSAKeyMaker(const DLGroup &_domain, QObject *parent = 0) : QThread(parent), domain(_domain), result(0) { } ~DSAKeyMaker() { wait(); if(result) DSA_free(result); } virtual void run() { DSA *dsa = DSA_new(); dsa->p = bi2bn(domain.p()); dsa->q = bi2bn(domain.q()); dsa->g = bi2bn(domain.g()); if(!DSA_generate_key(dsa)) { DSA_free(dsa); return; } result = dsa; } DSA *takeResult() { DSA *dsa = result; result = 0; return dsa; } }; // note: DSA doesn't use SignatureAlgorithm, since EMSA1 is always assumed class DSAKey : public DSAContext { Q_OBJECT public: EVPKey evp; DSAKeyMaker *keymaker; bool wasBlocking; bool transformsig; bool sec; DSAKey(Provider *p) : DSAContext(p) { keymaker = 0; sec = false; } DSAKey(const DSAKey &from) : DSAContext(from.provider()), evp(from.evp) { keymaker = 0; sec = from.sec; } ~DSAKey() { delete keymaker; } virtual Provider::Context *clone() const { return new DSAKey(*this); } virtual bool isNull() const { return (evp.pkey ? false: true); } virtual PKey::Type type() const { return PKey::DSA; } virtual bool isPrivate() const { return sec; } virtual bool canExport() const { return true; } virtual void convertToPublic() { if(!sec) return; // extract the public key into DER format int len = i2d_DSAPublicKey(evp.pkey->pkey.dsa, NULL); SecureArray result(len); unsigned char *p = (unsigned char *)result.data(); i2d_DSAPublicKey(evp.pkey->pkey.dsa, &p); p = (unsigned char *)result.data(); // put the DER public key back into openssl evp.reset(); DSA *dsa; #ifdef OSSL_097 dsa = d2i_DSAPublicKey(NULL, (const unsigned char **)&p, result.size()); #else dsa = d2i_DSAPublicKey(NULL, (unsigned char **)&p, result.size()); #endif evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DSA(evp.pkey, dsa); sec = false; } virtual int bits() const { return EVP_PKEY_bits(evp.pkey); } virtual void startSign(SignatureAlgorithm, SignatureFormat format) { // openssl native format is DER, so transform otherwise if(format != DERSequence) transformsig = true; else transformsig = false; evp.startSign(EVP_dss1()); } virtual void startVerify(SignatureAlgorithm, SignatureFormat format) { // openssl native format is DER, so transform otherwise if(format != DERSequence) transformsig = true; else transformsig = false; evp.startVerify(EVP_dss1()); } virtual void update(const MemoryRegion &in) { evp.update(in); } virtual QByteArray endSign() { SecureArray out = evp.endSign(); if(transformsig) return dsasig_der_to_raw(out).toByteArray(); else return out.toByteArray(); } virtual bool endVerify(const QByteArray &sig) { SecureArray in; if(transformsig) in = dsasig_raw_to_der(sig); else in = sig; return evp.endVerify(in); } virtual void createPrivate(const DLGroup &domain, bool block) { evp.reset(); keymaker = new DSAKeyMaker(domain, !block ? this : 0); wasBlocking = block; if(block) { keymaker->run(); km_finished(); } else { connect(keymaker, SIGNAL(finished()), SLOT(km_finished())); keymaker->start(); } } virtual void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) { evp.reset(); DSA *dsa = DSA_new(); dsa->p = bi2bn(domain.p()); dsa->q = bi2bn(domain.q()); dsa->g = bi2bn(domain.g()); dsa->pub_key = bi2bn(y); dsa->priv_key = bi2bn(x); if(!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key || !dsa->priv_key) { DSA_free(dsa); return; } evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DSA(evp.pkey, dsa); sec = true; } virtual void createPublic(const DLGroup &domain, const BigInteger &y) { evp.reset(); DSA *dsa = DSA_new(); dsa->p = bi2bn(domain.p()); dsa->q = bi2bn(domain.q()); dsa->g = bi2bn(domain.g()); dsa->pub_key = bi2bn(y); if(!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key) { DSA_free(dsa); return; } evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DSA(evp.pkey, dsa); sec = false; } virtual DLGroup domain() const { return DLGroup(bn2bi(evp.pkey->pkey.dsa->p), bn2bi(evp.pkey->pkey.dsa->q), bn2bi(evp.pkey->pkey.dsa->g)); } virtual BigInteger y() const { return bn2bi(evp.pkey->pkey.dsa->pub_key); } virtual BigInteger x() const { return bn2bi(evp.pkey->pkey.dsa->priv_key); } private slots: void km_finished() { DSA *dsa = keymaker->takeResult(); if(wasBlocking) delete keymaker; else keymaker->deleteLater(); keymaker = 0; if(dsa) { evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DSA(evp.pkey, dsa); sec = true; } if(!wasBlocking) emit finished(); } }; //---------------------------------------------------------------------------- // DHKey //---------------------------------------------------------------------------- class DHKeyMaker : public QThread { Q_OBJECT public: DLGroup domain; DH *result; DHKeyMaker(const DLGroup &_domain, QObject *parent = 0) : QThread(parent), domain(_domain), result(0) { } ~DHKeyMaker() { wait(); if(result) DH_free(result); } virtual void run() { DH *dh = DH_new(); dh->p = bi2bn(domain.p()); dh->g = bi2bn(domain.g()); if(!DH_generate_key(dh)) { DH_free(dh); return; } result = dh; } DH *takeResult() { DH *dh = result; result = 0; return dh; } }; class DHKey : public DHContext { Q_OBJECT public: EVPKey evp; DHKeyMaker *keymaker; bool wasBlocking; bool sec; DHKey(Provider *p) : DHContext(p) { keymaker = 0; sec = false; } DHKey(const DHKey &from) : DHContext(from.provider()), evp(from.evp) { keymaker = 0; sec = from.sec; } ~DHKey() { delete keymaker; } virtual Provider::Context *clone() const { return new DHKey(*this); } virtual bool isNull() const { return (evp.pkey ? false: true); } virtual PKey::Type type() const { return PKey::DH; } virtual bool isPrivate() const { return sec; } virtual bool canExport() const { return true; } virtual void convertToPublic() { if(!sec) return; DH *orig = evp.pkey->pkey.dh; DH *dh = DH_new(); dh->p = BN_dup(orig->p); dh->g = BN_dup(orig->g); dh->pub_key = BN_dup(orig->pub_key); evp.reset(); evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DH(evp.pkey, dh); sec = false; } virtual int bits() const { return EVP_PKEY_bits(evp.pkey); } virtual SymmetricKey deriveKey(const PKeyBase &theirs) { DH *dh = evp.pkey->pkey.dh; DH *them = static_cast(&theirs)->evp.pkey->pkey.dh; SecureArray result(DH_size(dh)); int ret = DH_compute_key((unsigned char *)result.data(), them->pub_key, dh); if(ret <= 0) return SymmetricKey(); result.resize(ret); return SymmetricKey(result); } virtual void createPrivate(const DLGroup &domain, bool block) { evp.reset(); keymaker = new DHKeyMaker(domain, !block ? this : 0); wasBlocking = block; if(block) { keymaker->run(); km_finished(); } else { connect(keymaker, SIGNAL(finished()), SLOT(km_finished())); keymaker->start(); } } virtual void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) { evp.reset(); DH *dh = DH_new(); dh->p = bi2bn(domain.p()); dh->g = bi2bn(domain.g()); dh->pub_key = bi2bn(y); dh->priv_key = bi2bn(x); if(!dh->p || !dh->g || !dh->pub_key || !dh->priv_key) { DH_free(dh); return; } evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DH(evp.pkey, dh); sec = true; } virtual void createPublic(const DLGroup &domain, const BigInteger &y) { evp.reset(); DH *dh = DH_new(); dh->p = bi2bn(domain.p()); dh->g = bi2bn(domain.g()); dh->pub_key = bi2bn(y); if(!dh->p || !dh->g || !dh->pub_key) { DH_free(dh); return; } evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DH(evp.pkey, dh); sec = false; } virtual DLGroup domain() const { return DLGroup(bn2bi(evp.pkey->pkey.dh->p), bn2bi(evp.pkey->pkey.dh->g)); } virtual BigInteger y() const { return bn2bi(evp.pkey->pkey.dh->pub_key); } virtual BigInteger x() const { return bn2bi(evp.pkey->pkey.dh->priv_key); } private slots: void km_finished() { DH *dh = keymaker->takeResult(); if(wasBlocking) delete keymaker; else keymaker->deleteLater(); keymaker = 0; if(dh) { evp.pkey = EVP_PKEY_new(); EVP_PKEY_assign_DH(evp.pkey, dh); sec = true; } if(!wasBlocking) emit finished(); } }; //---------------------------------------------------------------------------- // QCA-based RSA_METHOD //---------------------------------------------------------------------------- // only supports EMSA3_Raw for now class QCA_RSA_METHOD { public: RSAPrivateKey key; QCA_RSA_METHOD(RSAPrivateKey _key, RSA *rsa) { key = _key; RSA_set_method(rsa, rsa_method()); rsa->flags |= RSA_FLAG_SIGN_VER; RSA_set_app_data(rsa, this); rsa->n = bi2bn(_key.n()); rsa->e = bi2bn(_key.e()); } RSA_METHOD *rsa_method() { static RSA_METHOD *ops = 0; if(!ops) { ops = new RSA_METHOD(*RSA_get_default_method()); ops->rsa_priv_enc = 0;//pkcs11_rsa_encrypt; ops->rsa_priv_dec = 0;//pkcs11_rsa_decrypt; ops->rsa_sign = rsa_sign; ops->rsa_verify = 0;//pkcs11_rsa_verify; ops->finish = rsa_finish; } return ops; } static int rsa_sign(int type, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, const RSA *rsa) { QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa); // TODO: this is disgusting unsigned char *p, *tmps = NULL; const unsigned char *s = NULL; int i,j; j = 0; if(type == NID_md5_sha1) { } else { // make X509 packet X509_SIG sig; ASN1_TYPE parameter; X509_ALGOR algor; ASN1_OCTET_STRING digest; int rsa_size = RSA_size(rsa); //int rsa_size = 128; //CK_ULONG sigsize = rsa_size; sig.algor= &algor; sig.algor->algorithm=OBJ_nid2obj(type); if (sig.algor->algorithm == NULL) { //RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE); return 0; } if (sig.algor->algorithm->length == 0) { //RSAerr(RSA_F_RSA_SIGN,RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD); return 0; } parameter.type=V_ASN1_NULL; parameter.value.ptr=NULL; sig.algor->parameter= ¶meter; sig.digest= &digest; sig.digest->data=(unsigned char *)m; /* TMP UGLY CAST */ sig.digest->length=m_len; i=i2d_X509_SIG(&sig,NULL); j=rsa_size; if (i > (j-RSA_PKCS1_PADDING_SIZE)) { //RSAerr(RSA_F_RSA_SIGN,RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY); return 0; } tmps=(unsigned char *)OPENSSL_malloc((unsigned int)j+1); if (tmps == NULL) { //RSAerr(RSA_F_RSA_SIGN,ERR_R_MALLOC_FAILURE); return 0; } p=tmps; i2d_X509_SIG(&sig,&p); s=tmps; m = s; m_len = i; } SecureArray input; input.resize(m_len); memcpy(input.data(), m, input.size()); SecureArray result = self->key.signMessage(input, EMSA3_Raw); if(tmps) { OPENSSL_cleanse(tmps,(unsigned int)j+1); OPENSSL_free(tmps); } // TODO: even though we return error here, PKCS7_sign will // not return error. what gives? if(result.isEmpty()) return 0; memcpy(sigret, result.data(), result.size()); *siglen = result.size(); return 1; } static int rsa_finish(RSA *rsa) { QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa); delete self; return 1; } }; static RSA *createFromExisting(const RSAPrivateKey &key) { RSA *r = RSA_new(); new QCA_RSA_METHOD(key, r); // will delete itself on RSA_free return r; } //---------------------------------------------------------------------------- // MyPKeyContext //---------------------------------------------------------------------------- class MyPKeyContext : public PKeyContext { public: PKeyBase *k; MyPKeyContext(Provider *p) : PKeyContext(p) { k = 0; } ~MyPKeyContext() { delete k; } virtual Provider::Context *clone() const { MyPKeyContext *c = new MyPKeyContext(*this); c->k = (PKeyBase *)k->clone(); return c; } virtual QList supportedTypes() const { QList list; list += PKey::RSA; list += PKey::DSA; list += PKey::DH; return list; } virtual QList supportedIOTypes() const { QList list; list += PKey::RSA; list += PKey::DSA; return list; } virtual QList supportedPBEAlgorithms() const { QList list; list += PBES2_DES_SHA1; list += PBES2_TripleDES_SHA1; return list; } virtual PKeyBase *key() { return k; } virtual const PKeyBase *key() const { return k; } virtual void setKey(PKeyBase *key) { k = key; } virtual bool importKey(const PKeyBase *key) { Q_UNUSED(key); return false; } EVP_PKEY *get_pkey() const { PKey::Type t = k->type(); if(t == PKey::RSA) return static_cast(k)->evp.pkey; else if(t == PKey::DSA) return static_cast(k)->evp.pkey; else return static_cast(k)->evp.pkey; } PKeyBase *pkeyToBase(EVP_PKEY *pkey, bool sec) const { PKeyBase *nk = 0; if(pkey->type == EVP_PKEY_RSA) { RSAKey *c = new RSAKey(provider()); c->evp.pkey = pkey; c->sec = sec; nk = c; } else if(pkey->type == EVP_PKEY_DSA) { DSAKey *c = new DSAKey(provider()); c->evp.pkey = pkey; c->sec = sec; nk = c; } else if(pkey->type == EVP_PKEY_DH) { DHKey *c = new DHKey(provider()); c->evp.pkey = pkey; c->sec = sec; nk = c; } else { EVP_PKEY_free(pkey); } return nk; } virtual QByteArray publicToDER() const { EVP_PKEY *pkey = get_pkey(); // OpenSSL does not have DH import/export support if(pkey->type == EVP_PKEY_DH) return QByteArray(); BIO *bo = BIO_new(BIO_s_mem()); i2d_PUBKEY_bio(bo, pkey); QByteArray buf = bio2ba(bo); return buf; } virtual QString publicToPEM() const { EVP_PKEY *pkey = get_pkey(); // OpenSSL does not have DH import/export support if(pkey->type == EVP_PKEY_DH) return QString(); BIO *bo = BIO_new(BIO_s_mem()); PEM_write_bio_PUBKEY(bo, pkey); QByteArray buf = bio2ba(bo); return QString::fromLatin1(buf); } virtual ConvertResult publicFromDER(const QByteArray &in) { delete k; k = 0; BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); EVP_PKEY *pkey = d2i_PUBKEY_bio(bi, NULL); BIO_free(bi); if(!pkey) return ErrorDecode; k = pkeyToBase(pkey, false); if(k) return ConvertGood; else return ErrorDecode; } virtual ConvertResult publicFromPEM(const QString &s) { delete k; k = 0; QByteArray in = s.toLatin1(); BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bi, NULL, passphrase_cb, NULL); BIO_free(bi); if(!pkey) return ErrorDecode; k = pkeyToBase(pkey, false); if(k) return ConvertGood; else return ErrorDecode; } virtual SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const { //if(pbe == PBEDefault) // pbe = PBES2_TripleDES_SHA1; const EVP_CIPHER *cipher = 0; if(pbe == PBES2_TripleDES_SHA1) cipher = EVP_des_ede3_cbc(); else if(pbe == PBES2_DES_SHA1) cipher = EVP_des_cbc(); if(!cipher) return SecureArray(); EVP_PKEY *pkey = get_pkey(); // OpenSSL does not have DH import/export support if(pkey->type == EVP_PKEY_DH) return SecureArray(); BIO *bo = BIO_new(BIO_s_mem()); if(!passphrase.isEmpty()) i2d_PKCS8PrivateKey_bio(bo, pkey, cipher, NULL, 0, NULL, (void *)passphrase.data()); else i2d_PKCS8PrivateKey_bio(bo, pkey, NULL, NULL, 0, NULL, NULL); SecureArray buf = bio2buf(bo); return buf; } virtual QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const { //if(pbe == PBEDefault) // pbe = PBES2_TripleDES_SHA1; const EVP_CIPHER *cipher = 0; if(pbe == PBES2_TripleDES_SHA1) cipher = EVP_des_ede3_cbc(); else if(pbe == PBES2_DES_SHA1) cipher = EVP_des_cbc(); if(!cipher) return QString(); EVP_PKEY *pkey = get_pkey(); // OpenSSL does not have DH import/export support if(pkey->type == EVP_PKEY_DH) return QString(); BIO *bo = BIO_new(BIO_s_mem()); if(!passphrase.isEmpty()) PEM_write_bio_PKCS8PrivateKey(bo, pkey, cipher, NULL, 0, NULL, (void *)passphrase.data()); else PEM_write_bio_PKCS8PrivateKey(bo, pkey, NULL, NULL, 0, NULL, NULL); SecureArray buf = bio2buf(bo); return QString::fromLatin1(buf.toByteArray()); } virtual ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) { delete k; k = 0; EVP_PKEY *pkey; if(!passphrase.isEmpty()) pkey = qca_d2i_PKCS8PrivateKey(in, NULL, NULL, (void *)passphrase.data()); else pkey = qca_d2i_PKCS8PrivateKey(in, NULL, passphrase_cb, NULL); if(!pkey) return ErrorDecode; k = pkeyToBase(pkey, true); if(k) return ConvertGood; else return ErrorDecode; } virtual ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) { delete k; k = 0; QByteArray in = s.toLatin1(); BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); EVP_PKEY *pkey; if(!passphrase.isEmpty()) pkey = PEM_read_bio_PrivateKey(bi, NULL, NULL, (void *)passphrase.data()); else pkey = PEM_read_bio_PrivateKey(bi, NULL, passphrase_cb, NULL); BIO_free(bi); if(!pkey) return ErrorDecode; k = pkeyToBase(pkey, true); if(k) return ConvertGood; else return ErrorDecode; } }; //---------------------------------------------------------------------------- // MyCertContext //---------------------------------------------------------------------------- class X509Item { public: X509 *cert; X509_REQ *req; X509_CRL *crl; enum Type { TypeCert, TypeReq, TypeCRL }; X509Item() { cert = 0; req = 0; crl = 0; } X509Item(const X509Item &from) { cert = 0; req = 0; crl = 0; *this = from; } ~X509Item() { reset(); } X509Item & operator=(const X509Item &from) { if(this != &from) { reset(); cert = from.cert; req = from.req; crl = from.crl; if(cert) CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); if(req) CRYPTO_add(&req->references, 1, CRYPTO_LOCK_X509_REQ); if(crl) CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL); } return *this; } void reset() { if(cert) { X509_free(cert); cert = 0; } if(req) { X509_REQ_free(req); req = 0; } if(crl) { X509_CRL_free(crl); crl = 0; } } bool isNull() const { return (!cert && !req && !crl); } QByteArray toDER() const { BIO *bo = BIO_new(BIO_s_mem()); if(cert) i2d_X509_bio(bo, cert); else if(req) i2d_X509_REQ_bio(bo, req); else if(crl) i2d_X509_CRL_bio(bo, crl); QByteArray buf = bio2ba(bo); return buf; } QString toPEM() const { BIO *bo = BIO_new(BIO_s_mem()); if(cert) PEM_write_bio_X509(bo, cert); else if(req) PEM_write_bio_X509_REQ(bo, req); else if(crl) PEM_write_bio_X509_CRL(bo, crl); QByteArray buf = bio2ba(bo); return QString::fromLatin1(buf); } ConvertResult fromDER(const QByteArray &in, Type t) { reset(); BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); if(t == TypeCert) cert = d2i_X509_bio(bi, NULL); else if(t == TypeReq) req = d2i_X509_REQ_bio(bi, NULL); else if(t == TypeCRL) crl = d2i_X509_CRL_bio(bi, NULL); BIO_free(bi); if(isNull()) return ErrorDecode; return ConvertGood; } ConvertResult fromPEM(const QString &s, Type t) { reset(); QByteArray in = s.toLatin1(); BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); if(t == TypeCert) cert = PEM_read_bio_X509(bi, NULL, passphrase_cb, NULL); else if(t == TypeReq) req = PEM_read_bio_X509_REQ(bi, NULL, passphrase_cb, NULL); else if(t == TypeCRL) crl = PEM_read_bio_X509_CRL(bi, NULL, passphrase_cb, NULL); BIO_free(bi); if(isNull()) return ErrorDecode; return ConvertGood; } }; // (taken from kdelibs) -- Justin // // This code is mostly taken from OpenSSL v0.9.5a // by Eric Young QDateTime ASN1_UTCTIME_QDateTime(ASN1_UTCTIME *tm, int *isGmt) { QDateTime qdt; char *v; int gmt=0; int i; int y=0,M=0,d=0,h=0,m=0,s=0; QDate qdate; QTime qtime; i = tm->length; v = (char *)tm->data; if (i < 10) goto auq_err; if (v[i-1] == 'Z') gmt=1; for (i=0; i<10; i++) if ((v[i] > '9') || (v[i] < '0')) goto auq_err; y = (v[0]-'0')*10+(v[1]-'0'); if (y < 50) y+=100; M = (v[2]-'0')*10+(v[3]-'0'); if ((M > 12) || (M < 1)) goto auq_err; d = (v[4]-'0')*10+(v[5]-'0'); h = (v[6]-'0')*10+(v[7]-'0'); m = (v[8]-'0')*10+(v[9]-'0'); if ( (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) s = (v[10]-'0')*10+(v[11]-'0'); // localize the date and display it. qdate.setYMD(y+1900, M, d); qtime.setHMS(h,m,s); qdt.setDate(qdate); qdt.setTime(qtime); auq_err: if (isGmt) *isGmt = gmt; return qdt; } class MyCertContext; static bool sameChain(STACK_OF(X509) *ossl, const QList &qca); // TODO: support read/write of multiple info values with the same name class MyCertContext : public CertContext { public: X509Item item; CertContextProps _props; MyCertContext(Provider *p) : CertContext(p) { //printf("[%p] ** created\n", this); } MyCertContext(const MyCertContext &from) : CertContext(from), item(from.item), _props(from._props) { //printf("[%p] ** created as copy (from [%p])\n", this, &from); } ~MyCertContext() { //printf("[%p] ** deleted\n", this); } virtual Provider::Context *clone() const { return new MyCertContext(*this); } virtual QByteArray toDER() const { return item.toDER(); } virtual QString toPEM() const { return item.toPEM(); } virtual ConvertResult fromDER(const QByteArray &a) { _props = CertContextProps(); ConvertResult r = item.fromDER(a, X509Item::TypeCert); if(r == ConvertGood) make_props(); return r; } virtual ConvertResult fromPEM(const QString &s) { _props = CertContextProps(); ConvertResult r = item.fromPEM(s, X509Item::TypeCert); if(r == ConvertGood) make_props(); return r; } void fromX509(X509 *x) { CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); item.cert = x; make_props(); } virtual bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv) { _props = CertContextProps(); item.reset(); CertificateInfo info = opts.info(); // Note: removing default constraints, let the app choose these if it wants Constraints constraints = opts.constraints(); // constraints - logic from Botan /*Constraints constraints; if(opts.isCA()) { constraints += KeyCertificateSign; constraints += CRLSign; } else constraints = find_constraints(priv, opts.constraints());*/ EVP_PKEY *pk = static_cast(&priv)->get_pkey(); X509_EXTENSION *ex; const EVP_MD *md; if(priv.key()->type() == PKey::RSA) md = EVP_sha1(); else if(priv.key()->type() == PKey::DSA) md = EVP_dss1(); else return false; // create X509 *x = X509_new(); X509_set_version(x, 2); // serial BIGNUM *bn = bi2bn(opts.serialNumber()); BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(x)); BN_free(bn); // validity period ASN1_TIME_set(X509_get_notBefore(x), opts.notValidBefore().toTime_t()); ASN1_TIME_set(X509_get_notAfter(x), opts.notValidAfter().toTime_t()); // public key X509_set_pubkey(x, pk); // subject X509_NAME *name = new_cert_name(info); X509_set_subject_name(x, name); // issuer == subject X509_set_issuer_name(x, name); // subject key id ex = new_subject_key_id(x); { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // CA mode ex = new_basic_constraints(opts.isCA(), opts.pathLimit()); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // subject alt name ex = new_cert_subject_alt_name(info); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // key usage ex = new_cert_key_usage(constraints); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // extended key usage ex = new_cert_ext_key_usage(constraints); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // policies ex = new_cert_policies(opts.policies()); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // finished X509_sign(x, pk, md); item.cert = x; make_props(); return true; } virtual const CertContextProps *props() const { //printf("[%p] grabbing props\n", this); return &_props; } virtual bool compare(const CertContext *other) const { const CertContextProps *a = &_props; const CertContextProps *b = other->props(); PublicKey akey, bkey; PKeyContext *ac = subjectPublicKey(); akey.change(ac); PKeyContext *bc = other->subjectPublicKey(); bkey.change(bc); // logic from Botan if(a->sig != b->sig || a->sigalgo != b->sigalgo || akey != bkey) return false; if(a->issuer != b->issuer || a->subject != b->subject) return false; if(a->serial != b->serial || a->version != b->version) return false; if(a->start != b->start || a->end != b->end) return false; return true; } // does a new virtual PKeyContext *subjectPublicKey() const { MyPKeyContext *kc = new MyPKeyContext(provider()); EVP_PKEY *pkey = X509_get_pubkey(item.cert); PKeyBase *kb = kc->pkeyToBase(pkey, false); kc->setKey(kb); return kc; } virtual bool isIssuerOf(const CertContext *other) const { // to check a single issuer, we make a list of 1 STACK_OF(X509) *untrusted_list = sk_X509_new_null(); const MyCertContext *our_cc = this; X509 *x = our_cc->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(untrusted_list, x); const MyCertContext *other_cc = static_cast(other); X509 *ox = other_cc->item.cert; X509_STORE *store = X509_STORE_new(); X509_STORE_CTX *ctx = X509_STORE_CTX_new(); X509_STORE_CTX_init(ctx, store, ox, untrusted_list); // we don't care about the verify result here X509_verify_cert(ctx); // grab the chain, which may not be fully populated STACK_OF(X509) *chain = X509_STORE_CTX_get_chain(ctx); bool ok = false; // chain should be exactly 2 items QList expected; expected += other_cc; expected += our_cc; if(chain && sameChain(chain, expected)) ok = true; // cleanup X509_STORE_CTX_free(ctx); X509_STORE_free(store); sk_X509_pop_free(untrusted_list, X509_free); return ok; } // implemented later because it depends on MyCRLContext virtual Validity validate(const QList &trusted, const QList &untrusted, const QList &crls, UsageMode u, ValidateFlags vf) const; virtual Validity validate_chain(const QList &chain, const QList &trusted, const QList &crls, UsageMode u, ValidateFlags vf) const; void make_props() { X509 *x = item.cert; CertContextProps p; p.version = X509_get_version(x); ASN1_INTEGER *ai = X509_get_serialNumber(x); if(ai) { char *rep = i2s_ASN1_INTEGER(NULL, ai); QString str = rep; OPENSSL_free(rep); p.serial.fromString(str); } p.start = ASN1_UTCTIME_QDateTime(X509_get_notBefore(x), NULL); p.end = ASN1_UTCTIME_QDateTime(X509_get_notAfter(x), NULL); CertificateInfo subject, issuer; subject = get_cert_name(X509_get_subject_name(x)); issuer = get_cert_name(X509_get_issuer_name(x)); p.isSelfSigned = ( X509_V_OK == X509_check_issued( x, x ) ); p.isCA = false; p.pathLimit = 0; int pos = X509_get_ext_by_NID(x, NID_basic_constraints, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) get_basic_constraints(ex, &p.isCA, &p.pathLimit); } pos = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) subject.unite(get_cert_alt_name(ex)); } pos = X509_get_ext_by_NID(x, NID_issuer_alt_name, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) issuer.unite(get_cert_alt_name(ex)); } pos = X509_get_ext_by_NID(x, NID_key_usage, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) p.constraints = get_cert_key_usage(ex); } pos = X509_get_ext_by_NID(x, NID_ext_key_usage, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) p.constraints += get_cert_ext_key_usage(ex); } pos = X509_get_ext_by_NID(x, NID_certificate_policies, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) p.policies = get_cert_policies(ex); } if (x->signature) { p.sig = QByteArray(x->signature->length, 0); for (int i=0; i< x->signature->length; i++) p.sig[i] = x->signature->data[i]; } switch( OBJ_obj2nid(x->cert_info->signature->algorithm) ) { case NID_sha1WithRSAEncryption: p.sigalgo = QCA::EMSA3_SHA1; break; case NID_md5WithRSAEncryption: p.sigalgo = QCA::EMSA3_MD5; break; case NID_md2WithRSAEncryption: p.sigalgo = QCA::EMSA3_MD2; break; case NID_ripemd160WithRSA: p.sigalgo = QCA::EMSA3_RIPEMD160; break; case NID_dsaWithSHA1: p.sigalgo = QCA::EMSA1_SHA1; break; default: qDebug() << "Unknown signature value: " << OBJ_obj2nid(x->cert_info->signature->algorithm); p.sigalgo = QCA::SignatureUnknown; } pos = X509_get_ext_by_NID(x, NID_subject_key_identifier, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) p.subjectId += get_cert_subject_key_id(ex); } pos = X509_get_ext_by_NID(x, NID_authority_key_identifier, -1); if(pos != -1) { X509_EXTENSION *ex = X509_get_ext(x, pos); if(ex) p.issuerId += get_cert_issuer_key_id(ex); } // FIXME: super hack CertificateOptions opts; opts.setInfo(subject); p.subject = opts.infoOrdered(); opts.setInfo(issuer); p.issuer = opts.infoOrdered(); _props = p; //printf("[%p] made props: [%s]\n", this, _props.subject[CommonName].toLatin1().data()); } }; bool sameChain(STACK_OF(X509) *ossl, const QList &qca) { if(sk_X509_num(ossl) != qca.count()) return false; for(int n = 0; n < sk_X509_num(ossl); ++n) { X509 *a = sk_X509_value(ossl, n); X509 *b = qca[n]->item.cert; if(X509_cmp(a, b) != 0) return false; } return true; } //---------------------------------------------------------------------------- // MyCAContext //---------------------------------------------------------------------------- // Thanks to Pascal Patry class MyCAContext : public CAContext { public: X509Item caCert; MyPKeyContext *privateKey; MyCAContext(Provider *p) : CAContext(p) { privateKey = 0; } MyCAContext(const MyCAContext &from) : CAContext(from), caCert(from.caCert) { privateKey = static_cast(from.privateKey -> clone()); } ~MyCAContext() { delete privateKey; } virtual CertContext *certificate() const { MyCertContext *cert = new MyCertContext(provider()); cert->fromX509(caCert.cert); return cert; } virtual CertContext *createCertificate(const PKeyContext &pub, const CertificateOptions &opts) const { // TODO: implement Q_UNUSED(pub) Q_UNUSED(opts) return 0; } virtual CRLContext *createCRL(const QDateTime &nextUpdate) const { // TODO: implement Q_UNUSED(nextUpdate) return 0; } virtual void setup(const CertContext &cert, const PKeyContext &priv) { caCert = static_cast(cert).item; delete privateKey; privateKey = 0; privateKey = static_cast(priv.clone()); } virtual CertContext *signRequest(const CSRContext &req, const QDateTime ¬ValidAfter) const { MyCertContext *cert = 0; const EVP_MD *md = 0; X509 *x = 0; const CertContextProps &props = *req.props(); CertificateOptions subjectOpts; X509_NAME *subjectName = 0; X509_EXTENSION *ex = 0; if(privateKey -> key()->type() == PKey::RSA) md = EVP_sha1(); else if(privateKey -> key()->type() == PKey::DSA) md = EVP_dss1(); else return 0; cert = new MyCertContext(provider()); subjectOpts.setInfoOrdered(props.subject); subjectName = new_cert_name(subjectOpts.info()); // create x = X509_new(); X509_set_version(x, 2); // serial BIGNUM *bn = bi2bn(props.serial); BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(x)); BN_free(bn); // validity period ASN1_TIME_set(X509_get_notBefore(x), QDateTime::currentDateTime().toUTC().toTime_t()); ASN1_TIME_set(X509_get_notAfter(x), notValidAfter.toTime_t()); X509_set_pubkey(x, static_cast(req.subjectPublicKey()) -> get_pkey()); X509_set_subject_name(x, subjectName); X509_set_issuer_name(x, X509_get_subject_name(caCert.cert)); // subject key id ex = new_subject_key_id(x); { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // CA mode ex = new_basic_constraints(props.isCA, props.pathLimit); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // subject alt name ex = new_cert_subject_alt_name(subjectOpts.info()); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // key usage ex = new_cert_key_usage(props.constraints); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // extended key usage ex = new_cert_ext_key_usage(props.constraints); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } // policies ex = new_cert_policies(props.policies); if(ex) { X509_add_ext(x, ex, -1); X509_EXTENSION_free(ex); } if(!X509_sign(x, privateKey->get_pkey(), md)) { X509_free(x); delete cert; return 0; } cert->fromX509(x); X509_free(x); return cert; } virtual CRLContext *updateCRL(const CRLContext &crl, const QList &entries, const QDateTime &nextUpdate) const { // TODO: implement Q_UNUSED(crl) Q_UNUSED(entries) Q_UNUSED(nextUpdate) return 0; } virtual Provider::Context *clone() const { return new MyCAContext(*this); } }; //---------------------------------------------------------------------------- // MyCSRContext //---------------------------------------------------------------------------- class MyCSRContext : public CSRContext { public: X509Item item; CertContextProps _props; MyCSRContext(Provider *p) : CSRContext(p) { } MyCSRContext(const MyCSRContext &from) : CSRContext(from), item(from.item), _props(from._props) { } virtual Provider::Context *clone() const { return new MyCSRContext(*this); } virtual QByteArray toDER() const { return item.toDER(); } virtual QString toPEM() const { return item.toPEM(); } virtual ConvertResult fromDER(const QByteArray &a) { _props = CertContextProps(); ConvertResult r = item.fromDER(a, X509Item::TypeReq); if(r == ConvertGood) make_props(); return r; } virtual ConvertResult fromPEM(const QString &s) { _props = CertContextProps(); ConvertResult r = item.fromPEM(s, X509Item::TypeReq); if(r == ConvertGood) make_props(); return r; } virtual bool canUseFormat(CertificateRequestFormat f) const { if(f == PKCS10) return true; return false; } virtual bool createRequest(const CertificateOptions &opts, const PKeyContext &priv) { _props = CertContextProps(); item.reset(); CertificateInfo info = opts.info(); // Note: removing default constraints, let the app choose these if it wants Constraints constraints = opts.constraints(); // constraints - logic from Botan /*Constraints constraints; if(opts.isCA()) { constraints += KeyCertificateSign; constraints += CRLSign; } else constraints = find_constraints(priv, opts.constraints());*/ EVP_PKEY *pk = static_cast(&priv)->get_pkey(); X509_EXTENSION *ex; const EVP_MD *md; if(priv.key()->type() == PKey::RSA) md = EVP_sha1(); else if(priv.key()->type() == PKey::DSA) md = EVP_dss1(); else return false; // create X509_REQ *x = X509_REQ_new(); // public key X509_REQ_set_pubkey(x, pk); // subject X509_NAME *name = new_cert_name(info); X509_REQ_set_subject_name(x, name); // challenge QByteArray cs = opts.challenge().toLatin1(); if(!cs.isEmpty()) X509_REQ_add1_attr_by_NID(x, NID_pkcs9_challengePassword, MBSTRING_UTF8, (const unsigned char *)cs.data(), -1); STACK_OF(X509_EXTENSION) *exts = sk_X509_EXTENSION_new_null(); // CA mode ex = new_basic_constraints(opts.isCA(), opts.pathLimit()); if(ex) sk_X509_EXTENSION_push(exts, ex); // subject alt name ex = new_cert_subject_alt_name(info); if(ex) sk_X509_EXTENSION_push(exts, ex); // key usage ex = new_cert_key_usage(constraints); if(ex) sk_X509_EXTENSION_push(exts, ex); // extended key usage ex = new_cert_ext_key_usage(constraints); if(ex) sk_X509_EXTENSION_push(exts, ex); // policies ex = new_cert_policies(opts.policies()); if(ex) sk_X509_EXTENSION_push(exts, ex); if(sk_X509_EXTENSION_num(exts) > 0) X509_REQ_add_extensions(x, exts); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); // finished X509_REQ_sign(x, pk, md); item.req = x; make_props(); return true; } virtual const CertContextProps *props() const { return &_props; } virtual bool compare(const CSRContext *other) const { const CertContextProps *a = &_props; const CertContextProps *b = other->props(); PublicKey akey, bkey; PKeyContext *ac = subjectPublicKey(); akey.change(ac); PKeyContext *bc = other->subjectPublicKey(); bkey.change(bc); if(a->sig != b->sig || a->sigalgo != b->sigalgo || akey != bkey) return false; // TODO: Anything else we should compare? return true; } virtual PKeyContext *subjectPublicKey() const // does a new { MyPKeyContext *kc = new MyPKeyContext(provider()); EVP_PKEY *pkey = X509_REQ_get_pubkey(item.req); PKeyBase *kb = kc->pkeyToBase(pkey, false); kc->setKey(kb); return kc; } virtual QString toSPKAC() const { return QString(); } virtual ConvertResult fromSPKAC(const QString &s) { Q_UNUSED(s); return ErrorDecode; } void make_props() { X509_REQ *x = item.req; CertContextProps p; // TODO: QString challenge; p.format = PKCS10; CertificateInfo subject; subject = get_cert_name(X509_REQ_get_subject_name(x)); STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x); p.isCA = false; p.pathLimit = 0; int pos = X509v3_get_ext_by_NID(exts, NID_basic_constraints, -1); if(pos != -1) { X509_EXTENSION *ex = X509v3_get_ext(exts, pos); if(ex) get_basic_constraints(ex, &p.isCA, &p.pathLimit); } pos = X509v3_get_ext_by_NID(exts, NID_subject_alt_name, -1); if(pos != -1) { X509_EXTENSION *ex = X509v3_get_ext(exts, pos); if(ex) subject.unite(get_cert_alt_name(ex)); } pos = X509v3_get_ext_by_NID(exts, NID_key_usage, -1); if(pos != -1) { X509_EXTENSION *ex = X509v3_get_ext(exts, pos); if(ex) p.constraints = get_cert_key_usage(ex); } pos = X509v3_get_ext_by_NID(exts, NID_ext_key_usage, -1); if(pos != -1) { X509_EXTENSION *ex = X509v3_get_ext(exts, pos); if(ex) p.constraints += get_cert_ext_key_usage(ex); } pos = X509v3_get_ext_by_NID(exts, NID_certificate_policies, -1); if(pos != -1) { X509_EXTENSION *ex = X509v3_get_ext(exts, pos); if(ex) p.policies = get_cert_policies(ex); } sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); if (x->signature) { p.sig = QByteArray(x->signature->length, 0); for (int i=0; i< x->signature->length; i++) p.sig[i] = x->signature->data[i]; } switch( OBJ_obj2nid(x->sig_alg->algorithm) ) { case NID_sha1WithRSAEncryption: p.sigalgo = QCA::EMSA3_SHA1; break; case NID_md5WithRSAEncryption: p.sigalgo = QCA::EMSA3_MD5; break; case NID_md2WithRSAEncryption: p.sigalgo = QCA::EMSA3_MD2; break; case NID_ripemd160WithRSA: p.sigalgo = QCA::EMSA3_RIPEMD160; break; case NID_dsaWithSHA1: p.sigalgo = QCA::EMSA1_SHA1; break; default: qDebug() << "Unknown signature value: " << OBJ_obj2nid(x->sig_alg->algorithm); p.sigalgo = QCA::SignatureUnknown; } // FIXME: super hack CertificateOptions opts; opts.setInfo(subject); p.subject = opts.infoOrdered(); _props = p; } }; //---------------------------------------------------------------------------- // MyCRLContext //---------------------------------------------------------------------------- class MyCRLContext : public CRLContext { public: X509Item item; CRLContextProps _props; MyCRLContext(Provider *p) : CRLContext(p) { } MyCRLContext(const MyCRLContext &from) : CRLContext(from), item(from.item) { } virtual Provider::Context *clone() const { return new MyCRLContext(*this); } virtual QByteArray toDER() const { return item.toDER(); } virtual QString toPEM() const { return item.toPEM(); } virtual ConvertResult fromDER(const QByteArray &a) { _props = CRLContextProps(); ConvertResult r = item.fromDER(a, X509Item::TypeCRL); if(r == ConvertGood) make_props(); return r; } virtual ConvertResult fromPEM(const QString &s) { ConvertResult r = item.fromPEM(s, X509Item::TypeCRL); if(r == ConvertGood) make_props(); return r; } void fromX509(X509_CRL *x) { CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); item.crl = x; make_props(); } virtual const CRLContextProps *props() const { return &_props; } virtual bool compare(const CRLContext *other) const { const CRLContextProps *a = &_props; const CRLContextProps *b = other->props(); if(a->issuer != b->issuer) return false; if(a->number != b->number) return false; if(a->thisUpdate != b->thisUpdate) return false; if(a->nextUpdate != b->nextUpdate) return false; if(a->revoked != b->revoked) return false; if(a->sig != b->sig) return false; if(a->sigalgo != b->sigalgo) return false; if(a->issuerId != b->issuerId) return false; return true; } void make_props() { X509_CRL *x = item.crl; CRLContextProps p; CertificateInfo issuer; issuer = get_cert_name(X509_CRL_get_issuer(x)); p.thisUpdate = ASN1_UTCTIME_QDateTime(X509_CRL_get_lastUpdate(x), NULL); p.nextUpdate = ASN1_UTCTIME_QDateTime(X509_CRL_get_nextUpdate(x), NULL); STACK_OF(X509_REVOKED)* revokeStack = X509_CRL_get_REVOKED(x); for (int i = 0; i < sk_X509_REVOKED_num(revokeStack); ++i) { X509_REVOKED *rev = sk_X509_REVOKED_value(revokeStack, i); BigInteger serial = bn2bi(ASN1_INTEGER_to_BN(rev->serialNumber, NULL)); QDateTime time = ASN1_UTCTIME_QDateTime( rev->revocationDate, NULL); QCA::CRLEntry::Reason reason = QCA::CRLEntry::Unspecified; int pos = X509_REVOKED_get_ext_by_NID(rev, NID_crl_reason, -1); if (pos != -1) { X509_EXTENSION *ex = X509_REVOKED_get_ext(rev, pos); if(ex) { int *result = (int*) X509V3_EXT_d2i(ex); switch (*result) { case 0: reason = QCA::CRLEntry::Unspecified; break; case 1: reason = QCA::CRLEntry::KeyCompromise; break; case 2: reason = QCA::CRLEntry::CACompromise; break; case 3: reason = QCA::CRLEntry::AffiliationChanged; break; case 4: reason = QCA::CRLEntry::Superseded; break; case 5: reason = QCA::CRLEntry::CessationOfOperation; break; case 6: reason = QCA::CRLEntry::CertificateHold; break; case 8: reason = QCA::CRLEntry::RemoveFromCRL; break; case 9: reason = QCA::CRLEntry::PrivilegeWithdrawn; break; case 10: reason = QCA::CRLEntry::AACompromise; break; default: reason = QCA::CRLEntry::Unspecified; break; } ASN1_INTEGER_free((ASN1_INTEGER*)result); } } CRLEntry thisEntry( serial, time, reason); p.revoked.append(thisEntry); } if (x->signature) { p.sig = QByteArray(x->signature->length, 0); for (int i=0; i< x->signature->length; i++) p.sig[i] = x->signature->data[i]; } switch( OBJ_obj2nid(x->sig_alg->algorithm) ) { case NID_sha1WithRSAEncryption: p.sigalgo = QCA::EMSA3_SHA1; break; case NID_md5WithRSAEncryption: p.sigalgo = QCA::EMSA3_MD5; break; case NID_md2WithRSAEncryption: p.sigalgo = QCA::EMSA3_MD2; break; case NID_ripemd160WithRSA: p.sigalgo = QCA::EMSA3_RIPEMD160; break; case NID_dsaWithSHA1: p.sigalgo = QCA::EMSA1_SHA1; break; default: qWarning() << "Unknown signature value: " << OBJ_obj2nid(x->sig_alg->algorithm); p.sigalgo = QCA::SignatureUnknown; } int pos = X509_CRL_get_ext_by_NID(x, NID_authority_key_identifier, -1); if(pos != -1) { X509_EXTENSION *ex = X509_CRL_get_ext(x, pos); if(ex) p.issuerId += get_cert_issuer_key_id(ex); } p.number = -1; pos = X509_CRL_get_ext_by_NID(x, NID_crl_number, -1); if(pos != -1) { X509_EXTENSION *ex = X509_CRL_get_ext(x, pos); if(ex) { int *result = (int*) X509V3_EXT_d2i(ex); p.number = (*result); ASN1_INTEGER_free((ASN1_INTEGER*)result); } } // FIXME: super hack CertificateOptions opts; opts.setInfo(issuer); p.issuer = opts.infoOrdered(); _props = p; } }; //---------------------------------------------------------------------------- // MyCertCollectionContext //---------------------------------------------------------------------------- class MyCertCollectionContext : public CertCollectionContext { Q_OBJECT public: MyCertCollectionContext(Provider *p) : CertCollectionContext(p) { } virtual Provider::Context *clone() const { return new MyCertCollectionContext(*this); } virtual QByteArray toPKCS7(const QList &certs, const QList &crls) const { // TODO: implement Q_UNUSED(certs); Q_UNUSED(crls); return QByteArray(); } virtual ConvertResult fromPKCS7(const QByteArray &a, QList *certs, QList *crls) const { BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, a.data(), a.size()); PKCS7 *p7 = d2i_PKCS7_bio(bi, NULL); BIO_free(bi); if(!p7) return ErrorDecode; STACK_OF(X509) *xcerts = 0; STACK_OF(X509_CRL) *xcrls = 0; int i = OBJ_obj2nid(p7->type); if(i == NID_pkcs7_signed) { xcerts = p7->d.sign->cert; xcrls = p7->d.sign->crl; } else if(i == NID_pkcs7_signedAndEnveloped) { xcerts = p7->d.signed_and_enveloped->cert; xcrls = p7->d.signed_and_enveloped->crl; } QList _certs; QList _crls; if(xcerts) { for(int n = 0; n < sk_X509_num(xcerts); ++n) { MyCertContext *cc = new MyCertContext(provider()); cc->fromX509(sk_X509_value(xcerts, n)); _certs += cc; } } if(xcrls) { for(int n = 0; n < sk_X509_CRL_num(xcrls); ++n) { MyCRLContext *cc = new MyCRLContext(provider()); cc->fromX509(sk_X509_CRL_value(xcrls, n)); _crls += cc; } } PKCS7_free(p7); *certs = _certs; *crls = _crls; return ConvertGood; } }; static bool usage_check(const MyCertContext &cc, UsageMode u) { if (cc._props.constraints.isEmpty() ) { // then any usage is OK return true; } switch (u) { case UsageAny : return true; break; case UsageTLSServer : return cc._props.constraints.contains(ServerAuth); break; case UsageTLSClient : return cc._props.constraints.contains(ClientAuth); break; case UsageCodeSigning : return cc._props.constraints.contains(CodeSigning); break; case UsageEmailProtection : return cc._props.constraints.contains(EmailProtection); break; case UsageTimeStamping : return cc._props.constraints.contains(TimeStamping); break; case UsageCRLSigning : return cc._props.constraints.contains(CRLSign); break; default: return true; } } Validity MyCertContext::validate(const QList &trusted, const QList &untrusted, const QList &crls, UsageMode u, ValidateFlags vf) const { // TODO Q_UNUSED(vf); STACK_OF(X509) *trusted_list = sk_X509_new_null(); STACK_OF(X509) *untrusted_list = sk_X509_new_null(); QList crl_list; int n; for(n = 0; n < trusted.count(); ++n) { const MyCertContext *cc = static_cast(trusted[n]); X509 *x = cc->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(trusted_list, x); } for(n = 0; n < untrusted.count(); ++n) { const MyCertContext *cc = static_cast(untrusted[n]); X509 *x = cc->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(untrusted_list, x); } for(n = 0; n < crls.count(); ++n) { const MyCRLContext *cc = static_cast(crls[n]); X509_CRL *x = cc->item.crl; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); crl_list.append(x); } const MyCertContext *cc = this; X509 *x = cc->item.cert; // verification happens through a store "context" X509_STORE_CTX *ctx = X509_STORE_CTX_new(); // make a store of crls X509_STORE *store = X509_STORE_new(); for(int n = 0; n < crl_list.count(); ++n) X509_STORE_add_crl(store, crl_list[n]); // the first initialization handles untrusted certs, crls, and target cert X509_STORE_CTX_init(ctx, store, x, untrusted_list); // this initializes the trusted certs X509_STORE_CTX_trusted_stack(ctx, trusted_list); // verify! int ret = X509_verify_cert(ctx); int err = -1; if(!ret) err = ctx->error; // cleanup X509_STORE_CTX_free(ctx); X509_STORE_free(store); sk_X509_pop_free(trusted_list, X509_free); sk_X509_pop_free(untrusted_list, X509_free); for(int n = 0; n < crl_list.count(); ++n) X509_CRL_free(crl_list[n]); if(!ret) return convert_verify_error(err); if(!usage_check(*cc, u)) return ErrorInvalidPurpose; return ValidityGood; } Validity MyCertContext::validate_chain(const QList &chain, const QList &trusted, const QList &crls, UsageMode u, ValidateFlags vf) const { // TODO Q_UNUSED(vf); STACK_OF(X509) *trusted_list = sk_X509_new_null(); STACK_OF(X509) *untrusted_list = sk_X509_new_null(); QList crl_list; int n; for(n = 0; n < trusted.count(); ++n) { const MyCertContext *cc = static_cast(trusted[n]); X509 *x = cc->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(trusted_list, x); } for(n = 1; n < chain.count(); ++n) { const MyCertContext *cc = static_cast(chain[n]); X509 *x = cc->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(untrusted_list, x); } for(n = 0; n < crls.count(); ++n) { const MyCRLContext *cc = static_cast(crls[n]); X509_CRL *x = cc->item.crl; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); crl_list.append(x); } const MyCertContext *cc = static_cast(chain[0]); X509 *x = cc->item.cert; // verification happens through a store "context" X509_STORE_CTX *ctx = X509_STORE_CTX_new(); // make a store of crls X509_STORE *store = X509_STORE_new(); for(int n = 0; n < crl_list.count(); ++n) X509_STORE_add_crl(store, crl_list[n]); // the first initialization handles untrusted certs, crls, and target cert X509_STORE_CTX_init(ctx, store, x, untrusted_list); // this initializes the trusted certs X509_STORE_CTX_trusted_stack(ctx, trusted_list); // verify! int ret = X509_verify_cert(ctx); int err = -1; if(!ret) err = ctx->error; // grab the chain, which may not be fully populated STACK_OF(X509) *xchain = X509_STORE_CTX_get_chain(ctx); // make sure the chain is what we expect. the reason we need to do // this is because I don't think openssl cares about the order of // input. that is, if there's a chain A<-B<-C, and we input A as // the base cert, with B and C as the issuers, we will get a // successful validation regardless of whether the issuer list is // in the order B,C or C,B. we don't want an input chain of A,C,B // to be considered correct, so we must account for that here. QList expected; for(int n = 0; n < chain.count(); ++n) expected += static_cast(chain[n]); if(!xchain || !sameChain(xchain, expected)) err = ErrorValidityUnknown; // cleanup X509_STORE_CTX_free(ctx); X509_STORE_free(store); sk_X509_pop_free(trusted_list, X509_free); sk_X509_pop_free(untrusted_list, X509_free); for(int n = 0; n < crl_list.count(); ++n) X509_CRL_free(crl_list[n]); if(!ret) return convert_verify_error(err); if(!usage_check(*cc, u)) return ErrorInvalidPurpose; return ValidityGood; } class MyPKCS12Context : public PKCS12Context { public: MyPKCS12Context(Provider *p) : PKCS12Context(p) { } ~MyPKCS12Context() { } virtual Provider::Context *clone() const { return 0; } virtual QByteArray toPKCS12(const QString &name, const QList &chain, const PKeyContext &priv, const SecureArray &passphrase) const { if(chain.count() < 1) return QByteArray(); X509 *cert = static_cast(chain[0])->item.cert; STACK_OF(X509) *ca = sk_X509_new_null(); if(chain.count() > 1) { for(int n = 1; n < chain.count(); ++n) { X509 *x = static_cast(chain[n])->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(ca, x); } } const MyPKeyContext &pk = static_cast(priv); PKCS12 *p12 = PKCS12_create((char *)passphrase.data(), (char *)name.toLatin1().data(), pk.get_pkey(), cert, ca, 0, 0, 0, 0, 0); sk_X509_pop_free(ca, X509_free); if(!p12) return QByteArray(); BIO *bo = BIO_new(BIO_s_mem()); i2d_PKCS12_bio(bo, p12); QByteArray out = bio2ba(bo); return out; } virtual ConvertResult fromPKCS12(const QByteArray &in, const SecureArray &passphrase, QString *name, QList *chain, PKeyContext **priv) const { BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); PKCS12 *p12 = d2i_PKCS12_bio(bi, NULL); if(!p12) return ErrorDecode; EVP_PKEY *pkey; X509 *cert; STACK_OF(X509) *ca = NULL; if(!PKCS12_parse(p12, passphrase.data(), &pkey, &cert, &ca)) { PKCS12_free(p12); return ErrorDecode; } PKCS12_free(p12); // require private key if(!pkey) { if(cert) X509_free(cert); if(ca) sk_X509_pop_free(ca, X509_free); return ErrorDecode; } // TODO: require cert int aliasLength; char *aliasData = (char*)X509_alias_get0(cert, &aliasLength); *name = QString::fromAscii(aliasData, aliasLength); MyPKeyContext *pk = new MyPKeyContext(provider()); PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free() pk->k = k; *priv = pk; QList certs; if(cert) { MyCertContext *cc = new MyCertContext(provider()); cc->fromX509(cert); certs.append(cc); X509_free(cert); } if(ca) { // TODO: reorder in chain-order? // TODO: throw out certs that don't fit the chain? for(int n = 0; n < sk_X509_num(ca); ++n) { MyCertContext *cc = new MyCertContext(provider()); cc->fromX509(sk_X509_value(ca, n)); certs.append(cc); } sk_X509_pop_free(ca, X509_free); } // reorder, throw out QCA::CertificateChain ch; for(int n = 0; n < certs.count(); ++n) { QCA::Certificate cert; cert.change(certs[n]); ch += cert; } certs.clear(); ch = ch.complete(QList()); for(int n = 0; n < ch.count(); ++n) { MyCertContext *cc = (MyCertContext *)ch[n].context(); certs += (new MyCertContext(*cc)); } ch.clear(); *chain = certs; return ConvertGood; } }; //========================================================== static QString cipherIDtoString( const TLS::Version &version, const unsigned long &cipherID) { if (TLS::TLS_v1 == version) { switch( cipherID & 0xFFFF ) { case 0x0000: // RFC 2246 A.5 return QString("TLS_NULL_WITH_NULL_NULL"); break; case 0x0001: // RFC 2246 A.5 return QString("TLS_RSA_WITH_NULL_MD5"); break; case 0x0002: // RFC 2246 A.5 return QString("TLS_RSA_WITH_NULL_SHA"); break; case 0x0003: // RFC 2246 A.5 return QString("TLS_RSA_EXPORT_WITH_RC4_40_MD5"); break; case 0x0004: // RFC 2246 A.5 return QString("TLS_RSA_WITH_RC4_128_MD5"); break; case 0x0005: // RFC 2246 A.5 return QString("TLS_RSA_WITH_RC4_128_SHA"); break; case 0x0006: // RFC 2246 A.5 return QString("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"); break; case 0x0007: // RFC 2246 A.5 return QString("TLS_RSA_WITH_IDEA_CBC_SHA"); break; case 0x0008: // RFC 2246 A.5 return QString("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x0009: // RFC 2246 A.5 return QString("TLS_RSA_WITH_DES_CBC_SHA"); break; case 0x000A: // RFC 2246 A.5 return QString("TLS_RSA_WITH_3DES_EDE_CBC_SHA"); break; case 0x000B: // RFC 2246 A.5 return QString("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x000C: // RFC 2246 A.5 return QString("TLS_DH_DSS_WITH_DES_CBC_SHA"); break; case 0x000D: // RFC 2246 A.5 return QString("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"); break; case 0x000E: // RFC 2246 A.5 return QString("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x000F: // RFC 2246 A.5 return QString("TLS_DH_RSA_WITH_DES_CBC_SHA"); break; case 0x0010: // RFC 2246 A.5 return QString("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"); break; case 0x0011: // RFC 2246 A.5 return QString("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x0012: // RFC 2246 A.5 return QString("TLS_DHE_DSS_WITH_DES_CBC_SHA"); break; case 0x0013: // RFC 2246 A.5 return QString("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"); break; case 0x0014: // RFC 2246 A.5 return QString("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x0015: // RFC 2246 A.5 return QString("TLS_DHE_RSA_WITH_DES_CBC_SHA"); break; case 0x0016: // RFC 2246 A.5 return QString("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); break; case 0x0017: // RFC 2246 A.5 return QString("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"); break; case 0x0018: // RFC 2246 A.5 return QString("TLS_DH_anon_WITH_RC4_128_MD5"); break; case 0x0019: // RFC 2246 A.5 return QString("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x001A: // RFC 2246 A.5 return QString("TLS_DH_anon_WITH_DES_CBC_SHA"); break; case 0x001B: // RFC 2246 A.5 return QString("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"); break; // 0x001C and 0x001D are reserved to avoid collision with SSL3 Fortezza. case 0x001E: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_DES_CBC_SHA"); break; case 0x001F: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_3DES_EDE_CBC_SHA"); break; case 0x0020: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_RC4_128_SHA"); break; case 0x0021: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_IDEA_CBC_SHA"); break; case 0x0022: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_DES_CBC_MD5"); break; case 0x0023: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_3DES_EDE_CBC_MD5"); break; case 0x0024: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_RC4_128_MD5"); break; case 0x0025: // RFC 2712 Section 3 return QString("TLS_KRB5_WITH_IDEA_CBC_MD5"); break; case 0x0026: // RFC 2712 Section 3 return QString("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"); break; case 0x0027: // RFC 2712 Section 3 return QString("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"); break; case 0x0028: // RFC 2712 Section 3 return QString("TLS_KRB5_EXPORT_WITH_RC4_40_SHA"); break; case 0x0029: // RFC 2712 Section 3 return QString("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"); break; case 0x002A: // RFC 2712 Section 3 return QString("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"); break; case 0x002B: // RFC 2712 Section 3 return QString("TLS_KRB5_EXPORT_WITH_RC4_40_MD5"); break; case 0x002F: // RFC 3268 return QString("TLS_RSA_WITH_AES_128_CBC_SHA"); break; case 0x0030: // RFC 3268 return QString("TLS_DH_DSS_WITH_AES_128_CBC_SHA"); break; case 0x0031: // RFC 3268 return QString("TLS_DH_RSA_WITH_AES_128_CBC_SHA"); break; case 0x0032: // RFC 3268 return QString("TLS_DHE_DSS_WITH_AES_128_CBC_SHA"); break; case 0x0033: // RFC 3268 return QString("TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); break; case 0x0034: // RFC 3268 return QString("TLS_DH_anon_WITH_AES_128_CBC_SHA"); break; case 0x0035: // RFC 3268 return QString("TLS_RSA_WITH_AES_256_CBC_SHA"); break; case 0x0036: // RFC 3268 return QString("TLS_DH_DSS_WITH_AES_256_CBC_SHA"); break; case 0x0037: // RFC 3268 return QString("TLS_DH_RSA_WITH_AES_256_CBC_SHA"); break; case 0x0038: // RFC 3268 return QString("TLS_DHE_DSS_WITH_AES_256_CBC_SHA"); break; case 0x0039: // RFC 3268 return QString("TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); break; case 0x003A: // RFC 3268 return QString("TLS_DH_anon_WITH_AES_256_CBC_SHA"); break; // TODO: 0x0041 -> 0x0046 are from RFC4132 (Camellia) case 0x0060: // Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't return QString("TLS_CK_RSA_EXPORT1024_WITH_RC4_56_MD5"); break; case 0x0061: // Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't return QString("TLS_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5"); break; case 0x0062: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("TLS_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA"); break; case 0x0063: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("TLS_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA"); break; case 0x0064: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("TLS_CK_RSA_EXPORT1024_WITH_RC4_56_SHA"); break; case 0x0065: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("TLS_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA"); break; case 0x0066: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("TLS_CK_DHE_DSS_WITH_RC4_128_SHA"); break; // TODO: 0x0084 -> 0x0089 are from RFC4132 (Camellia) // TODO: 0x008A -> 0x0095 are from RFC4279 (PSK) // TODO: 0xC000 -> 0xC019 are from the ECC draft default: return QString("TLS algo to be added: %1").arg(cipherID & 0xffff, 0, 16); break; } } else if (TLS::SSL_v3 == version) { switch( cipherID & 0xFFFF ) { case 0x0000: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_NULL_WITH_NULL_NULL"); break; case 0x0001: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_NULL_MD5"); break; case 0x0002: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_NULL_SHA"); break; case 0x0003: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_EXPORT_WITH_RC4_40_MD5"); break; case 0x0004: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_RC4_128_MD5"); break; case 0x0005: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_RC4_128_SHA"); break; case 0x0006: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"); break; case 0x0007: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_IDEA_CBC_SHA"); break; case 0x0008: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x0009: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_DES_CBC_SHA"); break; case 0x000A: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_RSA_WITH_3DES_EDE_CBC_SHA"); break; case 0x000B: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x000C: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_DSS_WITH_DES_CBC_SHA"); break; case 0x000D: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"); break; case 0x000E: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_RSA_WITH_DES_CBC_SHA"); break; case 0x000F: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_RSA_WITH_DES_CBC_SHA"); break; case 0x0010: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"); break; case 0x0011: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x0012: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DHE_DSS_WITH_DES_CBC_SHA"); break; case 0x0013: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"); break; case 0x0014: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x0015: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DHE_RSA_WITH_DES_CBC_SHA"); break; case 0x0016: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); break; case 0x0017: // From the Netscape SSL3 Draft (nov 1996) return QString("SL_DH_anon_EXPORT_WITH_RC4_40_MD5"); break; case 0x0018: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_anon_WITH_RC4_128_MD5"); break; case 0x0019: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); break; case 0x001A: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_anon_WITH_DES_CBC_SHA"); break; case 0x001B: // From the Netscape SSL3 Draft (nov 1996) return QString("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"); break; // TODO: Sort out the Fortezza mess... // These aren't in the Netscape SSL3 draft, but openssl does // allow you to use them with SSL3. case 0x001E: return QString("SSL_KRB5_WITH_DES_CBC_SHA"); break; case 0x001F: return QString("SSL_KRB5_WITH_3DES_EDE_CBC_SHA"); break; case 0x0020: return QString("SSL_KRB5_WITH_RC4_128_SHA"); break; case 0x0021: return QString("SSL_KRB5_WITH_IDEA_CBC_SHA"); break; case 0x0022: return QString("SSL_KRB5_WITH_DES_CBC_MD5"); break; case 0x0023: return QString("SSL_KRB5_WITH_3DES_EDE_CBC_MD5"); break; case 0x0024: return QString("SSL_KRB5_WITH_RC4_128_MD5"); break; case 0x0025: return QString("SSL_KRB5_WITH_IDEA_CBC_MD5"); break; case 0x0026: return QString("SSL_KRB5_EXPORT_WITH_DES_CBC_40_SHA"); break; case 0x0027: return QString("SSL_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"); break; case 0x0028: return QString("SSL_KRB5_EXPORT_WITH_RC4_40_SHA"); break; case 0x0029: return QString("SSL_KRB5_EXPORT_WITH_DES_CBC_40_MD5"); break; case 0x002A: return QString("SSL_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"); break; case 0x002B: return QString("SSL_KRB5_EXPORT_WITH_RC4_40_MD5"); break; case 0x002F: return QString("SSL_RSA_WITH_AES_128_CBC_SHA"); break; case 0x0030: return QString("SSL_DH_DSS_WITH_AES_128_CBC_SHA"); break; case 0x0031: return QString("SSL_DH_RSA_WITH_AES_128_CBC_SHA"); break; case 0x0032: return QString("SSL_DHE_DSS_WITH_AES_128_CBC_SHA"); break; case 0x0033: return QString("SSL_DHE_RSA_WITH_AES_128_CBC_SHA"); break; case 0x0034: return QString("SSL_DH_anon_WITH_AES_128_CBC_SHA"); break; case 0x0035: return QString("SSL_RSA_WITH_AES_256_CBC_SHA"); break; case 0x0036: return QString("SSL_DH_DSS_WITH_AES_256_CBC_SHA"); break; case 0x0037: return QString("SSL_DH_RSA_WITH_AES_256_CBC_SHA"); break; case 0x0038: return QString("SSL_DHE_DSS_WITH_AES_256_CBC_SHA"); break; case 0x0039: return QString("SSL_DHE_RSA_WITH_AES_256_CBC_SHA"); break; case 0x003A: return QString("SSL_DH_anon_WITH_AES_256_CBC_SHA"); break; case 0x0060: // Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't return QString("SSL_CK_RSA_EXPORT1024_WITH_RC4_56_MD5"); break; case 0x0061: // Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't return QString("SSL_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5"); break; case 0x0062: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("SSL_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA"); break; case 0x0063: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("SSL_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA"); break; case 0x0064: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("SSL_CK_RSA_EXPORT1024_WITH_RC4_56_SHA"); break; case 0x0065: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("SSL_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA"); break; case 0x0066: // Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt return QString("SSL_CK_DHE_DSS_WITH_RC4_128_SHA"); break; default: return QString("SSL3 to be added: %1").arg(cipherID & 0xffff, 0, 16); break; } } else if (TLS::SSL_v2 == version) { switch( cipherID & 0xffffff) { case 0x010080: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_RC4_128_WITH_MD5"); break; case 0x020080: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_RC4_128_EXPORT40_WITH_MD5"); break; case 0x030080: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_RC2_128_CBC_WITH_MD5"); break; case 0x040080: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"); break; case 0x050080: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_RC4_128_EXPORT40_WITH_MD5"); break; case 0x060040: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_DES_64_CBC_WITH_MD5"); break; case 0x0700C0: // From the Netscape SSL2 Draft Section C.4 (nov 1994) return QString("SSL_CK_DES_192_EDE3_CBC_WITH_MD5"); break; case 0x080080: // From the openssl source, which says "MS hack" return QString("SSL_CK_RC4_64_WITH_MD5"); break; default: return QString("SSL2 to be added: %1").arg(cipherID & 0xffffff, 0, 16); break; } } else { return QString("Unknown version!"); } } // TODO: test to ensure there is no cert-test lag static bool ssl_init = false; class MyTLSContext : public TLSContext { public: enum { Good, TryAgain, Bad }; enum { Idle, Connect, Accept, Handshake, Active, Closing }; bool serv; // true if we are acting as a server int mode; QByteArray sendQueue; QByteArray recvQueue; CertificateCollection trusted; Certificate cert, peercert; // TODO: support cert chains PrivateKey key; QString targetHostName; Result result_result; QByteArray result_to_net; int result_encoded; QByteArray result_plain; SSL *ssl; #if OPENSSL_VERSION_NUMBER >= 0x00909000L const SSL_METHOD *method; #else SSL_METHOD *method; #endif SSL_CTX *context; BIO *rbio, *wbio; Validity vr; bool v_eof; MyTLSContext(Provider *p) : TLSContext(p, "tls") { if(!ssl_init) { SSL_library_init(); SSL_load_error_strings(); ssl_init = true; } ssl = 0; context = 0; reset(); } ~MyTLSContext() { reset(); } virtual Provider::Context *clone() const { return 0; } virtual void reset() { if(ssl) { SSL_free(ssl); ssl = 0; } if(context) { SSL_CTX_free(context); context = 0; } cert = Certificate(); key = PrivateKey(); sendQueue.resize(0); recvQueue.resize(0); mode = Idle; peercert = Certificate(); vr = ErrorValidityUnknown; v_eof = false; } // dummy verification function for SSL_set_verify() static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { Q_UNUSED(preverify_ok); Q_UNUSED(x509_ctx); // don't terminate handshake in case of verification failure return 1; } virtual QStringList supportedCipherSuites(const TLS::Version &version) const { OpenSSL_add_ssl_algorithms(); SSL_CTX *ctx = 0; switch (version) { case TLS::SSL_v2: ctx = SSL_CTX_new(SSLv2_client_method()); break; case TLS::SSL_v3: ctx = SSL_CTX_new(SSLv3_client_method()); break; case TLS::TLS_v1: ctx = SSL_CTX_new(TLSv1_client_method()); break; case TLS::DTLS_v1: default: /* should not happen - should be in a "dtls" provider*/ qWarning("Unexpected enum in cipherSuites"); ctx = 0; } if (NULL == ctx) return QStringList(); SSL *ssl = SSL_new(ctx); if (NULL == ssl) { SSL_CTX_free(ctx); return QStringList(); } STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl); QStringList cipherList; for(int i = 0; i < sk_SSL_CIPHER_num(sk); ++i) { SSL_CIPHER *thisCipher = sk_SSL_CIPHER_value(sk, i); cipherList += cipherIDtoString(version, thisCipher->id); } SSL_free(ssl); SSL_CTX_free(ctx); return cipherList; } virtual bool canCompress() const { // TODO return false; } virtual bool canSetHostName() const { // TODO return false; } virtual int maxSSF() const { // TODO return 256; } virtual void setConstraints(int minSSF, int maxSSF) { // TODO Q_UNUSED(minSSF); Q_UNUSED(maxSSF); } virtual void setConstraints(const QStringList &cipherSuiteList) { // TODO Q_UNUSED(cipherSuiteList); } virtual void setup(bool serverMode, const QString &hostName, bool compress) { serv = serverMode; if ( false == serverMode ) { // client targetHostName = hostName; } Q_UNUSED(compress); // TODO } virtual void setTrustedCertificates(const CertificateCollection &_trusted) { trusted = _trusted; } virtual void setIssuerList(const QList &issuerList) { Q_UNUSED(issuerList); // TODO } virtual void setCertificate(const CertificateChain &_cert, const PrivateKey &_key) { if(!_cert.isEmpty()) cert = _cert.primary(); // TODO: take the whole chain key = _key; } virtual void setSessionId(const TLSSessionContext &id) { // TODO Q_UNUSED(id); } virtual void shutdown() { mode = Closing; } virtual void start() { bool ok; if(serv) ok = priv_startServer(); else ok = priv_startClient(); result_result = ok ? Success : Error; doResultsReady(); } virtual void update(const QByteArray &from_net, const QByteArray &from_app) { if(mode == Active) { bool ok = true; if(!from_app.isEmpty()) ok = priv_encode(from_app, &result_to_net, &result_encoded); if(ok) ok = priv_decode(from_net, &result_plain, &result_to_net); result_result = ok ? Success : Error; } else if(mode == Closing) result_result = priv_shutdown(from_net, &result_to_net); else result_result = priv_handshake(from_net, &result_to_net); //printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(), from_app.size(), result_plain.size()); doResultsReady(); } bool priv_startClient() { //serv = false; method = SSLv23_client_method(); if(!init()) return false; mode = Connect; return true; } bool priv_startServer() { //serv = true; method = SSLv23_server_method(); if(!init()) return false; mode = Accept; return true; } Result priv_handshake(const QByteArray &from_net, QByteArray *to_net) { if(!from_net.isEmpty()) BIO_write(rbio, from_net.data(), from_net.size()); if(mode == Connect) { int ret = doConnect(); if(ret == Good) { mode = Handshake; } else if(ret == Bad) { reset(); return Error; } } if(mode == Accept) { int ret = doAccept(); if(ret == Good) { getCert(); mode = Active; } else if(ret == Bad) { reset(); return Error; } } if(mode == Handshake) { int ret = doHandshake(); if(ret == Good) { getCert(); mode = Active; } else if(ret == Bad) { reset(); return Error; } } // process outgoing *to_net = readOutgoing(); if(mode == Active) return Success; else return Continue; } Result priv_shutdown(const QByteArray &from_net, QByteArray *to_net) { if(!from_net.isEmpty()) BIO_write(rbio, from_net.data(), from_net.size()); int ret = doShutdown(); if(ret == Bad) { reset(); return Error; } *to_net = readOutgoing(); if(ret == Good) { mode = Idle; return Success; } else { //mode = Closing; return Continue; } } bool priv_encode(const QByteArray &plain, QByteArray *to_net, int *enc) { if(mode != Active) return false; sendQueue.append(plain); int encoded = 0; if(sendQueue.size() > 0) { int ret = SSL_write(ssl, sendQueue.data(), sendQueue.size()); enum { Good, Continue, Done, Error }; int m; if(ret <= 0) { int x = SSL_get_error(ssl, ret); if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) m = Continue; else if(x == SSL_ERROR_ZERO_RETURN) m = Done; else m = Error; } else { m = Good; encoded = ret; int newsize = sendQueue.size() - encoded; char *r = sendQueue.data(); memmove(r, r + encoded, newsize); sendQueue.resize(newsize); } if(m == Done) { sendQueue.resize(0); v_eof = true; return false; } if(m == Error) { sendQueue.resize(0); return false; } } *to_net += readOutgoing(); *enc = encoded; return true; } bool priv_decode(const QByteArray &from_net, QByteArray *plain, QByteArray *to_net) { if(mode != Active) return false; if(!from_net.isEmpty()) BIO_write(rbio, from_net.data(), from_net.size()); QByteArray a; while(!v_eof) { a.resize(8192); int ret = SSL_read(ssl, a.data(), a.size()); //printf("SSL_read = %d\n", ret); if(ret > 0) { if(ret != (int)a.size()) a.resize(ret); //printf("SSL_read chunk: [%s]\n", qPrintable(arrayToHex(a))); recvQueue.append(a); } else if(ret <= 0) { ERR_print_errors_fp(stdout); int x = SSL_get_error(ssl, ret); //printf("SSL_read error = %d\n", x); if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) break; else if(x == SSL_ERROR_ZERO_RETURN) v_eof = true; else return false; } } *plain = recvQueue; recvQueue.resize(0); // could be outgoing data also *to_net += readOutgoing(); return true; } virtual bool waitForResultsReady(int msecs) { // TODO: for now, all operations block anyway Q_UNUSED(msecs); return true; } virtual Result result() const { return result_result; } virtual QByteArray to_net() { QByteArray a = result_to_net; result_to_net.clear(); return a; } virtual int encoded() const { return result_encoded; } virtual QByteArray to_app() { QByteArray a = result_plain; result_plain.clear(); return a; } virtual bool eof() const { return v_eof; } virtual bool clientHelloReceived() const { // TODO return false; } virtual bool serverHelloReceived() const { // TODO return false; } virtual QString hostName() const { // TODO return QString(); } virtual bool certificateRequested() const { // TODO return false; } virtual QList issuerList() const { // TODO return QList(); } virtual SessionInfo sessionInfo() const { SessionInfo sessInfo; sessInfo.isCompressed = (0 != ssl->session->compress_meth); if (ssl->version == TLS1_VERSION) sessInfo.version = TLS::TLS_v1; else if (ssl->version == SSL3_VERSION) sessInfo.version = TLS::SSL_v3; else if (ssl->version == SSL2_VERSION) sessInfo.version = TLS::SSL_v2; else { qDebug("unexpected version response"); sessInfo.version = TLS::TLS_v1; } sessInfo.cipherSuite = cipherIDtoString( sessInfo.version, SSL_get_current_cipher(ssl)->id); sessInfo.cipherMaxBits = SSL_get_cipher_bits(ssl, &(sessInfo.cipherBits)); sessInfo.id = 0; // TODO: session resuming return sessInfo; } virtual QByteArray unprocessed() { QByteArray a; int size = BIO_pending(rbio); if(size <= 0) return a; a.resize(size); int r = BIO_read(rbio, a.data(), size); if(r <= 0) { a.resize(0); return a; } if(r != size) a.resize(r); return a; } virtual Validity peerCertificateValidity() const { return vr; } virtual CertificateChain peerCertificateChain() const { // TODO: support whole chain CertificateChain chain; chain.append(peercert); return chain; } void doResultsReady() { QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); } bool init() { context = SSL_CTX_new(method); if(!context) return false; // setup the cert store { X509_STORE *store = SSL_CTX_get_cert_store(context); QList cert_list = trusted.certificates(); QList crl_list = trusted.crls(); int n; for(n = 0; n < cert_list.count(); ++n) { const MyCertContext *cc = static_cast(cert_list[n].context()); X509 *x = cc->item.cert; //CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); X509_STORE_add_cert(store, x); } for(n = 0; n < crl_list.count(); ++n) { const MyCRLContext *cc = static_cast(crl_list[n].context()); X509_CRL *x = cc->item.crl; //CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); X509_STORE_add_crl(store, x); } } ssl = SSL_new(context); if(!ssl) { SSL_CTX_free(context); context = 0; return false; } SSL_set_ssl_method(ssl, method); // can this return error? #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if ( targetHostName.isEmpty() == false ) { // we have a target // this might fail, but we ignore that for now char *hostname = targetHostName.toAscii().data(); SSL_set_tlsext_host_name( ssl, hostname ); } #endif // setup the memory bio rbio = BIO_new(BIO_s_mem()); wbio = BIO_new(BIO_s_mem()); // this passes control of the bios to ssl. we don't need to free them. SSL_set_bio(ssl, rbio, wbio); // FIXME: move this to after server hello // setup the cert to send if(!cert.isNull() && !key.isNull()) { PrivateKey nkey = key; const PKeyContext *tmp_kc = static_cast(nkey.context()); if(!tmp_kc->sameProvider(this)) { //fprintf(stderr, "experimental: private key supplied by a different provider\n"); // make a pkey pointing to the existing private key EVP_PKEY *pkey; pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey, createFromExisting(nkey.toRSA())); // make a new private key object to hold it MyPKeyContext *pk = new MyPKeyContext(provider()); PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free() pk->k = k; nkey.change(pk); } const MyCertContext *cc = static_cast(cert.context()); const MyPKeyContext *kc = static_cast(nkey.context()); if(SSL_use_certificate(ssl, cc->item.cert) != 1) { SSL_free(ssl); SSL_CTX_free(context); return false; } if(SSL_use_PrivateKey(ssl, kc->get_pkey()) != 1) { SSL_free(ssl); SSL_CTX_free(context); return false; } } // request a certificate from the client, if in server mode if(serv) { SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, ssl_verify_callback); } return true; } void getCert() { // verify the certificate Validity code = ErrorValidityUnknown; X509 *x = SSL_get_peer_certificate(ssl); if(x) { MyCertContext *cc = new MyCertContext(provider()); cc->fromX509(x); X509_free(x); peercert.change(cc); int ret = SSL_get_verify_result(ssl); if(ret == X509_V_OK) code = ValidityGood; else code = convert_verify_error(ret); } else { peercert = Certificate(); } vr = code; } int doConnect() { int ret = SSL_connect(ssl); if(ret < 0) { int x = SSL_get_error(ssl, ret); if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) return TryAgain; else return Bad; } else if(ret == 0) return Bad; return Good; } int doAccept() { int ret = SSL_accept(ssl); if(ret < 0) { int x = SSL_get_error(ssl, ret); if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) return TryAgain; else return Bad; } else if(ret == 0) return Bad; return Good; } int doHandshake() { int ret = SSL_do_handshake(ssl); if(ret < 0) { int x = SSL_get_error(ssl, ret); if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) return TryAgain; else return Bad; } else if(ret == 0) return Bad; return Good; } int doShutdown() { int ret = SSL_shutdown(ssl); if(ret >= 1) return Good; else { if(ret == 0) return TryAgain; int x = SSL_get_error(ssl, ret); if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) return TryAgain; return Bad; } } QByteArray readOutgoing() { QByteArray a; int size = BIO_pending(wbio); if(size <= 0) return a; a.resize(size); int r = BIO_read(wbio, a.data(), size); if(r <= 0) { a.resize(0); return a; } if(r != size) a.resize(r); return a; } }; class CMSContext : public SMSContext { public: CertificateCollection trustedCerts; CertificateCollection untrustedCerts; QList privateKeys; CMSContext(Provider *p) : SMSContext(p, "cms") { } ~CMSContext() { } virtual Provider::Context *clone() const { return 0; } virtual void setTrustedCertificates(const CertificateCollection &trusted) { trustedCerts = trusted; } virtual void setUntrustedCertificates(const CertificateCollection &untrusted) { untrustedCerts = untrusted; } virtual void setPrivateKeys(const QList &keys) { privateKeys = keys; } virtual MessageContext *createMessage(); }; STACK_OF(X509) *get_pk7_certs(PKCS7 *p7) { int i = OBJ_obj2nid(p7->type); if(i == NID_pkcs7_signed) return p7->d.sign->cert; else if(i == NID_pkcs7_signedAndEnveloped) return p7->d.signed_and_enveloped->cert; else return 0; } class MyMessageContextThread : public QThread { Q_OBJECT public: SecureMessage::Format format; SecureMessage::SignMode signMode; Certificate cert; PrivateKey key; STACK_OF(X509) *other_certs; BIO *bi; int flags; PKCS7 *p7; bool ok; QByteArray out, sig; MyMessageContextThread(QObject *parent = 0) : QThread(parent), ok(false) { } protected: virtual void run() { MyCertContext *cc = static_cast(cert.context()); MyPKeyContext *kc = static_cast(key.context()); X509 *cx = cc->item.cert; EVP_PKEY *kx = kc->get_pkey(); p7 = PKCS7_sign(cx, kx, other_certs, bi, flags); BIO_free(bi); sk_X509_pop_free(other_certs, X509_free); if(p7) { //printf("good\n"); BIO *bo; //BIO *bo = BIO_new(BIO_s_mem()); //i2d_PKCS7_bio(bo, p7); //PEM_write_bio_PKCS7(bo, p7); //SecureArray buf = bio2buf(bo); //printf("[%s]\n", buf.data()); bo = BIO_new(BIO_s_mem()); if(format == SecureMessage::Binary) i2d_PKCS7_bio(bo, p7); else // Ascii PEM_write_bio_PKCS7(bo, p7); if (SecureMessage::Detached == signMode) sig = bio2ba(bo); else out = bio2ba(bo); ok = true; } else { printf("bad here\n"); ERR_print_errors_fp(stdout); } } }; class MyMessageContext : public MessageContext { Q_OBJECT public: CMSContext *cms; SecureMessageKey signer; SecureMessageKeyList to; SecureMessage::SignMode signMode; bool bundleSigner; bool smime; SecureMessage::Format format; Operation op; bool _finished; QByteArray in, out; QByteArray sig; int total; CertificateChain signerChain; int ver_ret; MyMessageContextThread *thread; MyMessageContext(CMSContext *_cms, Provider *p) : MessageContext(p, "cmsmsg") { cms = _cms; total = 0; ver_ret = 0; thread = 0; } ~MyMessageContext() { } virtual Provider::Context *clone() const { return 0; } virtual bool canSignMultiple() const { return false; } virtual SecureMessage::Type type() const { return SecureMessage::CMS; } virtual void reset() { } virtual void setupEncrypt(const SecureMessageKeyList &keys) { to = keys; } virtual void setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool bundleSigner, bool smime) { signer = keys.first(); signMode = m; this->bundleSigner = bundleSigner; this->smime = smime; } virtual void setupVerify(const QByteArray &detachedSig) { // TODO sig = detachedSig; } virtual void start(SecureMessage::Format f, Operation op) { format = f; _finished = false; // TODO: other operations //if(op == Sign) //{ this->op = op; //} //else if(op == Encrypt) //{ // this->op = op; //} } virtual void update(const QByteArray &in) { this->in.append(in); total += in.size(); QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); } virtual QByteArray read() { return out; } virtual int written() { int x = total; total = 0; return x; } virtual void end() { _finished = true; // sign if(op == Sign) { CertificateChain chain = signer.x509CertificateChain(); Certificate cert = chain.primary(); QList nonroots; if(chain.count() > 1) { for(int n = 1; n < chain.count(); ++n) nonroots.append(chain[n]); } PrivateKey key = signer.x509PrivateKey(); const PKeyContext *tmp_kc = static_cast(key.context()); if(!tmp_kc->sameProvider(this)) { //fprintf(stderr, "experimental: private key supplied by a different provider\n"); // make a pkey pointing to the existing private key EVP_PKEY *pkey; pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey, createFromExisting(key.toRSA())); // make a new private key object to hold it MyPKeyContext *pk = new MyPKeyContext(provider()); PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free() pk->k = k; key.change(pk); } // allow different cert provider. this is just a // quick hack, enough to please qca-test if(!cert.context()->sameProvider(this)) { //fprintf(stderr, "experimental: cert supplied by a different provider\n"); cert = Certificate::fromDER(cert.toDER()); if(cert.isNull() || !cert.context()->sameProvider(this)) { //fprintf(stderr, "error converting cert\n"); } } //MyCertContext *cc = static_cast(cert.context()); //MyPKeyContext *kc = static_cast(key.context()); //X509 *cx = cc->item.cert; //EVP_PKEY *kx = kc->get_pkey(); STACK_OF(X509) *other_certs; BIO *bi; int flags; //PKCS7 *p7; // nonroots other_certs = sk_X509_new_null(); for(int n = 0; n < nonroots.count(); ++n) { X509 *x = static_cast(nonroots[n].context())->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(other_certs, x); } //printf("bundling %d other_certs\n", sk_X509_num(other_certs)); bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); flags = 0; flags |= PKCS7_BINARY; if (SecureMessage::Detached == signMode) { flags |= PKCS7_DETACHED; } if (false == bundleSigner) flags |= PKCS7_NOCERTS; if(thread) delete thread; thread = new MyMessageContextThread(this); thread->format = format; thread->signMode = signMode; thread->cert = cert; thread->key = key; thread->other_certs = other_certs; thread->bi = bi; thread->flags = flags; connect(thread, SIGNAL(finished()), SLOT(thread_finished())); thread->start(); } else if(op == Encrypt) { // TODO: support multiple recipients Certificate target = to.first().x509CertificateChain().primary(); STACK_OF(X509) *other_certs; BIO *bi; int flags; PKCS7 *p7; other_certs = sk_X509_new_null(); X509 *x = static_cast(target.context())->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(other_certs, x); bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); flags = 0; flags |= PKCS7_BINARY; p7 = PKCS7_encrypt(other_certs, bi, EVP_des_ede3_cbc(), flags); // TODO: cipher? BIO_free(bi); sk_X509_pop_free(other_certs, X509_free); QString env; if(p7) { // FIXME: format BIO *bo = BIO_new(BIO_s_mem()); i2d_PKCS7_bio(bo, p7); //PEM_write_bio_PKCS7(bo, p7); out = bio2ba(bo); PKCS7_free(p7); } else { printf("bad\n"); return; } } else if(op == Verify) { // TODO: support non-detached sigs BIO *out = BIO_new(BIO_s_mem()); BIO *bi = BIO_new(BIO_s_mem()); if (false == sig.isEmpty()) { // We have detached signature BIO_write(bi, sig.data(), sig.size()); } else { BIO_write(bi, in.data(), in.size()); } PKCS7 *p7; if(format == SecureMessage::Binary) p7 = d2i_PKCS7_bio(bi, NULL); else // Ascii p7 = PEM_read_bio_PKCS7(bi, NULL, passphrase_cb, NULL); BIO_free(bi); if(!p7) { // TODO printf("bad1\n"); QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); return; } // intermediates/signers that may not be in the blob STACK_OF(X509) *other_certs = sk_X509_new_null(); QList untrusted_list = cms->untrustedCerts.certificates(); QList untrusted_crls = cms->untrustedCerts.crls(); // we'll use the crls later for(int n = 0; n < untrusted_list.count(); ++n) { X509 *x = static_cast(untrusted_list[n].context())->item.cert; CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sk_X509_push(other_certs, x); } // get the possible message signers QList signers; STACK_OF(X509) *xs = PKCS7_get0_signers(p7, other_certs, 0); if(xs) { for(int n = 0; n < sk_X509_num(xs); ++n) { MyCertContext *cc = new MyCertContext(provider()); cc->fromX509(sk_X509_value(xs, n)); Certificate cert; cert.change(cc); //printf("signer: [%s]\n", qPrintable(cert.commonName())); signers.append(cert); } sk_X509_free(xs); } // get the rest of the certificates lying around QList others; xs = get_pk7_certs(p7); // don't free if(xs) { for(int n = 0; n < sk_X509_num(xs); ++n) { MyCertContext *cc = new MyCertContext(provider()); cc->fromX509(sk_X509_value(xs, n)); Certificate cert; cert.change(cc); others.append(cert); //printf("other: [%s]\n", qPrintable(cert.commonName())); } } // signer needs to be supplied in the message itself // or via cms->untrustedCerts if(signers.isEmpty()) { QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); return; } // FIXME: handle more than one signer CertificateChain chain; chain += signers[0]; // build chain chain = chain.complete(others); signerChain = chain; X509_STORE *store = X509_STORE_new(); QList cert_list = cms->trustedCerts.certificates(); QList crl_list = cms->trustedCerts.crls(); for(int n = 0; n < cert_list.count(); ++n) { //printf("trusted: [%s]\n", qPrintable(cert_list[n].commonName())); const MyCertContext *cc = static_cast(cert_list[n].context()); X509 *x = cc->item.cert; //CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); X509_STORE_add_cert(store, x); } for(int n = 0; n < crl_list.count(); ++n) { const MyCRLContext *cc = static_cast(crl_list[n].context()); X509_CRL *x = cc->item.crl; //CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); X509_STORE_add_crl(store, x); } // add these crls also crl_list = untrusted_crls; for(int n = 0; n < crl_list.count(); ++n) { const MyCRLContext *cc = static_cast(crl_list[n].context()); X509_CRL *x = cc->item.crl; //CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); X509_STORE_add_crl(store, x); } int ret; if(!sig.isEmpty()) { // Detached signMode bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); ret = PKCS7_verify(p7, other_certs, store, bi, NULL, 0); BIO_free(bi); } else { ret = PKCS7_verify(p7, other_certs, store, NULL, out, 0); // qDebug() << "Verify: " << ret; } //if(!ret) // ERR_print_errors_fp(stdout); sk_X509_pop_free(other_certs, X509_free); X509_STORE_free(store); PKCS7_free(p7); ver_ret = ret; // TODO QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); } else if(op == Decrypt) { bool ok = false; for(int n = 0; n < cms->privateKeys.count(); ++n) { CertificateChain chain = cms->privateKeys[n].x509CertificateChain(); Certificate cert = chain.primary(); PrivateKey key = cms->privateKeys[n].x509PrivateKey(); MyCertContext *cc = static_cast(cert.context()); MyPKeyContext *kc = static_cast(key.context()); X509 *cx = cc->item.cert; EVP_PKEY *kx = kc->get_pkey(); BIO *bi = BIO_new(BIO_s_mem()); BIO_write(bi, in.data(), in.size()); PKCS7 *p7 = d2i_PKCS7_bio(bi, NULL); BIO_free(bi); if(!p7) { // TODO printf("bad1\n"); return; } BIO *bo = BIO_new(BIO_s_mem()); int ret = PKCS7_decrypt(p7, kx, cx, bo, 0); PKCS7_free(p7); if(!ret) continue; ok = true; out = bio2ba(bo); break; } if(!ok) { // TODO printf("bad2\n"); return; } } } virtual bool finished() const { return _finished; } virtual bool waitForFinished(int msecs) { // TODO Q_UNUSED(msecs); if(thread) { thread->wait(); getresults(); } return true; } virtual bool success() const { // TODO return true; } virtual SecureMessage::Error errorCode() const { // TODO return SecureMessage::ErrorUnknown; } virtual QByteArray signature() const { return sig; } virtual QString hashName() const { // TODO return "sha1"; } virtual SecureMessageSignatureList signers() const { // only report signers for verify if(op != Verify) return SecureMessageSignatureList(); SecureMessageKey key; if(!signerChain.isEmpty()) key.setX509CertificateChain(signerChain); // TODO/FIXME !!! InvalidSignature might be used here even // if the signature is just fine, and the key is invalid // (we need to use InvalidKey instead). Validity vr = ErrorValidityUnknown; if(!signerChain.isEmpty()) vr = signerChain.validate(cms->trustedCerts, cms->untrustedCerts.crls()); SecureMessageSignature::IdentityResult ir; if(vr == ValidityGood) ir = SecureMessageSignature::Valid; else ir = SecureMessageSignature::InvalidKey; if(!ver_ret) ir = SecureMessageSignature::InvalidSignature; SecureMessageSignature s(ir, vr, key, QDateTime::currentDateTime()); // TODO return SecureMessageSignatureList() << s; } void getresults() { sig = thread->sig; out = thread->out; } private slots: void thread_finished() { getresults(); emit updated(); } }; MessageContext *CMSContext::createMessage() { return new MyMessageContext(this, provider()); } class opensslCipherContext : public CipherContext { public: opensslCipherContext(const EVP_CIPHER *algorithm, const int pad, Provider *p, const QString &type) : CipherContext(p, type) { m_cryptoAlgorithm = algorithm; EVP_CIPHER_CTX_init(&m_context); m_pad = pad; m_type = type; } ~opensslCipherContext() { EVP_CIPHER_CTX_cleanup(&m_context); } void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv) { m_direction = dir; if ( ( m_cryptoAlgorithm == EVP_des_ede3() ) && (key.size() == 16) ) { // this is really a two key version of triple DES. m_cryptoAlgorithm = EVP_des_ede(); } if (Encode == m_direction) { EVP_EncryptInit_ex(&m_context, m_cryptoAlgorithm, 0, 0, 0); EVP_CIPHER_CTX_set_key_length(&m_context, key.size()); EVP_EncryptInit_ex(&m_context, 0, 0, (const unsigned char*)(key.data()), (const unsigned char*)(iv.data())); } else { EVP_DecryptInit_ex(&m_context, m_cryptoAlgorithm, 0, 0, 0); EVP_CIPHER_CTX_set_key_length(&m_context, key.size()); EVP_DecryptInit_ex(&m_context, 0, 0, (const unsigned char*)(key.data()), (const unsigned char*)(iv.data())); } EVP_CIPHER_CTX_set_padding(&m_context, m_pad); } Provider::Context *clone() const { return new opensslCipherContext( *this ); } int blockSize() const { return EVP_CIPHER_CTX_block_size(&m_context); } bool update(const SecureArray &in, SecureArray *out) { // This works around a problem in OpenSSL, where it asserts if // there is nothing to encrypt. if ( 0 == in.size() ) return true; out->resize(in.size()+blockSize()); int resultLength; if (Encode == m_direction) { if (0 == EVP_EncryptUpdate(&m_context, (unsigned char*)out->data(), &resultLength, (unsigned char*)in.data(), in.size())) { return false; } } else { if (0 == EVP_DecryptUpdate(&m_context, (unsigned char*)out->data(), &resultLength, (unsigned char*)in.data(), in.size())) { return false; } } out->resize(resultLength); return true; } bool final(SecureArray *out) { out->resize(blockSize()); int resultLength; if (Encode == m_direction) { if (0 == EVP_EncryptFinal_ex(&m_context, (unsigned char*)out->data(), &resultLength)) { return false; } } else { if (0 == EVP_DecryptFinal_ex(&m_context, (unsigned char*)out->data(), &resultLength)) { return false; } } out->resize(resultLength); return true; } // Change cipher names KeyLength keyLength() const { if (m_type.left(4) == "des-") { return KeyLength( 8, 8, 1); } else if (m_type.left(6) == "aes128") { return KeyLength( 16, 16, 1); } else if (m_type.left(6) == "aes192") { return KeyLength( 24, 24, 1); } else if (m_type.left(6) == "aes256") { return KeyLength( 32, 32, 1); } else if (m_type.left(5) == "cast5") { return KeyLength( 5, 16, 1); } else if (m_type.left(8) == "blowfish") { // Don't know - TODO return KeyLength( 1, 32, 1); } else if (m_type.left(9) == "tripledes") { return KeyLength( 16, 24, 1); } else { return KeyLength( 0, 1, 1); } } protected: EVP_CIPHER_CTX m_context; const EVP_CIPHER *m_cryptoAlgorithm; Direction m_direction; int m_pad; QString m_type; }; static QStringList all_hash_types() { QStringList list; list += "sha1"; list += "sha0"; list += "ripemd160"; list += "md2"; list += "md4"; list += "md5"; #ifdef SHA224_DIGEST_LENGTH list += "sha224"; #endif #ifdef SHA256_DIGEST_LENGTH list += "sha256"; #endif #ifdef SHA384_DIGEST_LENGTH list += "sha384"; #endif #ifdef SHA512_DIGEST_LENGTH list += "sha512"; #endif /* #ifdef OBJ_whirlpool list += "whirlpool"; #endif */ return list; } static QStringList all_cipher_types() { QStringList list; list += "aes128-ecb"; list += "aes128-cfb"; list += "aes128-cbc"; list += "aes128-cbc-pkcs7"; list += "aes128-ofb"; list += "aes192-ecb"; list += "aes192-cfb"; list += "aes192-cbc"; list += "aes192-cbc-pkcs7"; list += "aes192-ofb"; list += "aes256-ecb"; list += "aes256-cbc"; list += "aes256-cbc-pkcs7"; list += "aes256-cfb"; list += "aes256-ofb"; list += "blowfish-ecb"; list += "blowfish-cbc-pkcs7"; list += "blowfish-cbc"; list += "blowfish-cfb"; list += "blowfish-ofb"; list += "tripledes-ecb"; list += "tripledes-cbc"; list += "des-ecb"; list += "des-ecb-pkcs7"; list += "des-cbc"; list += "des-cbc-pkcs7"; list += "des-cfb"; list += "des-ofb"; list += "cast5-ecb"; list += "cast5-cbc"; list += "cast5-cbc-pkcs7"; list += "cast5-cfb"; list += "cast5-ofb"; return list; } static QStringList all_mac_types() { QStringList list; list += "hmac(md5)"; list += "hmac(sha1)"; #ifdef SHA224_DIGEST_LENGTH list += "hmac(sha224)"; #endif #ifdef SHA256_DIGEST_LENGTH list += "hmac(sha256)"; #endif #ifdef SHA384_DIGEST_LENGTH list += "hmac(sha384)"; #endif #ifdef SHA512_DIGEST_LENGTH list += "hmac(sha512)"; #endif list += "hmac(ripemd160)"; return list; } class opensslInfoContext : public InfoContext { Q_OBJECT public: opensslInfoContext(Provider *p) : InfoContext(p) { } Provider::Context *clone() const { return new opensslInfoContext(*this); } QStringList supportedHashTypes() const { return all_hash_types(); } QStringList supportedCipherTypes() const { return all_cipher_types(); } QStringList supportedMACTypes() const { return all_mac_types(); } }; class opensslRandomContext : public RandomContext { public: opensslRandomContext(QCA::Provider *p) : RandomContext(p) { } Context *clone() const { return new opensslRandomContext(*this); } QCA::SecureArray nextBytes(int size) { QCA::SecureArray buf(size); int r; // FIXME: loop while we don't have enough random bytes. while (true) { r = RAND_bytes((unsigned char*)(buf.data()), size); if (r == 1) break; // success r = RAND_pseudo_bytes((unsigned char*)(buf.data()), size); if (r >= 0) break; // accept insecure random numbers } return buf; } }; } using namespace opensslQCAPlugin; class opensslProvider : public Provider { public: bool openssl_initted; opensslProvider() { openssl_initted = false; } void init() { OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); // seed the RNG if it's not seeded yet if (RAND_status() == 0) { qsrand(time(NULL)); char buf[128]; for(int n = 0; n < 128; ++n) buf[n] = qrand(); RAND_seed(buf, 128); } openssl_initted = true; } ~opensslProvider() { // FIXME: ? for now we never deinit, in case other libs/code // are using openssl /*if(!openssl_initted) return; // todo: any other shutdown? EVP_cleanup(); //ENGINE_cleanup(); CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); ERR_free_strings();*/ } int qcaVersion() const { return QCA_VERSION; } QString name() const { return "qca-ossl"; } QString credit() const { return QString( "This product includes cryptographic software " "written by Eric Young (eay@cryptsoft.com)"); } QStringList features() const { QStringList list; list += "random"; list += all_hash_types(); list += all_mac_types(); list += all_cipher_types(); list += "pbkdf1(md2)"; list += "pbkdf1(sha1)"; list += "pbkdf2(sha1)"; list += "pkey"; list += "dlgroup"; list += "rsa"; list += "dsa"; list += "dh"; list += "cert"; list += "csr"; list += "crl"; list += "certcollection"; list += "pkcs12"; list += "tls"; list += "cms"; list += "ca"; return list; } Context *createContext(const QString &type) { //OpenSSL_add_all_digests(); if ( type == "random" ) return new opensslRandomContext(this); else if ( type == "info" ) return new opensslInfoContext(this); else if ( type == "sha1" ) return new opensslHashContext( EVP_sha1(), this, type); else if ( type == "sha0" ) return new opensslHashContext( EVP_sha(), this, type); else if ( type == "ripemd160" ) return new opensslHashContext( EVP_ripemd160(), this, type); else if ( type == "md2" ) return new opensslHashContext( EVP_md2(), this, type); else if ( type == "md4" ) return new opensslHashContext( EVP_md4(), this, type); else if ( type == "md5" ) return new opensslHashContext( EVP_md5(), this, type); #ifdef SHA224_DIGEST_LENGTH else if ( type == "sha224" ) return new opensslHashContext( EVP_sha224(), this, type); #endif #ifdef SHA256_DIGEST_LENGTH else if ( type == "sha256" ) return new opensslHashContext( EVP_sha256(), this, type); #endif #ifdef SHA384_DIGEST_LENGTH else if ( type == "sha384" ) return new opensslHashContext( EVP_sha384(), this, type); #endif #ifdef SHA512_DIGEST_LENGTH else if ( type == "sha512" ) return new opensslHashContext( EVP_sha512(), this, type); #endif /* #ifdef OBJ_whirlpool else if ( type == "whirlpool" ) return new opensslHashContext( EVP_whirlpool(), this, type); #endif */ else if ( type == "pbkdf1(sha1)" ) return new opensslPbkdf1Context( EVP_sha1(), this, type ); else if ( type == "pbkdf1(md2)" ) return new opensslPbkdf1Context( EVP_md2(), this, type ); else if ( type == "pbkdf2(sha1)" ) return new opensslPbkdf2Context( this, type ); else if ( type == "hmac(md5)" ) return new opensslHMACContext( EVP_md5(), this, type ); else if ( type == "hmac(sha1)" ) return new opensslHMACContext( EVP_sha1(),this, type ); #ifdef SHA224_DIGEST_LENGTH else if ( type == "hmac(sha224)" ) return new opensslHMACContext( EVP_sha224(), this, type); #endif #ifdef SHA256_DIGEST_LENGTH else if ( type == "hmac(sha256)" ) return new opensslHMACContext( EVP_sha256(), this, type); #endif #ifdef SHA384_DIGEST_LENGTH else if ( type == "hmac(sha384)" ) return new opensslHMACContext( EVP_sha384(), this, type); #endif #ifdef SHA512_DIGEST_LENGTH else if ( type == "hmac(sha512)" ) return new opensslHMACContext( EVP_sha512(), this, type); #endif else if ( type == "hmac(ripemd160)" ) return new opensslHMACContext( EVP_ripemd160(), this, type ); else if ( type == "aes128-ecb" ) return new opensslCipherContext( EVP_aes_128_ecb(), 0, this, type); else if ( type == "aes128-cfb" ) return new opensslCipherContext( EVP_aes_128_cfb(), 0, this, type); else if ( type == "aes128-cbc" ) return new opensslCipherContext( EVP_aes_128_cbc(), 0, this, type); else if ( type == "aes128-cbc-pkcs7" ) return new opensslCipherContext( EVP_aes_128_cbc(), 1, this, type); else if ( type == "aes128-ofb" ) return new opensslCipherContext( EVP_aes_128_ofb(), 0, this, type); else if ( type == "aes192-ecb" ) return new opensslCipherContext( EVP_aes_192_ecb(), 0, this, type); else if ( type == "aes192-cfb" ) return new opensslCipherContext( EVP_aes_192_cfb(), 0, this, type); else if ( type == "aes192-cbc" ) return new opensslCipherContext( EVP_aes_192_cbc(), 0, this, type); else if ( type == "aes192-cbc-pkcs7" ) return new opensslCipherContext( EVP_aes_192_cbc(), 1, this, type); else if ( type == "aes192-ofb" ) return new opensslCipherContext( EVP_aes_192_ofb(), 0, this, type); else if ( type == "aes256-ecb" ) return new opensslCipherContext( EVP_aes_256_ecb(), 0, this, type); else if ( type == "aes256-cfb" ) return new opensslCipherContext( EVP_aes_256_cfb(), 0, this, type); else if ( type == "aes256-cbc" ) return new opensslCipherContext( EVP_aes_256_cbc(), 0, this, type); else if ( type == "aes256-cbc-pkcs7" ) return new opensslCipherContext( EVP_aes_256_cbc(), 1, this, type); else if ( type == "aes256-ofb" ) return new opensslCipherContext( EVP_aes_256_ofb(), 0, this, type); else if ( type == "blowfish-ecb" ) return new opensslCipherContext( EVP_bf_ecb(), 0, this, type); else if ( type == "blowfish-cfb" ) return new opensslCipherContext( EVP_bf_cfb(), 0, this, type); else if ( type == "blowfish-ofb" ) return new opensslCipherContext( EVP_bf_ofb(), 0, this, type); else if ( type == "blowfish-cbc" ) return new opensslCipherContext( EVP_bf_cbc(), 0, this, type); else if ( type == "blowfish-cbc-pkcs7" ) return new opensslCipherContext( EVP_bf_cbc(), 1, this, type); else if ( type == "tripledes-ecb" ) return new opensslCipherContext( EVP_des_ede3(), 0, this, type); else if ( type == "tripledes-cbc" ) return new opensslCipherContext( EVP_des_ede3_cbc(), 0, this, type); else if ( type == "des-ecb" ) return new opensslCipherContext( EVP_des_ecb(), 0, this, type); else if ( type == "des-ecb-pkcs7" ) return new opensslCipherContext( EVP_des_ecb(), 1, this, type); else if ( type == "des-cbc" ) return new opensslCipherContext( EVP_des_cbc(), 0, this, type); else if ( type == "des-cbc-pkcs7" ) return new opensslCipherContext( EVP_des_cbc(), 1, this, type); else if ( type == "des-cfb" ) return new opensslCipherContext( EVP_des_cfb(), 0, this, type); else if ( type == "des-ofb" ) return new opensslCipherContext( EVP_des_ofb(), 0, this, type); else if ( type == "cast5-ecb" ) return new opensslCipherContext( EVP_cast5_ecb(), 0, this, type); else if ( type == "cast5-cbc" ) return new opensslCipherContext( EVP_cast5_cbc(), 0, this, type); else if ( type == "cast5-cbc-pkcs7" ) return new opensslCipherContext( EVP_cast5_cbc(), 1, this, type); else if ( type == "cast5-cfb" ) return new opensslCipherContext( EVP_cast5_cfb(), 0, this, type); else if ( type == "cast5-ofb" ) return new opensslCipherContext( EVP_cast5_ofb(), 0, this, type); else if ( type == "pkey" ) return new MyPKeyContext( this ); else if ( type == "dlgroup" ) return new MyDLGroup( this ); else if ( type == "rsa" ) return new RSAKey( this ); else if ( type == "dsa" ) return new DSAKey( this ); else if ( type == "dh" ) return new DHKey( this ); else if ( type == "cert" ) return new MyCertContext( this ); else if ( type == "csr" ) return new MyCSRContext( this ); else if ( type == "crl" ) return new MyCRLContext( this ); else if ( type == "certcollection" ) return new MyCertCollectionContext( this ); else if ( type == "pkcs12" ) return new MyPKCS12Context( this ); else if ( type == "tls" ) return new MyTLSContext( this ); else if ( type == "cms" ) return new CMSContext( this ); else if ( type == "ca" ) return new MyCAContext( this ); return 0; } }; class opensslPlugin : public QObject, public QCAPlugin { Q_OBJECT Q_INTERFACES(QCAPlugin) public: virtual Provider *createProvider() { return new opensslProvider; } }; #include "qca-ossl.moc" Q_EXPORT_PLUGIN2(qca_ossl, opensslPlugin) psi-0.14/third-party/qca/qca/0000755000175000017500000000000011305557613014120 5ustar janjanpsi-0.14/third-party/qca/qca/certs/0000755000175000017500000000000011305557613015240 5ustar janjanpsi-0.14/third-party/qca/qca/certs/rootcerts.pem0000644000175000017500000057114111305557613020000 0ustar janjan-----BEGIN CERTIFICATE----- MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0 MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII 0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3 YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc 1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5 1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P 9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa /RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei gQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG 7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ qdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG 9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw gYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3Rv bjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJv b3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05 OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkG A1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09N LCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkB FhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM 0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFG PR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGU LOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZs iSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU +/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYB Af8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOir vRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZ w8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8 eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/ O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i +DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F 5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG 9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl 5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi 3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+ QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG 9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ 2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL 553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q 10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR 4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx lA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 DzFc6PLZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn jBJ7xUS0rg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY oJ2daZH9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP T8qAkbYp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs 2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO 8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u 7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ +mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c 2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN 95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd 2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo 6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux 5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7 pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a EkP/TOYGJqibGapEPHayXOw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy vUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc 58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv 8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN /Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy 0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1 MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i /SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU 58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E 1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJX VzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBD QXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoX DTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1Rl ZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNU ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oT CjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P 6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwM jmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX 2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2N R47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5j rEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNV HSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQa gfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1 bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0 ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHBy YWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1Rl ZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rl cm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0 L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQx CzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNV HSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJ KoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktTo Qb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2 jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe 1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5 mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYc tmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC +Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X 7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz 43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV 6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH 1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF 62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh 4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G 87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i 2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no xqE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUFADCB wTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTwwOgYDVQQL EzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1 dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1OTU5WjCBpTEXMBUGA1UEChMO VmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx OzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5j b20vcnBhIChjKTAwMSwwKgYDVQQDEyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1 dGhvcml0eSBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVli zrQJIkRpivglWtvtDbc2fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU /OB4naCTuQk9I1F/RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11 S7zi6ESHzeZBCiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/ AgEAMEUGA1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0 cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIGCCsG AQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j b20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2DcIBcBlK0lRW HqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQnKeg3S/LvRJdrF1Ea w1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937ntag+RaypJXUie28/sJyU 58dzq6wf7iWbwBbtt8pb8BQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT 6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL 8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC 9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ CayJSdM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UEChML RW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xfQ1BTIGlu Y29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg RW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJl IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDQxNzIwMDBa Fw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UE CxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVk MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO 8GCGD9JYf9Mzly0XonUwtZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaB bL3+qPZ1V1eMkGxKwz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2 dWcTC5/oVzbIXQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4 QgEBBAQDAgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoT C0VudHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw IEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3Vy ZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEw KwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIwNDE3NTAwMFowCwYD VR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc/vuLkpyw8m4iMB0GA1Ud DgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2 fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBi24GRzsia d0Iv7L0no1MPUBvqTpLwqa+poLpIYcvvyQbvH9X07t9WLebKahlzqlO+krNQAraF JnJj2HVQYnUUt7NQGj/KEQALhUVpbbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1U yrrJzOCE98g+EZfTYAkYvAX/bIkz8OwVDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NBX0NQUyBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVu dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDcxNjE2NDBaFw0yMDAy MDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7Ny Spj10InJrWPNTTVRaoTUrcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0 iJBeAZfv6lOm3fzB3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn 5JVn1j+SgF7yNH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHd BgNVHR8EgdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0 MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5l dCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAy MDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQDAgEGMB8GA1UdIwQY MBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQWBBSEi3T9xY3A/ydtIDdF fP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4w AwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWAO9GK9Q6nIMstZVXQkvTnhLUGJoMS hAusO7JE7r3PQNsgDrpuFOow4DtifH+La3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/ GpsKkMWr2tGzhtQvJFJcem3G8v7lTRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKd zmVml64mXg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1 MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U 0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn 9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ 7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO 1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q 7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT 9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5 fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq YmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0aW9uMB4XDTAy MDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UEChMJYmVUUlVTVGVk MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl ZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALx+xDmcjOPWHIb/ymKt4H8wRXqOGrO4x/nRNv8i 805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R9U+jK7wYFuK13XneIviCfsuBH/0nLI/6 l2Qijvj/YaOcGx6Sj8CoCd8JEey3fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92B FODEPM2dMPgwqZfT7syj0B9fHBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+Ymp kbIq2eszh+6l/ePazIjmiSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7 eHgZFLL8kFKJOGJgB7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIa MA8GA1UdEwEB/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4A AAEJKIORMTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3Ig dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmljYXRpb24g UHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1l bnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVTVGVkIHdlYiBzaXRl LCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVjdHNfc2VydmljZXMvaW5k ZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3dy5iZXRydXN0ZWQuY29tL3By b2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwHQYDVR0OBBYEFEU9w6nR3D8kVpgc cxiIav+DR+22MB8GA1UdIwQYMBaAFEU9w6nR3D8kVpgccxiIav+DR+22MA4GA1Ud DwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCA WXf82n+0S9/DZEtqTg6t8n1ZdwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu6 7RMdmgduyzFiEuhjA6p9beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AY gkHNZTfqjjJ+vWuZXTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb 4cV97yHgjQ5dUX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9 CReJf8Py05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq YmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0aW9uMB4XDTAy MDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UEChMJYmVUUlVTVGVk MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl ZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1Q+xVkrYwfTVXDNvzDSduTPdQqJtO K2/b9a0cS12zqcH+e0TrW6MFDR/FNCswACnxeECypP869AGIF37m1CbTukzqMvtD d5eHI8XbQ6P1KqNRXuE70mVpflUVm3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdj DheT389Lrm5zdeDzqrmkwAkbhepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCe yv78IZTuEyhL11xeDGbu6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCkt VjMFu5dZfsZJT4nXLySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMB MIIBtwYDVR0gBIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYI KwYBBQUHAgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRp ZmljYXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0 aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGljaCBjYW4gYmUg Zm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0cHM6Ly93d3cuYmV0 cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMEIGCCsGAQUF BwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2Vz L2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQDAgAHMIGJBgNVHR8EgYEwfzB9oHug eaR3MHUxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJv b3QgQ0FzMTMwMQYDVQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1w bGVtZW50YXRpb24xDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEw ODI0MjdagQ8yMDIyMDQxMTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaA FH1w5a44iwY/qhwaj/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQw qoSEFjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIE kDANBgkqhkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ 5V04ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220Y/oz ADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2KjiS2d2k XgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFiaDrmLzfzgYYh xKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep9w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUFADBi MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENB czEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRp b24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBiMRIwEAYDVQQKEwli ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEvMC0GA1UEAxMm YmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRpb24wggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQwCY5X0LkGLG9uJIAiv11DpvpPrILn HGhwhRujbrWqeNluB0s/6d/16uhUoWGKDi9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I 1DpAa5LxmZZk3tv/ePTulh1HiXzUvrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPk tPDgaTuID0GQ+NRxQyTBjyZLO1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnU GxlkVgoZ98zh/4avflherHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8er cmsl9fNTGwxMLvF1S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIY MIICFDAMBgNVHRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+ AAADCSiDkTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5j b20vcHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjcmVh dGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRoZSB0aGVu IGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNl LCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgYW5kIHRoZSBS ZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IHRo ZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93d3cuYmV0cnVzdGVkLmNvbS9w cm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMAsGA1UdDwQEAwIBBjAfBgNVHSME GDAWgBSp7BR++dlDzFMrFK3P9/BZiUHNGTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxSt z/fwWYlBzRkwDQYJKoZIhvcNAQEFBQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g 6IHHtt9DwSwddUvUQo3neqh03GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuK mET7m9cqg5c0Lcd9NUwtNLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbd LrML3kqNWz2rDcI1UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28Bb J1zTcwfBwvNMm2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3 SK41ty8ymmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg /9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch 6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 7CAFYd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUFADA6 MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp dHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAxNDlaMDoxGTAX BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAx MDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV3f5mCc8kPD6ugU5O isRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dYrIMKo1W1exeQFYRMiu4mmdxY 78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYtbzZUaMjShFbuklNhCbM/OZuoyZu9 zp9+1BlqFikYvtc6adwlWzMaUQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAd BgNVHQ4EFgQUxMAcpAeU/c1NAdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEA Py1q4yZDlX2Jl2X7deRyHUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdN T1+nr6JGFLkM88y9am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgD mMrzVcydro7BqkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL 5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe 2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv /NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz 4iIprn2DQKi6bA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m 1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH 6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb QErNaLly7HF27FSOH4UMAWr6pjisH8SE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym 1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb 2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC 206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 +L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw RY8mkaKO/qk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h 2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq 299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd 7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw ++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8 /vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/ jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD 2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk 3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz 6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW 1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEzMDEGA1UECxMq SVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYD VQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx HjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczAeFw0wMTEyMjkwMDUzNTha Fw0yNTEyMjcwMDUzNThaMIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQg cHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMu ZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBD QXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFp bmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYP aXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJ spQgvJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQTy2nB Bt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8wHQYDVR0O BBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCCAUGAFKGtMbH5 PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQGEwJFUzESMBAGA1UE CBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJ bnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0Bt YWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxMzAxBgNVBAsTKklQUyBDQSBD aGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAxMqSVBT IENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG CCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYB BAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBC BglghkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlw cy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5pcHMuZXMv aXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYtaHR0cDovL3d3 dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/MDkGCWCGSAGG+EIB BwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3JlbmV3YWxDQUMuaHRtbD8w NwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5 Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYoaHR0cDovL3d3dy5pcHMuZXMvaXBz MjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCgLoYsaHR0cDovL3d3d2JhY2suaXBzLmVz L2lwczIwMDIvaXBzMjAwMkNBQy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1W WKJBGyi3leGmGpVfp3hAK+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfN HnNDJGD1HWHc3JagvPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvN b2ar7QMiRDjMWb2f2/YHogF/JsRj9SVCXmK9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAwNTkzOFoXDTI1MTIyNzAw NTkzOFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywS zHb5BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJZHMQ KD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzcuh9morKb adB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKbadB4CKGCARqk ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRp ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMD8GCWCG SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D TEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw czIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTEuaHRtbDBzBgNVHR8EbDBq MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEu Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy Q0xBU0UxLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuK Yn4VLenZMdMu9Ccj/1urxUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpj V4F1Wo7ojPsCwJTGKbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+ hjM+5i9Ibq9UkE6tsSU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMDE0NFoXDTI1MTIyNzAx MDE0NFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZ H49NzjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY 8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBxRiVr SXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLnev42USGj mFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGjmFsMNKGCARqk ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRp ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMD8GCWCG SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D TEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw czIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTMuaHRtbDBzBgNVHR8EbDBq MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMu Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy Q0xBU0UzLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dD qsfwfewPxqmurpYPdikc4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9 D6eSb9ijBmgpjnn1/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGy r33I6unUVtkOE7LFRVA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm SVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNTMyWhcNMjUxMjI3 MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8 m2mdd81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1e+J8 eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/2LUDnf47 3P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf473P7yiuYV3TCh ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBD QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2 b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRtbD8wOwYJYIZIAYb4QgEI BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMS5odG1s MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz MjAwMkNMQVNFQTEuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz MjAwMi9pcHMyMDAyQ0xBU0VBMS5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyA AIQVCtWYUQxkxZwCWINmyq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeF aQoO42Hu6r4okzPV7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aL H2betgPAK7N41lUH5Y85UN4HI3LmvSAUS7SG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm SVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNzUwWhcNMjUxMjI3 MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvN G7uGBiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4Ninn 6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2YZM50yz8 2l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz82l09BXW3mQKh ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBD QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2 b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRtbD8wOwYJYIZIAYb4QgEI BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMy5odG1s MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz MjAwMkNMQVNFQTMuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz MjAwMi9pcHMyMDAyQ0xBU0VBMy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca 2on0eisxeewBwMwB9dbB/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI 3y2s6Q73nMify5NF8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYS AfWRMS1Jjbs/RU4s4OjNtckUFQzjB4ObJnXv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1 gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4 Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14 cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYTAkVT MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjE0MDIGA1UECxMr SVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE0MDIG A1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMTAx OFoXDTI1MTIyNzAxMTAxOFowggEeMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFy Y2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5l dCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlw cy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3Rh bXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBU aW1lc3RhbXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0B CQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA vLjuVqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4 Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6KaFY q6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAwggR8MB0G A1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSCAUcwggFDgBSL 0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkGA1UEBhMCRVMxEjAQ BgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJ UFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJp cHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMg Q0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQD EytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4w HAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYD VR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlw cy5lczBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwWGmh0 dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFodHRwOi8v d3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMEUGCWCG SAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25U aW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUWM2h0dHA6Ly93d3cuaXBz LmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGluZy5odG1sPzBABglghkgBhvhC AQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lUaW1lc3RhbXBp bmcuaHRtbDB/BgNVHR8EeDB2MDegNaAzhjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMy MDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFj ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEF BQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI hvcNAQEFBQADgYEAZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk3 6MNbsMRnLWhasl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I 3pGW7hdbrqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK SnQ2+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp +ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og /zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB 4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd 8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A 4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd +LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B 4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG 29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk 3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt 5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s 3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu 8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ 3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA 7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k /rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy 7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a 0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ 2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr 2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s 2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 BKNDLdr8C2LqL19iUw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK 4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv 2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM 1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws 6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u 7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn 0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t 3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo 5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU 4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY 83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 macqaJVmlaut74nLYKkGEsaUR+ko -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi 3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP 0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK 8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS NitjrFgBazMpUIaD8QFI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC 2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 Fp1hBWeAyNDYpQcCNJgEjTME1A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0 Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0 OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x 18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5 yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/ YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1 ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p 00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb cCOxgN8aIDjnfg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl pYYsfPQS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0 MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5 quGnM/b9Sh/22WA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0 MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13 5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo 7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/ 0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7 nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ 33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo 19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e 3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7 XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1 JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51 b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV 9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7 kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS RGQDJereW26fyfJOrN3H -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ 6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl +zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH 6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ 2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa /FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B 8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed 2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH /M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU 9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH /nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd /ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv 2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMjCCA5ugAwIBAgIBQjANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTA0MDczMTAwMDAwMVoXDTA0 MDkwMjAwMDAwMVowPDE6MDgGA1UEAxMxTUQ1IENvbGxpc2lvbnMgSW5jLiAoaHR0 cDovL3d3dy5waHJlZWRvbS5vcmcvbWQ1KTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEAuqZZySwo1iqw+O2fRqSkN+4OGWhZ0bMDmVHWFppeN2sV4A5L9YRk+KPb QW811ZsVH9vEOFJwgZdej6C193458DKsHq1E0rP6SMPOkZvs9Jx84Vr1yDdrmoPe 58oglzFCcxWRaPSIr/koKMXpD3OwF0sTTJl10ETmfghsGvJPG0ECAwEAAaOCAiQw ggIgMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSnBGAf q3JDCMV/CJBVVhzWzuY46zAfBgNVHSMEGDAWgBS+qKB0clBrRLfJI9j7qP+zV2to bDCCAb4GCWCGSAGG+EIBDQSCAa8WggGrMwAAACdeOeCJYQ9Oo8VFCza7AdFTqsMI j2/4Tz6Hh0QR3GDg35JV+bhzG1STxZ/QRsRgtjVizbmvHKhpGslbPJY3wO1n77v+ wIucUC8pvYMino4I+qwTcKJYf2JiihH3ifbftmdZcxb7YxaKtJE4zi71tr5MpJRJ 5GURCkIVycEw4mnVRX2lJru5YexiZPA54ee8aNhQUZ4dYNPRo6cK+AMgoXABF5E2 TwJwMYaD3fcP2AcdEbMTBKXc8K5QsSgOY2kqDIJvj0cz32yiBpLxT0W+2TA2oyuM 1neuNWN/Tkyak0g22Z8CAwEAAaOBvTCBujAOBgNVHQ8BAf8EBAMCBPAwHQYDVR0O BBYEFM2mg/qlYDf3ljcXKd5BePGHiVXnMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6 Ly9jcmwuZ2VvdHJ1c3QuY29tL2NybHMvZ2xvYmFsY2ExLmNybDAfBgNVHSMEGDAW gBS+qKB0clBrRLfJI9j7qP+zV2tobDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB BQUHAwIwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQQFAAOBgQCnIQKN0Q6igHcl /UNgFY/s75BH1IRCFSYRHM3CPBApqbbfq1d1kdrlK7OQRRwwY1Y/itlQ+u1YbMBl rGZX3hzGdjv1AA6ORc5/TJDsK8bNs7SPYtD+t8UmckTt9phbrsvRlfXaCL5oRrF1 yOwdjx56lPGqU3iiRa5U6tGedMh2Zw== -----END CERTIFICATE----- psi-0.14/third-party/qca/qca/certs/README0000644000175000017500000000020411305557613016114 0ustar janjanrootcerts.pem is created by qca/tools/mozcerts File: mozilla/security/nss/lib/ckfw/builtins/certdata.txt Date: January 15th, 2009 psi-0.14/third-party/qca/qca/src/0000755000175000017500000000000011305557613014707 5ustar janjanpsi-0.14/third-party/qca/qca/src/qca_tools.cpp0000644000175000017500000004136411305557613017407 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_tools.h" #include "qdebug.h" #ifdef Q_OS_UNIX # include # include #endif #include "botantools/botantools.h" namespace QCA { static bool can_lock() { #ifdef Q_OS_UNIX bool ok = false; #ifdef MLOCK_NOT_VOID_PTR # define MLOCK_TYPE char * # define MLOCK_TYPE_CAST (MLOCK_TYPE) #else # define MLOCK_TYPE void * # define MLOCK_TYPE_CAST #endif MLOCK_TYPE d = MLOCK_TYPE_CAST malloc(256); if(mlock(d, 256) == 0) { munlock(d, 256); ok = true; } free(d); return ok; #else return true; #endif } // Botan shouldn't throw any exceptions in our init/deinit. static Botan::Allocator *alloc = 0; void botan_throw_abort() { fprintf(stderr, "QCA: Exception from internal Botan\n"); abort(); } bool botan_init(int prealloc, bool mmap) { // 64k minimum if(prealloc < 64) prealloc = 64; bool secmem = false; try { Botan::Builtin_Modules modules; Botan::Library_State *libstate = new Botan::Library_State(modules.mutex_factory()); libstate->prealloc_size = prealloc * 1024; Botan::set_global_state(libstate); Botan::global_state().load(modules); if(can_lock()) { Botan::global_state().set_default_allocator("locking"); secmem = true; } else if(mmap) { Botan::global_state().set_default_allocator("mmap"); secmem = true; } alloc = Botan::Allocator::get(true); } catch(std::exception &) { fprintf(stderr, "QCA: Error initializing internal Botan\n"); abort(); } return secmem; } void botan_deinit() { try { alloc = 0; Botan::set_global_state(0); } catch(std::exception &) { botan_throw_abort(); } } void *botan_secure_alloc(int bytes) { try { return alloc->allocate((Botan::u32bit)bytes); } catch(std::exception &) { botan_throw_abort(); } return 0; // never get here } void botan_secure_free(void *p, int bytes) { try { alloc->deallocate(p, (Botan::u32bit)bytes); } catch(std::exception &) { botan_throw_abort(); } } } // end namespace QCA void *qca_secure_alloc(int bytes) { // allocate enough room to store a size value in front, return a pointer after it char *c = (char *)QCA::botan_secure_alloc(bytes + sizeof(int)); ((int *)c)[0] = bytes + sizeof(int); return c + sizeof(int); } void qca_secure_free(void *p) { // backtrack to read the size value char *c = (char *)p; c -= sizeof(int); int bytes = ((int *)c)[0]; QCA::botan_secure_free(c, bytes); } void *qca_secure_realloc(void *p, int bytes) { // if null, do a plain alloc (just like how realloc() works) if(!p) return qca_secure_alloc(bytes); // backtrack to read the size value char *c = (char *)p; c -= sizeof(int); int oldsize = ((int *)c)[0] - sizeof(int); // alloc the new chunk char *new_p = (char *)qca_secure_alloc(bytes); if(!new_p) return 0; // move over the memory from the original block memmove(new_p, p, qMin(oldsize, bytes)); // free the original qca_secure_free(p); // done return new_p; } namespace QCA { // secure or non-secure buffer, with trailing 0-byte. // buffer size of 0 is okay (sbuf/qbuf will be 0). struct alloc_info { bool sec; char *data; int size; // internal Botan::SecureVector *sbuf; QByteArray *qbuf; }; // note: these functions don't return error if memory allocation/resizing // fails.. maybe fix this someday? // ai: uninitialized // size: >= 0 // note: memory will be initially zero'd out static bool ai_new(alloc_info *ai, int size, bool sec); // ai: uninitialized // from: initialized static bool ai_copy(alloc_info *ai, const alloc_info *from); // ai: initialized // new_size: >= 0 static bool ai_resize(alloc_info *ai, int new_size); // ai: initialized static void ai_delete(alloc_info *ai); bool ai_new(alloc_info *ai, int size, bool sec) { if(size < 0) return false; ai->size = size; ai->sec = sec; if(size == 0) { ai->sbuf = 0; ai->qbuf = 0; ai->data = 0; return true; } if(sec) { try { ai->sbuf = new Botan::SecureVector((Botan::u32bit)size + 1); } catch(std::exception &) { botan_throw_abort(); return false; // never get here } (*(ai->sbuf))[size] = 0; ai->qbuf = 0; Botan::byte *bp = (Botan::byte *)(*(ai->sbuf)); ai->data = (char *)bp; } else { ai->sbuf = 0; ai->qbuf = new QByteArray(size, 0); ai->data = ai->qbuf->data(); } return true; } bool ai_copy(alloc_info *ai, const alloc_info *from) { ai->size = from->size; ai->sec = from->sec; if(ai->size == 0) { ai->sbuf = 0; ai->qbuf = 0; ai->data = 0; return true; } if(ai->sec) { try { ai->sbuf = new Botan::SecureVector(*(from->sbuf)); } catch(std::exception &) { botan_throw_abort(); return false; // never get here } ai->qbuf = 0; Botan::byte *bp = (Botan::byte *)(*(ai->sbuf)); ai->data = (char *)bp; } else { ai->sbuf = 0; ai->qbuf = new QByteArray(*(from->qbuf)); ai->data = ai->qbuf->data(); } return true; } bool ai_resize(alloc_info *ai, int new_size) { if(new_size < 0) return false; // new size is empty if(new_size == 0) { // we currently aren't empty if(ai->size > 0) { if(ai->sec) { delete ai->sbuf; ai->sbuf = 0; } else { delete ai->qbuf; ai->qbuf = 0; } ai->size = 0; ai->data = 0; } return true; } if(ai->sec) { Botan::SecureVector *new_buf; try { new_buf = new Botan::SecureVector((Botan::u32bit)new_size + 1); } catch(std::exception &) { botan_throw_abort(); return false; // never get here } Botan::byte *new_p = (Botan::byte *)(*new_buf); if(ai->size > 0) { const Botan::byte *old_p = (const Botan::byte *)(*(ai->sbuf)); memcpy(new_p, old_p, qMin(new_size, ai->size)); delete ai->sbuf; } ai->sbuf = new_buf; ai->size = new_size; (*(ai->sbuf))[new_size] = 0; ai->data = (char *)new_p; } else { if(ai->size > 0) ai->qbuf->resize(new_size); else ai->qbuf = new QByteArray(new_size, 0); ai->size = new_size; ai->data = ai->qbuf->data(); } return true; } void ai_delete(alloc_info *ai) { if(ai->size > 0) { if(ai->sec) delete ai->sbuf; else delete ai->qbuf; } } //---------------------------------------------------------------------------- // MemoryRegion //---------------------------------------------------------------------------- static char blank[] = ""; class MemoryRegion::Private : public QSharedData { public: alloc_info ai; Private(int size, bool sec) { ai_new(&ai, size, sec); } Private(const QByteArray &from, bool sec) { ai_new(&ai, from.size(), sec); memcpy(ai.data, from.data(), ai.size); } Private(const Private &from) : QSharedData(from) { ai_copy(&ai, &from.ai); } ~Private() { ai_delete(&ai); } bool resize(int new_size) { return ai_resize(&ai, new_size); } void setSecure(bool sec) { // if same mode, do nothing if(ai.sec == sec) return; alloc_info other; ai_new(&other, ai.size, sec); memcpy(other.data, ai.data, ai.size); ai_delete(&ai); ai = other; } }; MemoryRegion::MemoryRegion() :_secure(false), d(0) { } MemoryRegion::MemoryRegion(const char *str) :_secure(false), d(new Private(QByteArray::fromRawData(str, strlen(str)), false)) { } MemoryRegion::MemoryRegion(const QByteArray &from) :_secure(false), d(new Private(from, false)) { } MemoryRegion::MemoryRegion(const MemoryRegion &from) :_secure(from._secure), d(from.d) { } MemoryRegion::~MemoryRegion() { } MemoryRegion & MemoryRegion::operator=(const MemoryRegion &from) { _secure = from._secure; d = from.d; return *this; } MemoryRegion & MemoryRegion::operator=(const QByteArray &from) { set(from, false); return *this; } bool MemoryRegion::isNull() const { return (d ? false : true); } bool MemoryRegion::isSecure() const { return _secure; } QByteArray MemoryRegion::toByteArray() const { if(!d) return QByteArray(); if(d->ai.sec) { QByteArray buf(d->ai.size, 0); memcpy(buf.data(), d->ai.data, d->ai.size); return buf; } else { if(d->ai.size > 0) return *(d->ai.qbuf); else return QByteArray((int)0, (char)0); } } MemoryRegion::MemoryRegion(bool secure) :_secure(secure), d(0) { } MemoryRegion::MemoryRegion(int size, bool secure) :_secure(secure), d(new Private(size, secure)) { } MemoryRegion::MemoryRegion(const QByteArray &from, bool secure) :_secure(secure), d(new Private(from, secure)) { } char *MemoryRegion::data() { if(!d) return blank; return d->ai.data; } const char *MemoryRegion::data() const { if(!d) return blank; return d->ai.data; } const char *MemoryRegion::constData() const { if(!d) return blank; return d->ai.data; } char & MemoryRegion::at(int index) { return *(d->ai.data + index); } const char & MemoryRegion::at(int index) const { return *(d->ai.data + index); } int MemoryRegion::size() const { if(!d) return 0; return d->ai.size; } bool MemoryRegion::isEmpty() const { if(!d) return true; return (d->ai.size > 0 ? false : true); } bool MemoryRegion::resize(int size) { if(!d) { d = new Private(size, _secure); return true; } if(d->ai.size == size) return true; return d->resize(size); } void MemoryRegion::set(const QByteArray &from, bool secure) { _secure = secure; if(!from.isEmpty()) d = new Private(from, secure); else d = new Private(0, secure); } void MemoryRegion::setSecure(bool secure) { _secure = secure; if(!d) { d = new Private(0, secure); return; } d->setSecure(secure); } //---------------------------------------------------------------------------- // SecureArray //---------------------------------------------------------------------------- SecureArray::SecureArray() :MemoryRegion(true) { } SecureArray::SecureArray(int size, char ch) :MemoryRegion(size, true) { // ai_new fills with zeros for us if(ch != 0) fill(ch, size); } SecureArray::SecureArray(const char *str) :MemoryRegion(QByteArray::fromRawData(str, strlen(str)), true) { } SecureArray::SecureArray(const QByteArray &a) :MemoryRegion(a, true) { } SecureArray::SecureArray(const MemoryRegion &a) :MemoryRegion(a) { setSecure(true); } SecureArray::SecureArray(const SecureArray &from) :MemoryRegion(from) { } SecureArray::~SecureArray() { } SecureArray & SecureArray::operator=(const SecureArray &from) { MemoryRegion::operator=(from); return *this; } SecureArray & SecureArray::operator=(const QByteArray &from) { MemoryRegion::set(from, true); return *this; } void SecureArray::clear() { MemoryRegion::resize(0); } bool SecureArray::resize(int size) { return MemoryRegion::resize(size); } char & SecureArray::operator[](int index) { return at(index); } const char & SecureArray::operator[](int index) const { return at(index); } char & SecureArray::at(int index) { return MemoryRegion::at(index); } const char & SecureArray::at(int index) const { return MemoryRegion::at(index); } char *SecureArray::data() { return MemoryRegion::data(); } const char *SecureArray::data() const { return MemoryRegion::data(); } const char *SecureArray::constData() const { return MemoryRegion::constData(); } int SecureArray::size() const { return MemoryRegion::size(); } bool SecureArray::isEmpty() const { return MemoryRegion::isEmpty(); } QByteArray SecureArray::toByteArray() const { return MemoryRegion::toByteArray(); } SecureArray & SecureArray::append(const SecureArray &a) { int oldsize = size(); resize(oldsize + a.size()); memcpy(data() + oldsize, a.data(), a.size()); return *this; } bool SecureArray::operator==(const MemoryRegion &other) const { if(this == &other) return true; if(size() == other.size() && memcmp(data(), other.data(), size()) == 0) return true; return false; } SecureArray & SecureArray::operator+=(const SecureArray &a) { return append(a); } void SecureArray::fill(char fillChar, int fillToPosition) { int len = (fillToPosition == -1) ? size() : qMin(fillToPosition, size()); if(len > 0) memset(data(), (int)fillChar, len); } void SecureArray::set(const SecureArray &from) { *this = from; } void SecureArray::set(const QByteArray &from) { *this = from; } const SecureArray operator+(const SecureArray &a, const SecureArray &b) { SecureArray c = a; return c.append(b); } //---------------------------------------------------------------------------- // BigInteger //---------------------------------------------------------------------------- static void negate_binary(char *a, int size) { // negate = two's compliment + 1 bool done = false; for(int n = size - 1; n >= 0; --n) { a[n] = ~a[n]; if(!done) { if((unsigned char)a[n] < 0xff) { ++a[n]; done = true; } else a[n] = 0; } } } class BigInteger::Private : public QSharedData { public: Botan::BigInt n; }; BigInteger::BigInteger() { d = new Private; } BigInteger::BigInteger(int i) { d = new Private; if(i < 0) { d->n = Botan::BigInt(i * (-1)); d->n.set_sign(Botan::BigInt::Negative); } else { d->n = Botan::BigInt(i); d->n.set_sign(Botan::BigInt::Positive); } } BigInteger::BigInteger(const char *c) { d = new Private; fromString(QString(c)); } BigInteger::BigInteger(const QString &s) { d = new Private; fromString(s); } BigInteger::BigInteger(const SecureArray &a) { d = new Private; fromArray(a); } BigInteger::BigInteger(const BigInteger &from) { *this = from; } BigInteger::~BigInteger() { } BigInteger & BigInteger::operator=(const BigInteger &from) { d = from.d; return *this; } BigInteger & BigInteger::operator+=(const BigInteger &i) { d->n += i.d->n; return *this; } BigInteger & BigInteger::operator-=(const BigInteger &i) { d->n -= i.d->n; return *this; } BigInteger & BigInteger::operator*=(const BigInteger &i) { d->n *= i.d->n; return *this; } BigInteger & BigInteger::operator/=(const BigInteger &i) { try { d->n /= i.d->n; } catch(std::exception &) { fprintf(stderr, "QCA: Botan integer division error\n"); abort(); } return *this; } BigInteger & BigInteger::operator%=(const BigInteger &i) { try { d->n %= i.d->n; } catch(std::exception &) { fprintf(stderr, "QCA: Botan integer division error\n"); abort(); } return *this; } BigInteger & BigInteger::operator=(const QString &s) { fromString(s); return *this; } int BigInteger::compare(const BigInteger &n) const { return ( (d->n).cmp( n.d->n, true) ); } QTextStream &operator<<(QTextStream &stream, const BigInteger& b) { stream << b.toString(); return stream; } SecureArray BigInteger::toArray() const { int size = d->n.encoded_size(Botan::BigInt::Binary); // return at least 8 bits if(size == 0) { SecureArray a(1); a[0] = 0; return a; } int offset = 0; SecureArray a; // make room for a sign bit if needed if(d->n.get_bit((size * 8) - 1)) { ++size; a.resize(size); a[0] = 0; ++offset; } else a.resize(size); Botan::BigInt::encode((Botan::byte *)a.data() + offset, d->n, Botan::BigInt::Binary); if(d->n.is_negative()) negate_binary(a.data(), a.size()); return a; } void BigInteger::fromArray(const SecureArray &_a) { if(_a.isEmpty()) { d->n = Botan::BigInt(0); return; } SecureArray a = _a; Botan::BigInt::Sign sign = Botan::BigInt::Positive; if(a[0] & 0x80) sign = Botan::BigInt::Negative; if(sign == Botan::BigInt::Negative) negate_binary(a.data(), a.size()); d->n = Botan::BigInt::decode((const Botan::byte *)a.data(), a.size(), Botan::BigInt::Binary); d->n.set_sign(sign); } QString BigInteger::toString() const { QByteArray cs; try { cs.resize(d->n.encoded_size(Botan::BigInt::Decimal)); Botan::BigInt::encode((Botan::byte *)cs.data(), d->n, Botan::BigInt::Decimal); } catch(std::exception &) { return QString(); } QString str; if(d->n.is_negative()) str += '-'; str += QString::fromLatin1(cs); return str; } bool BigInteger::fromString(const QString &s) { if(s.isEmpty()) return false; QByteArray cs = s.toLatin1(); bool neg = false; if(s[0] == '-') neg = true; try { d->n = Botan::BigInt::decode((const Botan::byte *)cs.data() + (neg ? 1 : 0), cs.length() - (neg ? 1 : 0), Botan::BigInt::Decimal); } catch(std::exception &) { return false; } if(neg) d->n.set_sign(Botan::BigInt::Negative); else d->n.set_sign(Botan::BigInt::Positive); return true; } } psi-0.14/third-party/qca/qca/src/qca_plugin.h0000644000175000017500000000411311305557613017201 0ustar janjan/* * qca_plugin.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef QCA_PLUGIN_H #define QCA_PLUGIN_H // NOTE: this API is private to QCA #include "qca_core.h" #include namespace QCA { class ProviderItem; class ProviderManager { public: ProviderManager(); ~ProviderManager(); void scan(); bool add(Provider *p, int priority); void unload(const QString &name); void unloadAll(); void setDefault(Provider *p); Provider *find(Provider *p) const; Provider *find(const QString &name) const; Provider *findFor(const QString &name, const QString &type) const; void changePriority(const QString &name, int priority); int getPriority(const QString &name); QStringList allFeatures() const; ProviderList providers() const; static void mergeFeatures(QStringList *a, const QStringList &b); QString diagnosticText() const; void appendDiagnosticText(const QString &str); void clearDiagnosticText(); private: mutable QMutex logMutex, providerMutex; QString dtext; QList providerItemList; ProviderList providerList; Provider *def; bool scanned_static; void addItem(ProviderItem *i, int priority); bool haveAlready(const QString &name) const; int get_default_priority(const QString &name) const; }; } #endif psi-0.14/third-party/qca/qca/src/qca_keystore.cpp0000644000175000017500000010675711305557613020124 0ustar janjan/* * Copyright (C) 2003-2008 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_keystore.h" #include #include #include #include #include #include #include // abort #include // fprintf #include "qcaprovider.h" Q_DECLARE_METATYPE(QCA::KeyStoreEntry) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QCA::KeyBundle) Q_DECLARE_METATYPE(QCA::Certificate) Q_DECLARE_METATYPE(QCA::CRL) Q_DECLARE_METATYPE(QCA::PGPKey) namespace QCA { Provider::Context *getContext(const QString &type, Provider *p); // from qca_plugin.cpp QString truncate_log(const QString &in, int size); /* How this stuff works: KeyStoreListContext is queried for a list of store context ids. A signal is used to indicate when the list may have changed, so polling for changes is not necessary. Context ids change for every new presence of a store. Even if a user removes and inserts the same smart card device, which has the same storeId, the context id will ALWAYS be different. If a previously known context id is missing from a later queried list, then it means the associated store is unavailable. It is recommended that the provider just use a counter for the contextId, incrementing the value anytime a new context is made. KeyStoreTracker manages all of the keystore stuff, and exists in its own thread (called the tracker thread). All of the KeyStoreListContext objects exist in the tracker thread. */ /* scenarios to handle: - ksm.start shouldn't block - keystore in available list, but gone by the time it is requested - keystore is unavailable during a call to a keystoreentry method - keystore/keystoreentry methods called simultaneously from different threads - and of course, objects from keystores should work, despite being created in the keystore thread */ //---------------------------------------------------------------------------- // KeyStoreTracker //---------------------------------------------------------------------------- static int tracker_id_at = 0; class KeyStoreTracker : public QObject { Q_OBJECT public: static KeyStoreTracker *self; class Item { public: // combine keystore owner and contextid into a single id int trackerId; // number of times the keystore has been updated int updateCount; // keystore context KeyStoreListContext *owner; int storeContextId; // properties QString storeId; QString name; KeyStore::Type type; bool isReadOnly; Item() : trackerId(-1), updateCount(0), owner(0), storeContextId(-1) { } }; QMutex m; QSet sources; QSet busySources; QList items; QString dtext; bool startedAll; bool busy; QMutex updateMutex; KeyStoreTracker() { self = this; qRegisterMetaType(); qRegisterMetaType< QList >(); qRegisterMetaType< QList >(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); connect(this, SIGNAL(updated_p()), SLOT(updated_locked()), Qt::QueuedConnection); startedAll = false; busy = true; // we start out busy } ~KeyStoreTracker() { qDeleteAll(sources); self = 0; } static KeyStoreTracker *instance() { return self; } // thread-safe bool isBusy() { QMutexLocker locker(&m); return busy; } // thread-safe QList getItems() { QMutexLocker locker(&m); return items; } // thread-safe QString getDText() { QMutexLocker locker(&m); return dtext; } // thread-safe void clearDText() { QMutexLocker locker(&m); dtext.clear(); } // thread-safe void addTarget(QObject *ksm) { QMutexLocker locker(&updateMutex); ksm->connect(this, SIGNAL(updated()), SLOT(tracker_updated()), Qt::DirectConnection); } // thread-safe void removeTarget(QObject *ksm) { QMutexLocker locker(&updateMutex); disconnect(ksm); } public slots: void spinEventLoop() { QAbstractEventDispatcher::instance()->processEvents(QEventLoop::AllEvents); } void start() { // grab providers (and default) ProviderList list = providers(); list.append(defaultProvider()); for(int n = 0; n < list.count(); ++n) { Provider *p = list[n]; if(p->features().contains("keystorelist") && !haveProviderSource(p)) startProvider(p); } startedAll = true; } void start(const QString &provider) { // grab providers (and default) ProviderList list = providers(); list.append(defaultProvider()); Provider *p = 0; for(int n = 0; n < list.count(); ++n) { if(list[n]->name() == provider) { p = list[n]; break; } } if(p && p->features().contains("keystorelist") && !haveProviderSource(p)) startProvider(p); } void scan() { if(startedAll) start(); } QList entryList(int trackerId) { QList out; int at = findItem(trackerId); if(at == -1) return out; Item &i = items[at]; QList list = i.owner->entryList(i.storeContextId); for(int n = 0; n < list.count(); ++n) { KeyStoreEntry entry; entry.change(list[n]); out.append(entry); } return out; } QList entryTypes(int trackerId) { QList out; int at = findItem(trackerId); if(at == -1) return out; Item &i = items[at]; return i.owner->entryTypes(i.storeContextId); } // hack with void * void *entry(const QString &storeId, const QString &entryId) { KeyStoreListContext *c = 0; int contextId = -1; m.lock(); foreach(const Item &i, items) { if(i.storeId == storeId) { c = i.owner; contextId = i.storeContextId; break; } } m.unlock(); if(!c) return 0; return c->entry(contextId, entryId); } // hack with void * void *entryPassive(const QString &serialized) { foreach(KeyStoreListContext *ksl, sources) { // "is this yours?" KeyStoreEntryContext *e = ksl->entryPassive(serialized); if(e) return e; } return 0; } QString writeEntry(int trackerId, const QVariant &v) { int at = findItem(trackerId); if(at == -1) return QString(); Item &i = items[at]; if(qVariantCanConvert(v)) return i.owner->writeEntry(i.storeContextId, qVariantValue(v)); else if(qVariantCanConvert(v)) return i.owner->writeEntry(i.storeContextId, qVariantValue(v)); else if(qVariantCanConvert(v)) return i.owner->writeEntry(i.storeContextId, qVariantValue(v)); else if(qVariantCanConvert(v)) return i.owner->writeEntry(i.storeContextId, qVariantValue(v)); else return QString(); } QString writeEntry(int trackerId, const QCA::KeyBundle &v) { int at = findItem(trackerId); if(at == -1) return QString(); Item &i = items[at]; return i.owner->writeEntry(i.storeContextId, v); } QString writeEntry(int trackerId, const QCA::Certificate &v) { int at = findItem(trackerId); if(at == -1) return QString(); Item &i = items[at]; return i.owner->writeEntry(i.storeContextId, v); } QString writeEntry(int trackerId, const QCA::CRL &v) { int at = findItem(trackerId); if(at == -1) return QString(); Item &i = items[at]; return i.owner->writeEntry(i.storeContextId, v); } QString writeEntry(int trackerId, const QCA::PGPKey &v) { int at = findItem(trackerId); if(at == -1) return QString(); Item &i = items[at]; return i.owner->writeEntry(i.storeContextId, v); } bool removeEntry(int trackerId, const QString &entryId) { int at = findItem(trackerId); if(at == -1) return false; Item &i = items[at]; return i.owner->removeEntry(i.storeContextId, entryId); } signals: // emit this when items or busy state changes void updated(); void updated_p(); private slots: void updated_locked() { QMutexLocker locker(&updateMutex); emit updated(); } private: bool haveProviderSource(Provider *p) const { foreach(KeyStoreListContext *ksl, sources) { if(ksl->provider() == p) return true; } return false; } int findItem(int trackerId) { for(int n = 0; n < items.count(); ++n) { if(items[n].trackerId == trackerId) return n; } return -1; } void startProvider(Provider *p) { KeyStoreListContext *c = static_cast(getContext("keystorelist", p)); if(!c) return; sources += c; busySources += c; connect(c, SIGNAL(busyStart()), SLOT(ksl_busyStart())); connect(c, SIGNAL(busyEnd()), SLOT(ksl_busyEnd())); connect(c, SIGNAL(updated()), SLOT(ksl_updated())); connect(c, SIGNAL(diagnosticText(const QString &)), SLOT(ksl_diagnosticText(const QString &))); connect(c, SIGNAL(storeUpdated(int)), SLOT(ksl_storeUpdated(int))); c->start(); c->setUpdatesEnabled(true); QCA_logTextMessage(QString("keystore: startProvider %1").arg(p->name()), Logger::Information); } bool updateStores(KeyStoreListContext *c) { bool changed = false; QMutexLocker locker(&m); QList keyStores = c->keyStores(); // remove any contexts that are gone for(int n = 0; n < items.count(); ++n) { if(items[n].owner == c && !keyStores.contains(items[n].storeContextId)) { QCA_logTextMessage(QString("keystore: updateStores remove %1").arg(items[n].storeContextId), Logger::Information); items.removeAt(n); --n; // adjust position changed = true; } } // handle add/updates foreach(int id, keyStores) { // do we have it already? int at = -1; for(int n = 0; n < items.count(); ++n) { if(items[n].owner == c && items[n].storeContextId == id) { at = n; break; } } // if so, update it if(at != -1) { Item &i = items[at]; QString name = c->name(id); bool isReadOnly = c->isReadOnly(id); if(i.name != name || i.isReadOnly != isReadOnly) { QCA_logTextMessage(QString("keystore: updateStores update %1").arg(id), Logger::Information); i.name = name; i.isReadOnly = isReadOnly; changed = true; } } // otherwise, add it else { QCA_logTextMessage(QString("keystore: updateStores add %1").arg(id), Logger::Information); Item i; i.trackerId = tracker_id_at++; i.updateCount = 0; i.owner = c; i.storeContextId = id; i.storeId = c->storeId(id); i.name = c->name(id); i.type = c->type(id); i.isReadOnly = c->isReadOnly(id); items += i; changed = true; } } return changed; } private slots: void ksl_busyStart() { KeyStoreListContext *c = (KeyStoreListContext *)sender(); QCA_logTextMessage(QString("keystore: ksl_busyStart %1").arg(c->provider()->name()), Logger::Information); if(!busySources.contains(c)) { busySources += c; QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information); emit updated_p(); } } void ksl_busyEnd() { KeyStoreListContext *c = (KeyStoreListContext *)sender(); QCA_logTextMessage(QString("keystore: ksl_busyEnd %1").arg(c->provider()->name()), Logger::Information); busySources.remove(c); bool changed = updateStores(c); bool any_busy = !busySources.isEmpty(); if(!any_busy) { m.lock(); busy = false; m.unlock(); } if(!any_busy || changed) { QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information); emit updated_p(); } } void ksl_updated() { KeyStoreListContext *c = (KeyStoreListContext *)sender(); QCA_logTextMessage(QString("keystore: ksl_updated %1").arg(c->provider()->name()), Logger::Information); bool changed = updateStores(c); if(changed) { QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information); emit updated_p(); } } void ksl_diagnosticText(const QString &str) { QMutexLocker locker(&m); dtext += str; dtext = truncate_log(dtext, 100000); } void ksl_storeUpdated(int id) { KeyStoreListContext *c = (KeyStoreListContext *)sender(); QCA_logTextMessage(QString("keystore: ksl_storeUpdated %1 %2").arg(c->provider()->name(), QString::number(id)), Logger::Information); QMutexLocker locker(&m); for(int n = 0; n < items.count(); ++n) { Item &i = items[n]; if(i.owner == c && i.storeContextId == id) { ++i.updateCount; QCA_logTextMessage(QString("keystore: %1 updateCount = %2").arg(i.name, QString::number(i.updateCount)), Logger::Information); QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information); emit updated_p(); return; } } } }; KeyStoreTracker *KeyStoreTracker::self = 0; //---------------------------------------------------------------------------- // KeyStoreThread //---------------------------------------------------------------------------- class KeyStoreThread : public SyncThread { Q_OBJECT public: KeyStoreTracker *tracker; QMutex call_mutex; KeyStoreThread(QObject *parent = 0) : SyncThread(parent) { } ~KeyStoreThread() { stop(); } void atStart() { tracker = new KeyStoreTracker; } void atEnd() { delete tracker; } }; //---------------------------------------------------------------------------- // KeyStoreGlobal //---------------------------------------------------------------------------- class KeyStoreManagerGlobal; Q_GLOBAL_STATIC(QMutex, ksm_mutex) static KeyStoreManagerGlobal *g_ksm = 0; class KeyStoreManagerGlobal { public: KeyStoreThread *thread; KeyStoreManagerGlobal() { thread = new KeyStoreThread; thread->moveToThread(QCoreApplication::instance()->thread()); thread->start(); } ~KeyStoreManagerGlobal() { delete thread; } }; // this function is thread-safe static QVariant trackercall(const char *method, const QVariantList &args = QVariantList()) { QVariant ret; bool ok; g_ksm->thread->call_mutex.lock(); ret = g_ksm->thread->call(KeyStoreTracker::instance(), method, args, &ok); g_ksm->thread->call_mutex.unlock(); Q_ASSERT(ok); if(!ok) { fprintf(stderr, "QCA: KeyStoreTracker call [%s] failed.\n", method); abort(); return QVariant(); } return ret; } //---------------------------------------------------------------------------- // KeyStoreEntry //---------------------------------------------------------------------------- class KeyStoreEntry::Private { public: bool accessible; Private() { accessible = false; } }; KeyStoreEntry::KeyStoreEntry() :d(new Private) { } KeyStoreEntry::KeyStoreEntry(const QString &serialized) :d(new Private) { *this = fromString(serialized); } KeyStoreEntry::KeyStoreEntry(const KeyStoreEntry &from) :Algorithm(from), d(new Private(*from.d)) { } KeyStoreEntry::~KeyStoreEntry() { delete d; } KeyStoreEntry & KeyStoreEntry::operator=(const KeyStoreEntry &from) { Algorithm::operator=(from); *d = *from.d; return *this; } bool KeyStoreEntry::isNull() const { return (!context() ? true : false); } bool KeyStoreEntry::isAvailable() const { return static_cast(context())->isAvailable(); } bool KeyStoreEntry::isAccessible() const { return d->accessible; } KeyStoreEntry::Type KeyStoreEntry::type() const { return static_cast(context())->type(); } QString KeyStoreEntry::name() const { return static_cast(context())->name(); } QString KeyStoreEntry::id() const { return static_cast(context())->id(); } QString KeyStoreEntry::storeName() const { return static_cast(context())->storeName(); } QString KeyStoreEntry::storeId() const { return static_cast(context())->storeId(); } QString KeyStoreEntry::toString() const { return static_cast(context())->serialize(); } KeyStoreEntry KeyStoreEntry::fromString(const QString &serialized) { KeyStoreEntry e; KeyStoreEntryContext *c = (KeyStoreEntryContext *)KeyStoreTracker::instance()->entryPassive(serialized); if(c) e.change(c); return e; } KeyBundle KeyStoreEntry::keyBundle() const { return static_cast(context())->keyBundle(); } Certificate KeyStoreEntry::certificate() const { return static_cast(context())->certificate(); } CRL KeyStoreEntry::crl() const { return static_cast(context())->crl(); } PGPKey KeyStoreEntry::pgpSecretKey() const { return static_cast(context())->pgpSecretKey(); } PGPKey KeyStoreEntry::pgpPublicKey() const { return static_cast(context())->pgpPublicKey(); } bool KeyStoreEntry::ensureAvailable() { QString storeId = this->storeId(); QString entryId = id(); KeyStoreEntryContext *c = (KeyStoreEntryContext *)qVariantValue(trackercall("entry", QVariantList() << storeId << entryId)); if(c) change(c); return isAvailable(); } bool KeyStoreEntry::ensureAccess() { if(!ensureAvailable()) { d->accessible = false; return false; } bool ok = static_cast(context())->ensureAccess(); d->accessible = ok; return d->accessible; } //---------------------------------------------------------------------------- // KeyStoreEntryWatcher //---------------------------------------------------------------------------- class KeyStoreEntryWatcher::Private : public QObject { Q_OBJECT public: KeyStoreEntryWatcher *q; KeyStoreManager ksm; KeyStoreEntry entry; QString storeId, entryId; KeyStore *ks; bool avail; Private(KeyStoreEntryWatcher *_q) : QObject(_q), q(_q), ksm(this) { ks = 0; avail = false; connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ksm_available(const QString &))); } ~Private() { delete ks; } void start() { QStringList list = ksm.keyStores(); foreach(const QString &storeId, list) ksm_available(storeId); } private slots: void ksm_available(const QString &_storeId) { // we only care about one store if(_storeId == storeId) { ks = new KeyStore(storeId, &ksm); connect(ks, SIGNAL(updated()), SLOT(ks_updated())); ks->startAsynchronousMode(); } } void ks_updated() { bool found = false; QList list = ks->entryList(); foreach(const KeyStoreEntry &e, list) { if(e.id() == entryId && e.isAvailable()) { found = true; if(!avail) entry = e; break; } } if(found && !avail) { avail = true; emit q->available(); } else if(!found && avail) { avail = false; emit q->unavailable(); } } void ks_unavailable() { delete ks; ks = 0; if(avail) { avail = false; emit q->unavailable(); } } }; KeyStoreEntryWatcher::KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent) :QObject(parent) { d = new Private(this); if(!e.isNull()) { d->entry = e; d->storeId = e.storeId(); d->entryId = e.id(); d->start(); } } KeyStoreEntryWatcher::~KeyStoreEntryWatcher() { delete d; } KeyStoreEntry KeyStoreEntryWatcher::entry() const { return d->entry; } //---------------------------------------------------------------------------- // KeyStore //---------------------------------------------------------------------------- // union thingy class KeyStoreWriteEntry { public: enum Type { TypeKeyBundle, TypeCertificate, TypeCRL, TypePGPKey }; Type type; KeyBundle keyBundle; Certificate cert; CRL crl; PGPKey pgpKey; KeyStoreWriteEntry() { } KeyStoreWriteEntry(const KeyBundle &_keyBundle) :type(TypeKeyBundle), keyBundle(_keyBundle) { } KeyStoreWriteEntry(const Certificate &_cert) :type(TypeCertificate), cert(_cert) { } KeyStoreWriteEntry(const CRL &_crl) :type(TypeCRL), crl(_crl) { } KeyStoreWriteEntry(const PGPKey &_pgpKey) :type(TypePGPKey), pgpKey(_pgpKey) { } }; class KeyStoreOperation : public QThread { Q_OBJECT public: enum Type { EntryList, WriteEntry, RemoveEntry }; Type type; int trackerId; KeyStoreWriteEntry wentry; // in: WriteEntry QList entryList; // out: EntryList QString entryId; // in: RemoveEntry, out: WriteEntry bool success; // out: RemoveEntry KeyStoreOperation(QObject *parent = 0) :QThread(parent) { } ~KeyStoreOperation() { wait(); } protected: virtual void run() { if(type == EntryList) entryList = qVariantValue< QList >(trackercall("entryList", QVariantList() << trackerId)); else if(type == WriteEntry) { QVariant arg; if(wentry.type == KeyStoreWriteEntry::TypeKeyBundle) qVariantSetValue(arg, wentry.keyBundle); else if(wentry.type == KeyStoreWriteEntry::TypeCertificate) qVariantSetValue(arg, wentry.cert); else if(wentry.type == KeyStoreWriteEntry::TypeCRL) qVariantSetValue(arg, wentry.crl); else if(wentry.type == KeyStoreWriteEntry::TypePGPKey) qVariantSetValue(arg, wentry.pgpKey); // note: each variant in the argument list is resolved // to its native type. so even though it looks like // we're attempting to call a method named // writeEntry(QString,QVariant), we're actually // calling one of many possible methods, such as // writeEntry(QString,PGPKey) or // writeEntry(QString,Certificate), etc, depending // on the type of object we put in the variant. entryId = trackercall("writeEntry", QVariantList() << trackerId << arg).toString(); } else // RemoveEntry { success = trackercall("removeEntry", QVariantList() << trackerId << entryId).toBool(); } } }; class KeyStorePrivate : public QObject { Q_OBJECT public: KeyStore *q; KeyStoreManager *ksm; int trackerId; KeyStoreTracker::Item item; bool async; bool need_update; QList latestEntryList; QList ops; KeyStorePrivate(KeyStore *_q) : QObject(_q), q(_q), async(false) { } ~KeyStorePrivate() { qDeleteAll(ops); } // implemented below, after KeyStorePrivate is declared void reg(); void unreg(); KeyStoreTracker::Item *getItem(const QString &storeId); KeyStoreTracker::Item *getItem(int trackerId); void invalidate() { trackerId = -1; unreg(); } bool have_entryList_op() const { foreach(KeyStoreOperation *op, ops) { if(op->type == KeyStoreOperation::EntryList) return true; } return false; } void handle_updated() { if(async) { if(!have_entryList_op()) async_entryList(); else need_update = true; } else emit q->updated(); } void async_entryList() { KeyStoreOperation *op = new KeyStoreOperation(this); // use queued for signal-safety connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection); op->type = KeyStoreOperation::EntryList; op->trackerId = trackerId; ops += op; op->start(); } void async_writeEntry(const KeyStoreWriteEntry &wentry) { KeyStoreOperation *op = new KeyStoreOperation(this); // use queued for signal-safety connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection); op->type = KeyStoreOperation::WriteEntry; op->trackerId = trackerId; op->wentry = wentry; ops += op; op->start(); } void async_removeEntry(const QString &entryId) { KeyStoreOperation *op = new KeyStoreOperation(this); // use queued for signal-safety connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection); op->type = KeyStoreOperation::RemoveEntry; op->trackerId = trackerId; op->entryId = entryId; ops += op; op->start(); } private slots: void op_finished() { KeyStoreOperation *op = (KeyStoreOperation *)sender(); if(op->type == KeyStoreOperation::EntryList) { latestEntryList = op->entryList; ops.removeAll(op); delete op; if(need_update) { need_update = false; async_entryList(); } emit q->updated(); } else if(op->type == KeyStoreOperation::WriteEntry) { QString entryId = op->entryId; ops.removeAll(op); delete op; emit q->entryWritten(entryId); } else // RemoveEntry { bool success = op->success; ops.removeAll(op); delete op; emit q->entryRemoved(success); } } }; KeyStore::KeyStore(const QString &id, KeyStoreManager *keyStoreManager) :QObject(keyStoreManager) { d = new KeyStorePrivate(this); d->ksm = keyStoreManager; KeyStoreTracker::Item *i = d->getItem(id); if(i) { d->trackerId = i->trackerId; d->item = *i; d->reg(); } else d->trackerId = -1; } KeyStore::~KeyStore() { if(d->trackerId != -1) d->unreg(); delete d; } bool KeyStore::isValid() const { return (d->getItem(d->trackerId) ? true : false); } KeyStore::Type KeyStore::type() const { return d->item.type; } QString KeyStore::name() const { return d->item.name; } QString KeyStore::id() const { return d->item.storeId; } bool KeyStore::isReadOnly() const { return d->item.isReadOnly; } void KeyStore::startAsynchronousMode() { if(d->async) return; d->async = true; // initial entrylist d->need_update = false; d->async_entryList(); } QList KeyStore::entryList() const { if(d->async) return d->latestEntryList; if(d->trackerId == -1) return QList(); return qVariantValue< QList >(trackercall("entryList", QVariantList() << d->trackerId)); } bool KeyStore::holdsTrustedCertificates() const { QList list; if(d->trackerId == -1) return false; list = qVariantValue< QList >(trackercall("entryTypes", QVariantList() << d->trackerId)); if(list.contains(KeyStoreEntry::TypeCertificate) || list.contains(KeyStoreEntry::TypeCRL)) return true; return false; } bool KeyStore::holdsIdentities() const { QList list; if(d->trackerId == -1) return false; list = qVariantValue< QList >(trackercall("entryTypes", QVariantList() << d->trackerId)); if(list.contains(KeyStoreEntry::TypeKeyBundle) || list.contains(KeyStoreEntry::TypePGPSecretKey)) return true; return false; } bool KeyStore::holdsPGPPublicKeys() const { QList list; if(d->trackerId == -1) return false; list = qVariantValue< QList >(trackercall("entryTypes", QVariantList() << d->trackerId)); if(list.contains(KeyStoreEntry::TypePGPPublicKey)) return true; return false; } QString KeyStore::writeEntry(const KeyBundle &kb) { if(d->async) { d->async_writeEntry(KeyStoreWriteEntry(kb)); return QString(); } else { QVariant arg; qVariantSetValue(arg, kb); return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); } } QString KeyStore::writeEntry(const Certificate &cert) { if(d->async) { d->async_writeEntry(KeyStoreWriteEntry(cert)); return QString(); } else { QVariant arg; qVariantSetValue(arg, cert); return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); } } QString KeyStore::writeEntry(const CRL &crl) { if(d->async) { d->async_writeEntry(KeyStoreWriteEntry(crl)); return QString(); } else { QVariant arg; qVariantSetValue(arg, crl); return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); } } QString KeyStore::writeEntry(const PGPKey &key) { if(d->async) { d->async_writeEntry(KeyStoreWriteEntry(key)); return QString(); } else { QVariant arg; qVariantSetValue(arg, key); return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); } } bool KeyStore::removeEntry(const QString &id) { if(d->async) { d->async_removeEntry(id); return false; } else { return trackercall("removeEntry", QVariantList() << d->trackerId << id).toBool(); } } //---------------------------------------------------------------------------- // KeyStoreManager //---------------------------------------------------------------------------- static void ensure_init() { QMutexLocker locker(ksm_mutex()); if(!g_ksm) g_ksm = new KeyStoreManagerGlobal; } // static functions void KeyStoreManager::start() { ensure_init(); QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection); trackercall("spinEventLoop"); } void KeyStoreManager::start(const QString &provider) { ensure_init(); QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection, Q_ARG(QString, provider)); trackercall("spinEventLoop"); } QString KeyStoreManager::diagnosticText() { ensure_init(); // spin one event cycle in the tracker, to receive any pending text. // note that since trackercall also goes through the eventloop, // this may end up doing two rounds. probably no big deal. trackercall("spinEventLoop"); return KeyStoreTracker::instance()->getDText(); } void KeyStoreManager::clearDiagnosticText() { ensure_init(); KeyStoreTracker::instance()->clearDText(); } void KeyStoreManager::scan() { ensure_init(); QMetaObject::invokeMethod(KeyStoreTracker::instance(), "scan", Qt::QueuedConnection); } void KeyStoreManager::shutdown() { QMutexLocker locker(ksm_mutex()); delete g_ksm; g_ksm = 0; } // object class KeyStoreManagerPrivate : public QObject { Q_OBJECT public: KeyStoreManager *q; QMutex m; QWaitCondition w; bool busy; QList items; bool pending, waiting; QMultiHash keyStoreForTrackerId; QHash trackerIdForKeyStore; KeyStoreManagerPrivate(KeyStoreManager *_q) : QObject(_q), q(_q) { pending = false; waiting = false; } ~KeyStoreManagerPrivate() { // invalidate registered keystores QList list; QHashIterator it(trackerIdForKeyStore); while(it.hasNext()) { it.next(); list += it.key(); } foreach(KeyStore *ks, list) ks->d->invalidate(); } // for keystore void reg(KeyStore *ks, int trackerId) { keyStoreForTrackerId.insert(trackerId, ks); trackerIdForKeyStore.insert(ks, trackerId); } void unreg(KeyStore *ks) { int trackerId = trackerIdForKeyStore.take(ks); // this is the only way I know to remove one item from a multihash QList vals = keyStoreForTrackerId.values(trackerId); keyStoreForTrackerId.remove(trackerId); vals.removeAll(ks); foreach(KeyStore *i, vals) keyStoreForTrackerId.insert(trackerId, i); } KeyStoreTracker::Item *getItem(const QString &storeId) { for(int n = 0; n < items.count(); ++n) { KeyStoreTracker::Item *i = &items[n]; if(i->storeId == storeId) return i; } return 0; } KeyStoreTracker::Item *getItem(int trackerId) { for(int n = 0; n < items.count(); ++n) { KeyStoreTracker::Item *i = &items[n]; if(i->trackerId == trackerId) return i; } return 0; } void do_update() { // ksm doesn't have reset or state changes so we can // use QPointer here for full SS. QPointer self(this); bool newbusy = KeyStoreTracker::instance()->isBusy(); QList newitems = KeyStoreTracker::instance()->getItems(); if(!busy && newbusy) { emit q->busyStarted(); if(!self) return; } if(busy && !newbusy) { emit q->busyFinished(); if(!self) return; } QStringList here; QList changed; QList gone; // removed for(int n = 0; n < items.count(); ++n) { KeyStoreTracker::Item &i = items[n]; bool found = false; for(int k = 0; k < newitems.count(); ++k) { if(i.trackerId == newitems[k].trackerId) { found = true; break; } } if(!found) gone += i.trackerId; } // changed for(int n = 0; n < items.count(); ++n) { KeyStoreTracker::Item &i = items[n]; for(int k = 0; k < newitems.count(); ++k) { if(i.trackerId == newitems[k].trackerId) { if(i.updateCount < newitems[k].updateCount) changed += i.trackerId; break; } } } // added for(int n = 0; n < newitems.count(); ++n) { KeyStoreTracker::Item &i = newitems[n]; bool found = false; for(int k = 0; k < items.count(); ++k) { if(i.trackerId == items[k].trackerId) { found = true; break; } } if(!found) here += i.storeId; } busy = newbusy; items = newitems; // signals foreach(int trackerId, gone) { KeyStore *ks = keyStoreForTrackerId.value(trackerId); if(ks) { ks->d->invalidate(); emit ks->unavailable(); if(!self) return; } } foreach(int trackerId, changed) { KeyStore *ks = keyStoreForTrackerId.value(trackerId); if(ks) { ks->d->handle_updated(); if(!self) return; } } foreach(const QString &storeId, here) { emit q->keyStoreAvailable(storeId); if(!self) return; } } public slots: void tracker_updated() { QCA_logTextMessage(QString().sprintf("keystore: %p: tracker_updated start", q), Logger::Information); QMutexLocker locker(&m); if(!pending) { QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); pending = true; } if(waiting && !KeyStoreTracker::instance()->isBusy()) { busy = false; items = KeyStoreTracker::instance()->getItems(); w.wakeOne(); } QCA_logTextMessage(QString().sprintf("keystore: %p: tracker_updated end", q), Logger::Information); } void update() { m.lock(); pending = false; m.unlock(); do_update(); } }; // from KeyStorePrivate void KeyStorePrivate::reg() { ksm->d->reg(q, trackerId); } void KeyStorePrivate::unreg() { ksm->d->unreg(q); } KeyStoreTracker::Item *KeyStorePrivate::getItem(const QString &storeId) { return ksm->d->getItem(storeId); } KeyStoreTracker::Item *KeyStorePrivate::getItem(int trackerId) { return ksm->d->getItem(trackerId); } KeyStoreManager::KeyStoreManager(QObject *parent) :QObject(parent) { ensure_init(); d = new KeyStoreManagerPrivate(this); KeyStoreTracker::instance()->addTarget(d); sync(); } KeyStoreManager::~KeyStoreManager() { Q_ASSERT(KeyStoreTracker::instance()); KeyStoreTracker::instance()->removeTarget(d); delete d; } bool KeyStoreManager::isBusy() const { return d->busy; } void KeyStoreManager::waitForBusyFinished() { d->m.lock(); d->busy = KeyStoreTracker::instance()->isBusy(); if(d->busy) { d->waiting = true; d->w.wait(&d->m); d->waiting = false; } d->m.unlock(); } QStringList KeyStoreManager::keyStores() const { QStringList out; for(int n = 0; n < d->items.count(); ++n) out += d->items[n].storeId; return out; } void KeyStoreManager::sync() { d->busy = KeyStoreTracker::instance()->isBusy(); d->items = KeyStoreTracker::instance()->getItems(); } //---------------------------------------------------------------------------- // KeyStoreInfo //---------------------------------------------------------------------------- class KeyStoreInfo::Private : public QSharedData { public: KeyStore::Type type; QString id, name; }; KeyStoreInfo::KeyStoreInfo() { } KeyStoreInfo::KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name) :d(new Private) { d->type = type; d->id = id; d->name = name; } KeyStoreInfo::KeyStoreInfo(const KeyStoreInfo &from) :d(from.d) { } KeyStoreInfo::~KeyStoreInfo() { } KeyStoreInfo & KeyStoreInfo::operator=(const KeyStoreInfo &from) { d = from.d; return *this; } bool KeyStoreInfo::isNull() const { return (d ? false: true); } KeyStore::Type KeyStoreInfo::type() const { return d->type; } QString KeyStoreInfo::id() const { return d->id; } QString KeyStoreInfo::name() const { return d->name; } } #include "qca_keystore.moc" psi-0.14/third-party/qca/qca/src/qca_default.cpp0000644000175000017500000010403511305557613017666 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_core.h" #include #include #include "qca_textfilter.h" #include "qca_cert.h" #include "qcaprovider.h" #ifndef QCA_NO_SYSTEMSTORE # include "qca_systemstore.h" #endif #define FRIENDLY_NAMES namespace QCA { class DefaultShared { private: mutable QMutex m; bool _use_system; QString _roots_file; QStringList _skip_plugins; QStringList _plugin_priorities; public: DefaultShared() : _use_system(true) { } bool use_system() const { QMutexLocker locker(&m); return _use_system; } QString roots_file() const { QMutexLocker locker(&m); return _roots_file; } QStringList skip_plugins() const { QMutexLocker locker(&m); return _skip_plugins; } QStringList plugin_priorities() const { QMutexLocker locker(&m); return _plugin_priorities; } void set(bool use_system, const QString &roots_file, const QStringList &skip_plugins, const QStringList &plugin_priorities) { QMutexLocker locker(&m); _use_system = use_system; _roots_file = roots_file; _skip_plugins = skip_plugins; _plugin_priorities = plugin_priorities; } }; //---------------------------------------------------------------------------- // DefaultRandomContext //---------------------------------------------------------------------------- class DefaultRandomContext : public RandomContext { public: DefaultRandomContext(Provider *p) : RandomContext(p) {} virtual Provider::Context *clone() const { return new DefaultRandomContext(provider()); } virtual SecureArray nextBytes(int size) { SecureArray buf(size); for(int n = 0; n < (int)buf.size(); ++n) buf[n] = (char)qrand(); return buf; } }; //---------------------------------------------------------------------------- // DefaultMD5Context //---------------------------------------------------------------------------- /* NOTE: the following code was modified to not need BYTE_ORDER -- Justin */ /* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: qca_default.cpp 808523 2008-05-16 20:41:50Z infiniti $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef quint8 md5_byte_t; /* 8-bit byte */ typedef quint32 md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ struct md5_state_t { SecureArray sbuf; md5_word_t *count; // 2 /* message length in bits, lsw first */ md5_word_t *abcd; // 4 /* digest buffer */ md5_byte_t *buf; // 64 /* accumulate block */ md5_state_t() { sbuf.resize((6 * sizeof(md5_word_t)) + 64); setup(); } md5_state_t(const md5_state_t &from) { *this = from; } md5_state_t & operator=(const md5_state_t &from) { sbuf = from.sbuf; setup(); return *this; } inline void setup() { char *p = sbuf.data(); count = (md5_word_t *)p; abcd = (md5_word_t *)(p + (2 * sizeof(md5_word_t))); buf = (md5_byte_t *)(p + (6 * sizeof(md5_word_t))); } }; /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; /* Define storage for little-endian or both types of CPUs. */ // possible FIXME: does xbuf really need to be secured? SecureArray sxbuf(16 * sizeof(md5_word_t)); md5_word_t *xbuf = (md5_word_t *)sxbuf.data(); const md5_word_t *X; { if(QSysInfo::ByteOrder == QSysInfo::BigEndian) { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; X = xbuf; /* (dynamic only) */ for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } else /* dynamic big-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } class DefaultMD5Context : public HashContext { public: DefaultMD5Context(Provider *p) : HashContext(p, "md5") { clear(); } virtual Provider::Context *clone() const { return new DefaultMD5Context(*this); } virtual void clear() { secure = true; md5_init(&md5); } virtual void update(const MemoryRegion &in) { if(!in.isSecure()) secure = false; md5_append(&md5, (const md5_byte_t *)in.data(), in.size()); } virtual MemoryRegion final() { if(secure) { SecureArray b(16, 0); md5_finish(&md5, (md5_byte_t *)b.data()); return b; } else { QByteArray b(16, 0); md5_finish(&md5, (md5_byte_t *)b.data()); return b; } } bool secure; md5_state_t md5; }; //---------------------------------------------------------------------------- // DefaultSHA1Context //---------------------------------------------------------------------------- // SHA1 - from a public domain implementation by Steve Reid (steve@edmweb.com) #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15]^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); struct SHA1_CONTEXT { SecureArray sbuf; quint32 *state; // 5 quint32 *count; // 2 unsigned char *buffer; // 64 SHA1_CONTEXT() { sbuf.resize((7 * sizeof(quint32)) + 64); setup(); } SHA1_CONTEXT(const SHA1_CONTEXT &from) { *this = from; } SHA1_CONTEXT & operator=(const SHA1_CONTEXT &from) { sbuf = from.sbuf; setup(); return *this; } inline void setup() { char *p = sbuf.data(); state = (quint32 *)p; count = (quint32 *)(p + (5 * sizeof(quint32))); buffer = (unsigned char *)(p + (7 * sizeof(quint32))); } }; typedef union { unsigned char c[64]; quint32 l[16]; } CHAR64LONG16; class DefaultSHA1Context : public HashContext { public: SHA1_CONTEXT _context; CHAR64LONG16* block; bool secure; DefaultSHA1Context(Provider *p) : HashContext(p, "sha1") { clear(); } virtual Provider::Context *clone() const { return new DefaultSHA1Context(*this); } virtual void clear() { secure = true; sha1_init(&_context); } virtual void update(const MemoryRegion &in) { if(!in.isSecure()) secure = false; sha1_update(&_context, (unsigned char *)in.data(), (unsigned int)in.size()); } virtual MemoryRegion final() { if(secure) { SecureArray b(20, 0); sha1_final((unsigned char *)b.data(), &_context); return b; } else { QByteArray b(20, 0); sha1_final((unsigned char *)b.data(), &_context); return b; } } inline unsigned long blk0(quint32 i) { if(QSysInfo::ByteOrder == QSysInfo::BigEndian) return block->l[i]; else return (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) | (rol(block->l[i],8)&0x00FF00FF)); } // Hash a single 512-bit block. This is the core of the algorithm. void transform(quint32 state[5], unsigned char buffer[64]) { quint32 a, b, c, d, e; block = (CHAR64LONG16*)buffer; // Copy context->state[] to working vars a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; // 4 rounds of 20 operations each. Loop unrolled. R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); // Add the working vars back into context.state[] state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; // Wipe variables a = b = c = d = e = 0; } // SHA1Init - Initialize new context void sha1_init(SHA1_CONTEXT* context) { // SHA1 initialization constants context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } // Run your data through this void sha1_update(SHA1_CONTEXT* context, unsigned char* data, quint32 len) { quint32 i, j; j = (context->count[0] >> 3) & 63; if((context->count[0] += len << 3) < (len << 3)) context->count[1]++; context->count[1] += (len >> 29); if((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { transform(context->state, &data[i]); } j = 0; } else i = 0; memcpy(&context->buffer[j], &data[i], len - i); } // Add padding and return the message digest void sha1_final(unsigned char digest[20], SHA1_CONTEXT* context) { quint32 i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); // Endian independent } sha1_update(context, (unsigned char *)"\200", 1); while ((context->count[0] & 504) != 448) { sha1_update(context, (unsigned char *)"\0", 1); } sha1_update(context, finalcount, 8); // Should cause a transform() for (i = 0; i < 20; i++) { digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } // Wipe variables i = 0; memset(context->buffer, 0, 64); memset(context->state, 0, 20); memset(context->count, 0, 8); memset(&finalcount, 0, 8); } }; //---------------------------------------------------------------------------- // DefaultKeyStoreEntry //---------------------------------------------------------------------------- // this escapes colons, commas, and newlines. colons and commas so that they // are available as delimiters, and newlines so that our output can be a // single line of text. static QString escape_string(const QString &in) { QString out; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') out += "\\\\"; else if(in[n] == ':') out += "\\c"; else if(in[n] == ',') out += "\\o"; else if(in[n] == '\n') out += "\\n"; else out += in[n]; } return out; } static bool unescape_string(const QString &in, QString *_out) { QString out; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') { if(n + 1 >= in.length()) return false; if(in[n + 1] == '\\') out += '\\'; else if(in[n + 1] == 'c') out += ':'; else if(in[n + 1] == 'o') out += ','; else if(in[n + 1] == 'n') out += '\n'; else return false; ++n; } else out += in[n]; } *_out = out; return true; } static QString escape_stringlist(const QStringList &in) { QStringList list; for(int n = 0; n < in.count(); ++n) list += escape_string(in[n]); return list.join(":"); } static bool unescape_stringlist(const QString &in, QStringList *_out) { QStringList out; QStringList list = in.split(':'); for(int n = 0; n < list.count(); ++n) { QString str; if(!unescape_string(list[n], &str)) return false; out += str; } *_out = out; return true; } // serialization format is a colon separated list of 7 escaped strings // 0 - "qca_def_1" (header) // 1 - store id // 2 - store name // 3 - entry id // 4 - entry name // 5 - entry type (e.g. "cert") // 6 - string encoding of object (e.g. DER encoded in Base64) static QString entry_serialize(const QString &storeId, const QString &storeName, const QString &entryId, const QString &entryName, const QString &entryType, const QString &data) { QStringList out; out += "qca_def"; out += storeId; out += storeName; out += entryId; out += entryName; out += entryType; out += data; return escape_stringlist(out); } static bool entry_deserialize(const QString &in, QString *storeId, QString *storeName, QString *entryId, QString *entryName, QString *entryType, QString *data) { QStringList list; if(!unescape_stringlist(in, &list)) return false; if(list.count() != 7) return false; if(list[0] != "qca_def") return false; *storeId = list[1]; *storeName = list[2]; *entryId = list[3]; *entryName = list[4]; *entryType = list[5]; *data = list[6]; return true; } class DefaultKeyStoreEntry : public KeyStoreEntryContext { public: KeyStoreEntry::Type _type; QString _id, _name, _storeId, _storeName; Certificate _cert; CRL _crl; mutable QString _serialized; DefaultKeyStoreEntry(const Certificate &cert, const QString &storeId, const QString &storeName, Provider *p) : KeyStoreEntryContext(p) { _type = KeyStoreEntry::TypeCertificate; _storeId = storeId; _storeName = storeName; _cert = cert; } DefaultKeyStoreEntry(const CRL &crl, const QString &storeId, const QString &storeName, Provider *p) : KeyStoreEntryContext(p) { _type = KeyStoreEntry::TypeCRL; _storeId = storeId; _storeName = storeName; _crl = crl; } virtual Provider::Context *clone() const { return new DefaultKeyStoreEntry(*this); } virtual KeyStoreEntry::Type type() const { return _type; } virtual QString id() const { return _id; } virtual QString name() const { return _name; } virtual QString storeId() const { return _storeId; } virtual QString storeName() const { return _storeName; } virtual Certificate certificate() const { return _cert; } virtual CRL crl() const { return _crl; } virtual QString serialize() const { if(_serialized.isEmpty()) { QString typestr; QString datastr; if(_type == KeyStoreEntry::TypeCertificate) { typestr = "cert"; datastr = Base64().arrayToString(_cert.toDER()); } else { typestr = "crl"; datastr = Base64().arrayToString(_crl.toDER()); } _serialized = entry_serialize(_storeId, _storeName, _id, _name, typestr, datastr); } return _serialized; } static DefaultKeyStoreEntry *deserialize(const QString &in, Provider *provider) { QString storeId, storeName, id, name, typestr, datastr; if(entry_deserialize(in, &storeId, &storeName, &id, &name, &typestr, &datastr)) { QByteArray data = Base64().stringToArray(datastr).toByteArray(); DefaultKeyStoreEntry *c; if(typestr == "cert") { Certificate cert = Certificate::fromDER(data); if(cert.isNull()) return 0; c = new DefaultKeyStoreEntry(cert, storeId, storeName, provider); } else if(typestr == "crl") { CRL crl = CRL::fromDER(data); if(crl.isNull()) return 0; c = new DefaultKeyStoreEntry(crl, storeId, storeName, provider); } else return 0; c->_id = id; c->_name = name; c->_serialized = in; return c; } return 0; } QString simpleId() const { if(_type == KeyStoreEntry::TypeCertificate) return QString::number(qHash(_cert.toDER())); else return QString::number(qHash(_crl.toDER())); } QString simpleName() const { // use the common name, else orgname if(_type == KeyStoreEntry::TypeCertificate) { QString str = _cert.commonName(); if(str.isEmpty()) str = _cert.subjectInfo().value(Organization); return str; } else return _crl.issuerInfo().value(CommonName); } }; //---------------------------------------------------------------------------- // DefaultKeyStoreList //---------------------------------------------------------------------------- class DefaultKeyStoreList : public KeyStoreListContext { Q_OBJECT public: bool x509_supported; DefaultShared *shared; DefaultKeyStoreList(Provider *p, DefaultShared *_shared) : KeyStoreListContext(p), shared(_shared) { } ~DefaultKeyStoreList() { } virtual Provider::Context *clone() const { return 0; } virtual void start() { x509_supported = false; QMetaObject::invokeMethod(this, "busyEnd", Qt::QueuedConnection); } virtual QList keyStores() { if(!x509_supported) { if(isSupported("cert") && isSupported("crl")) x509_supported = true; } bool have_systemstore = false; #ifndef QCA_NO_SYSTEMSTORE if(shared->use_system()) have_systemstore = qca_have_systemstore(); #endif QList list; // system store only shows up if the OS store is available or // there is a configured store file if(x509_supported && (have_systemstore || !shared->roots_file().isEmpty())) list += 0; return list; } virtual KeyStore::Type type(int) const { return KeyStore::System; } virtual QString storeId(int) const { return "qca-default-systemstore"; } virtual QString name(int) const { return "System Trusted Certificates"; } virtual QList entryTypes(int) const { QList list; list += KeyStoreEntry::TypeCertificate; list += KeyStoreEntry::TypeCRL; return list; } virtual QList entryList(int) { QList out; QList certs; QList crls; if(shared->use_system()) { CertificateCollection col; #ifndef QCA_NO_SYSTEMSTORE col = qca_get_systemstore(QString()); #endif certs += col.certificates(); crls += col.crls(); } QString roots = shared->roots_file(); if(!roots.isEmpty()) { CertificateCollection col = CertificateCollection::fromFlatTextFile(roots); certs += col.certificates(); crls += col.crls(); } #ifdef FRIENDLY_NAMES QStringList names = makeFriendlyNames(certs); #endif for(int n = 0; n < certs.count(); ++n) { DefaultKeyStoreEntry *c = new DefaultKeyStoreEntry(certs[n], storeId(0), name(0), provider()); c->_id = c->simpleId(); #ifdef FRIENDLY_NAMES c->_name = names[n]; #else c->_name = c->simpleName(); #endif out.append(c); } for(int n = 0; n < crls.count(); ++n) { DefaultKeyStoreEntry *c = new DefaultKeyStoreEntry(crls[n], storeId(0), name(0), provider()); c->_id = c->simpleId(); c->_name = c->simpleName(); out.append(c); } return out; } virtual KeyStoreEntryContext *entryPassive(const QString &serialized) { return DefaultKeyStoreEntry::deserialize(serialized, provider()); } }; //---------------------------------------------------------------------------- // DefaultProvider //---------------------------------------------------------------------------- static bool unescape_config_stringlist(const QString &in, QStringList *_out) { QStringList out; QStringList list = in.split(','); for(int n = 0; n < list.count(); ++n) { QString str; if(!unescape_string(list[n], &str)) return false; out += str.trimmed(); } *_out = out; return true; } class DefaultProvider : public Provider { public: DefaultShared shared; virtual void init() { QDateTime now = QDateTime::currentDateTime(); uint t = now.toTime_t(); if(now.time().msec() > 0) t /= now.time().msec(); qsrand(t); } virtual int version() const { return QCA_VERSION; } virtual int qcaVersion() const { return QCA_VERSION; } virtual QString name() const { return "default"; } virtual QStringList features() const { QStringList list; list += "random"; list += "md5"; list += "sha1"; list += "keystorelist"; return list; } virtual Provider::Context *createContext(const QString &type) { if(type == "random") return new DefaultRandomContext(this); else if(type == "md5") return new DefaultMD5Context(this); else if(type == "sha1") return new DefaultSHA1Context(this); else if(type == "keystorelist") return new DefaultKeyStoreList(this, &shared); else return 0; } virtual QVariantMap defaultConfig() const { QVariantMap config; config["formtype"] = "http://affinix.com/qca/forms/default#1.0"; config["use_system"] = true; config["roots_file"] = QString(); config["skip_plugins"] = QString(); config["plugin_priorities"] = QString(); return config; } virtual void configChanged(const QVariantMap &config) { bool use_system = config["use_system"].toBool(); QString roots_file = config["roots_file"].toString(); QString skip_plugins_str = config["skip_plugins"].toString(); QString plugin_priorities_str = config["plugin_priorities"].toString(); QStringList tmp; QStringList skip_plugins; if(unescape_config_stringlist(skip_plugins_str, &tmp)) skip_plugins = tmp; QStringList plugin_priorities; if(unescape_config_stringlist(plugin_priorities_str, &tmp)) plugin_priorities = tmp; for(int n = 0; n < plugin_priorities.count(); ++n) { QString &s = plugin_priorities[n]; // make sure the entry ends with ":number" int x = s.indexOf(':'); bool ok = false; if(x != -1) s.mid(x + 1).toInt(&ok); if(!ok) { plugin_priorities.removeAt(n); --n; } } shared.set(use_system, roots_file, skip_plugins, plugin_priorities); } }; Provider *create_default_provider() { return new DefaultProvider; } QStringList skip_plugins(Provider *defaultProvider) { DefaultProvider *that = (DefaultProvider *)defaultProvider; return that->shared.skip_plugins(); } QStringList plugin_priorities(Provider *defaultProvider) { DefaultProvider *that = (DefaultProvider *)defaultProvider; return that->shared.plugin_priorities(); } #include "qca_default.moc" } psi-0.14/third-party/qca/qca/src/qca_systemstore.h0000644000175000017500000000212511305557613020305 0ustar janjan/* * qca_systemstore.h - Qt Cryptographic Architecture * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef QCA_SYSTEMSTORE_H #define QCA_SYSTEMSTORE_H // NOTE: this API is private to QCA #include "qca_cert.h" namespace QCA { bool qca_have_systemstore(); CertificateCollection qca_get_systemstore(const QString &provider); } #endif psi-0.14/third-party/qca/qca/src/qca_systemstore_mac.cpp0000644000175000017500000000312111305557613021455 0ustar janjan/* * Copyright (C) 2004,2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_systemstore.h" #include #include #include namespace QCA { bool qca_have_systemstore() { return true; } CertificateCollection qca_get_systemstore(const QString &provider) { CertificateCollection col; CFArrayRef anchors; if(SecTrustCopyAnchorCertificates(&anchors) != 0) return col; for(int n = 0; n < CFArrayGetCount(anchors); ++n) { SecCertificateRef cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, n); CSSM_DATA cssm; SecCertificateGetData(cr, &cssm); QByteArray der(cssm.Length, 0); memcpy(der.data(), cssm.Data, cssm.Length); Certificate cert = Certificate::fromDER(der, 0, provider); if(!cert.isNull()) col.addCertificate(cert); } CFRelease(anchors); return col; } } psi-0.14/third-party/qca/qca/src/qca_basic.cpp0000644000175000017500000002565511305557613017335 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005,2007 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_basic.h" #include "qcaprovider.h" #include #include namespace QCA { // from qca_core.cpp QMutex *global_random_mutex(); Random *global_random(); Provider::Context *getContext(const QString &type, Provider *p); // from qca_publickey.cpp ProviderList allProviders(); Provider *providerForName(const QString &name); static void mergeList(QStringList *a, const QStringList &b) { foreach(const QString &s, b) { if(!a->contains(s)) a->append(s); } } static QStringList get_hash_types(Provider *p) { QStringList out; InfoContext *c = static_cast(getContext("info", p)); if(!c) return out; out = c->supportedHashTypes(); delete c; return out; } static QStringList get_cipher_types(Provider *p) { QStringList out; InfoContext *c = static_cast(getContext("info", p)); if(!c) return out; out = c->supportedCipherTypes(); delete c; return out; } static QStringList get_mac_types(Provider *p) { QStringList out; InfoContext *c = static_cast(getContext("info", p)); if(!c) return out; out = c->supportedMACTypes(); delete c; return out; } static QStringList get_types(QStringList (*get_func)(Provider *p), const QString &provider) { QStringList out; if(!provider.isEmpty()) { Provider *p = providerForName(provider); if(p) out = get_func(p); } else { ProviderList pl = allProviders(); foreach(Provider *p, pl) mergeList(&out, get_func(p)); } return out; } static QStringList supportedHashTypes(const QString &provider) { return get_types(get_hash_types, provider); } static QStringList supportedCipherTypes(const QString &provider) { return get_types(get_cipher_types, provider); } static QStringList supportedMACTypes(const QString &provider) { return get_types(get_mac_types, provider); } //---------------------------------------------------------------------------- // Random //---------------------------------------------------------------------------- Random::Random(const QString &provider) :Algorithm("random", provider) { } Random::Random(const Random &from) :Algorithm(from) { } Random::~Random() { } Random & Random::operator=(const Random &from) { Algorithm::operator=(from); return *this; } uchar Random::nextByte() { return (uchar)(nextBytes(1)[0]); } SecureArray Random::nextBytes(int size) { return static_cast(context())->nextBytes(size); } uchar Random::randomChar() { QMutexLocker locker(global_random_mutex()); return global_random()->nextByte(); } int Random::randomInt() { QMutexLocker locker(global_random_mutex()); SecureArray a = global_random()->nextBytes(sizeof(int)); int x; memcpy(&x, a.data(), a.size()); return x; } SecureArray Random::randomArray(int size) { QMutexLocker locker(global_random_mutex()); return global_random()->nextBytes(size); } //---------------------------------------------------------------------------- // Hash //---------------------------------------------------------------------------- Hash::Hash(const QString &type, const QString &provider) :Algorithm(type, provider) { } Hash::Hash(const Hash &from) :Algorithm(from), BufferedComputation(from) { } Hash::~Hash() { } Hash & Hash::operator=(const Hash &from) { Algorithm::operator=(from); return *this; } QStringList Hash::supportedTypes(const QString &provider) { return supportedHashTypes(provider); } QString Hash::type() const { // algorithm type is the same as the hash type return Algorithm::type(); } void Hash::clear() { static_cast(context())->clear(); } void Hash::update(const MemoryRegion &a) { static_cast(context())->update(a); } void Hash::update(const QByteArray &a) { update(MemoryRegion(a)); } void Hash::update(const char *data, int len) { if(len < 0) len = qstrlen(data); if(len == 0) return; update(MemoryRegion(QByteArray::fromRawData(data, len))); } // Reworked from KMD5, from KDE's kdelibs void Hash::update(QIODevice *file) { char buffer[1024]; int len; while ((len=file->read(reinterpret_cast(buffer), sizeof(buffer))) > 0) update(buffer, len); } MemoryRegion Hash::final() { return static_cast(context())->final(); } MemoryRegion Hash::hash(const MemoryRegion &a) { return process(a); } QString Hash::hashToString(const MemoryRegion &a) { return arrayToHex(hash(a).toByteArray()); } //---------------------------------------------------------------------------- // Cipher //---------------------------------------------------------------------------- class Cipher::Private { public: QString type; Cipher::Mode mode; Cipher::Padding pad; Direction dir; SymmetricKey key; InitializationVector iv; bool ok, done; }; Cipher::Cipher(const QString &type, Mode mode, Padding pad, Direction dir, const SymmetricKey &key, const InitializationVector &iv, const QString &provider) :Algorithm(withAlgorithms(type, mode, pad), provider) { d = new Private; d->type = type; d->mode = mode; d->pad = pad; if(!key.isEmpty()) setup(dir, key, iv); } Cipher::Cipher(const Cipher &from) :Algorithm(from), Filter(from) { d = new Private(*from.d); } Cipher::~Cipher() { delete d; } Cipher & Cipher::operator=(const Cipher &from) { Algorithm::operator=(from); *d = *from.d; return *this; } QStringList Cipher::supportedTypes(const QString &provider) { return supportedCipherTypes(provider); } QString Cipher::type() const { return d->type; } Cipher::Mode Cipher::mode() const { return d->mode; } Cipher::Padding Cipher::padding() const { return d->pad; } Direction Cipher::direction() const { return d->dir; } KeyLength Cipher::keyLength() const { return static_cast(context())->keyLength(); } bool Cipher::validKeyLength(int n) const { KeyLength len = keyLength(); return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0)); } int Cipher::blockSize() const { return static_cast(context())->blockSize(); } void Cipher::clear() { d->done = false; static_cast(context())->setup(d->dir, d->key, d->iv); } MemoryRegion Cipher::update(const MemoryRegion &a) { SecureArray out; if(d->done) return out; d->ok = static_cast(context())->update(a, &out); return out; } MemoryRegion Cipher::final() { SecureArray out; if(d->done) return out; d->done = true; d->ok = static_cast(context())->final(&out); return out; } bool Cipher::ok() const { return d->ok; } void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv) { d->dir = dir; d->key = key; d->iv = iv; clear(); } QString Cipher::withAlgorithms(const QString &cipherType, Mode modeType, Padding paddingType) { QString mode; switch(modeType) { case CBC: mode = "cbc"; break; case CFB: mode = "cfb"; break; case OFB: mode = "ofb"; break; case ECB: mode = "ecb"; break; default: Q_ASSERT(0); } // do the default if(paddingType == DefaultPadding) { // logic from Botan if(modeType == CBC) paddingType = PKCS7; else paddingType = NoPadding; } QString pad; if(paddingType == NoPadding) pad = ""; else pad = "pkcs7"; QString result = cipherType + '-' + mode; if(!pad.isEmpty()) result += QString("-") + pad; return result; } //---------------------------------------------------------------------------- // MessageAuthenticationCode //---------------------------------------------------------------------------- class MessageAuthenticationCode::Private { public: SymmetricKey key; bool done; MemoryRegion buf; }; MessageAuthenticationCode::MessageAuthenticationCode(const QString &type, const SymmetricKey &key, const QString &provider) :Algorithm(type, provider) { d = new Private; setup(key); } MessageAuthenticationCode::MessageAuthenticationCode(const MessageAuthenticationCode &from) :Algorithm(from), BufferedComputation(from) { d = new Private(*from.d); } MessageAuthenticationCode::~MessageAuthenticationCode() { delete d; } MessageAuthenticationCode & MessageAuthenticationCode::operator=(const MessageAuthenticationCode &from) { Algorithm::operator=(from); *d = *from.d; return *this; } QStringList MessageAuthenticationCode::supportedTypes(const QString &provider) { return supportedMACTypes(provider); } QString MessageAuthenticationCode::type() const { // algorithm type is the same as the mac type return Algorithm::type(); } KeyLength MessageAuthenticationCode::keyLength() const { return static_cast(context())->keyLength(); } bool MessageAuthenticationCode::validKeyLength(int n) const { KeyLength len = keyLength(); return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0)); } void MessageAuthenticationCode::clear() { d->done = false; static_cast(context())->setup(d->key); } void MessageAuthenticationCode::update(const MemoryRegion &a) { if(d->done) return; static_cast(context())->update(a); } MemoryRegion MessageAuthenticationCode::final() { if(!d->done) { d->done = true; static_cast(context())->final(&d->buf); } return d->buf; } void MessageAuthenticationCode::setup(const SymmetricKey &key) { d->key = key; clear(); } //---------------------------------------------------------------------------- // Key Derivation Function //---------------------------------------------------------------------------- KeyDerivationFunction::KeyDerivationFunction(const QString &type, const QString &provider) :Algorithm(type, provider) { } KeyDerivationFunction::KeyDerivationFunction(const KeyDerivationFunction &from) :Algorithm(from) { } KeyDerivationFunction::~KeyDerivationFunction() { } KeyDerivationFunction & KeyDerivationFunction::operator=(const KeyDerivationFunction &from) { Algorithm::operator=(from); return *this; } SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret, const InitializationVector &salt, unsigned int keyLength, unsigned int iterationCount) { return static_cast(context())->makeKey(secret, salt, keyLength, iterationCount); } QString KeyDerivationFunction::withAlgorithm(const QString &kdfType, const QString &algType) { return (kdfType + '(' + algType + ')'); } } psi-0.14/third-party/qca/qca/src/qca_cert.cpp0000644000175000017500000020525211305557613017202 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004-2006 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_cert.h" #include "qca_publickey.h" #include "qcaprovider.h" #include #include #include #include namespace QCA { Provider::Context *getContext(const QString &type, const QString &provider); Provider::Context *getContext(const QString &type, Provider *p); // from qca_publickey.cpp bool stringToFile(const QString &fileName, const QString &content); bool stringFromFile(const QString &fileName, QString *s); bool arrayToFile(const QString &fileName, const QByteArray &content); bool arrayFromFile(const QString &fileName, QByteArray *a); bool ask_passphrase(const QString &fname, void *ptr, SecureArray *answer); ProviderList allProviders(); Provider *providerForName(const QString &name); bool use_asker_fallback(ConvertResult r); // last 3 arguments must be valid, and chain must be empty static bool get_pkcs12_der(const QByteArray &der, const QString &fileName, void *ptr, const SecureArray &passphrase, ConvertResult *result, const QString &provider, QString *name, CertificateChain *chain, PrivateKey *key) { QString _name; QList list; PKeyContext *kc = 0; PKCS12Context *pix = static_cast(getContext("pkcs12", provider)); ConvertResult r = pix->fromPKCS12(der, passphrase, &_name, &list, &kc); // error converting without passphrase? maybe a passphrase is needed if(use_asker_fallback(r) && passphrase.isEmpty()) { SecureArray pass; if(ask_passphrase(fileName, ptr, &pass)) r = pix->fromPKCS12(der, pass, &_name, &list, &kc); } delete pix; if(result) *result = r; if(r == ConvertGood) { *name = _name; for(int n = 0; n < list.count(); ++n) { Certificate cert; cert.change(list[n]); chain->append(cert); } key->change(kc); return true; } return false; } static CertificateInfo orderedToMap(const CertificateInfoOrdered &info) { CertificateInfo out; // first, do all but EmailLegacy for(int n = 0; n < info.count(); ++n) { const CertificateInfoPair &i = info[n]; if(i.type().known() != EmailLegacy) out.insert(i.type(), i.value()); } // lastly, apply EmailLegacy for(int n = 0; n < info.count(); ++n) { const CertificateInfoPair &i = info[n]; if(i.type().known() == EmailLegacy) { // de-dup QList emails = out.values(Email); if(!emails.contains(i.value())) out.insert(Email, i.value()); } } return out; } static void moveMapValues(CertificateInfo *from, CertificateInfoOrdered *to, const CertificateInfoType &type) { QList values = from->values(type); from->remove(type); // multimap values are stored in reverse. we'll insert backwards in // order to right them. for(int n = values.count() - 1; n >= 0; --n) to->append(CertificateInfoPair(type, values[n])); } static CertificateInfoOrdered mapToOrdered(const CertificateInfo &info) { CertificateInfo in = info; CertificateInfoOrdered out; // have a specific order for some types moveMapValues(&in, &out, CommonName); moveMapValues(&in, &out, Country); moveMapValues(&in, &out, Locality); moveMapValues(&in, &out, State); moveMapValues(&in, &out, Organization); moveMapValues(&in, &out, OrganizationalUnit); moveMapValues(&in, &out, Email); moveMapValues(&in, &out, URI); moveMapValues(&in, &out, DNS); moveMapValues(&in, &out, IPAddress); moveMapValues(&in, &out, XMPP); // get remaining types QList typesLeft = in.keys(); // dedup QList types; for(int n = 0; n < typesLeft.count(); ++n) { if(!types.contains(typesLeft[n])) types += typesLeft[n]; } // insert the rest of the types in the order we got them (map order) for(int n = 0; n < types.count(); ++n) moveMapValues(&in, &out, types[n]); Q_ASSERT(in.isEmpty()); return out; } //---------------------------------------------------------------------------- // Global //---------------------------------------------------------------------------- static const char CommonName_id[] = "2.5.4.3"; static const char Email_id[] = "GeneralName.rfc822Name"; static const char EmailLegacy_id[] = "1.2.840.113549.1.9.1"; static const char Organization_id[] = "2.5.4.10"; static const char OrganizationalUnit_id[] = "2.5.4.11"; static const char Locality_id[] = "2.5.4.7"; static const char IncorporationLocality_id[] = "1.3.6.1.4.1.311.60.2.1.1"; static const char State_id[] = "2.5.4.8"; static const char IncorporationState_id[] = "1.3.6.1.4.1.311.60.2.1.2"; static const char Country_id[] = "2.5.4.6"; static const char IncorporationCountry_id[] = "1.3.6.1.4.1.311.60.2.1.3"; static const char URI_id[] = "GeneralName.uniformResourceIdentifier"; static const char DNS_id[] = "GeneralName.dNSName"; static const char IPAddress_id[] = "GeneralName.iPAddress"; static const char XMPP_id[] = "1.3.6.1.5.5.7.8.5"; static const char DigitalSignature_id[] = "KeyUsage.digitalSignature"; static const char NonRepudiation_id[] = "KeyUsage.nonRepudiation"; static const char KeyEncipherment_id[] = "KeyUsage.keyEncipherment"; static const char DataEncipherment_id[] = "KeyUsage.dataEncipherment"; static const char KeyAgreement_id[] = "KeyUsage.keyAgreement"; static const char KeyCertificateSign_id[] = "KeyUsage.keyCertSign"; static const char CRLSign_id[] = "KeyUsage.crlSign"; static const char EncipherOnly_id[] = "KeyUsage.encipherOnly"; static const char DecipherOnly_id[] = "KeyUsage.decipherOnly"; static const char ServerAuth_id[] = "1.3.6.1.5.5.7.3.1"; static const char ClientAuth_id[] = "1.3.6.1.5.5.7.3.2"; static const char CodeSigning_id[] = "1.3.6.1.5.5.7.3.3"; static const char EmailProtection_id[] = "1.3.6.1.5.5.7.3.4"; static const char IPSecEndSystem_id[] = "1.3.6.1.5.5.7.3.5"; static const char IPSecTunnel_id[] = "1.3.6.1.5.5.7.3.6"; static const char IPSecUser_id[] = "1.3.6.1.5.5.7.3.7"; static const char TimeStamping_id[] = "1.3.6.1.5.5.7.3.8"; static const char OCSPSigning_id[] = "1.3.6.1.5.5.7.3.9"; static QString knownToId(CertificateInfoTypeKnown k) { const char *out = 0; switch(k) { case CommonName: out = CommonName_id; break; case Email: out = Email_id; break; case EmailLegacy: out = EmailLegacy_id; break; case Organization: out = Organization_id; break; case OrganizationalUnit: out = OrganizationalUnit_id; break; case Locality: out = Locality_id; break; case IncorporationLocality: out = IncorporationLocality_id; break; case State: out = State_id; break; case IncorporationState: out = IncorporationState_id; break; case Country: out = Country_id; break; case IncorporationCountry: out = IncorporationCountry_id; break; case URI: out = URI_id; break; case DNS: out = DNS_id; break; case IPAddress: out = IPAddress_id; break; case XMPP: out = XMPP_id; break; } Q_ASSERT(out); if(!out) abort(); return QString(out); } static int idToKnown(const QString &id) { if(id == CommonName_id) return CommonName; else if(id == Email_id) return Email; else if(id == EmailLegacy_id) return EmailLegacy; else if(id == Organization_id) return Organization; else if(id == OrganizationalUnit_id) return OrganizationalUnit; else if(id == Locality_id) return Locality; else if(id == IncorporationLocality_id) return IncorporationLocality; else if(id == State_id) return State; else if(id == IncorporationState_id) return IncorporationState; else if(id == Country_id) return Country; else if(id == IncorporationCountry_id) return IncorporationCountry; else if(id == URI_id) return URI; else if(id == DNS_id) return DNS; else if(id == IPAddress_id) return IPAddress; else if(id == XMPP_id) return XMPP; else return -1; } static CertificateInfoType::Section knownToSection(CertificateInfoTypeKnown k) { switch(k) { case CommonName: case EmailLegacy: case Organization: case OrganizationalUnit: case Locality: case IncorporationLocality: case State: case IncorporationState: case Country: case IncorporationCountry: return CertificateInfoType::DN; default: break; } return CertificateInfoType::AlternativeName; } static const char *knownToShortName(CertificateInfoTypeKnown k) { switch(k) { case CommonName: return "CN"; case Locality: return "L"; case State: return "ST"; case Organization: return "O"; case OrganizationalUnit: return "OU"; case Country: return "C"; case EmailLegacy: return "emailAddress"; default: break; } return 0; } static QString constraintKnownToId(ConstraintTypeKnown k) { const char *out = 0; switch(k) { case DigitalSignature: out = DigitalSignature_id; break; case NonRepudiation: out = NonRepudiation_id; break; case KeyEncipherment: out = KeyEncipherment_id; break; case DataEncipherment: out = DataEncipherment_id; break; case KeyAgreement: out = KeyAgreement_id; break; case KeyCertificateSign: out = KeyCertificateSign_id; break; case CRLSign: out = CRLSign_id; break; case EncipherOnly: out = EncipherOnly_id; break; case DecipherOnly: out = DecipherOnly_id; break; case ServerAuth: out = ServerAuth_id; break; case ClientAuth: out = ClientAuth_id; break; case CodeSigning: out = CodeSigning_id; break; case EmailProtection: out = EmailProtection_id; break; case IPSecEndSystem: out = IPSecEndSystem_id; break; case IPSecTunnel: out = IPSecTunnel_id; break; case IPSecUser: out = IPSecUser_id; break; case TimeStamping: out = TimeStamping_id; break; case OCSPSigning: out = OCSPSigning_id; break; } Q_ASSERT(out); if(!out) abort(); return QString(out); } static int constraintIdToKnown(const QString &id) { if(id == DigitalSignature_id) return DigitalSignature; else if(id == NonRepudiation_id) return NonRepudiation; else if(id == KeyEncipherment_id) return KeyEncipherment; else if(id == DataEncipherment_id) return DataEncipherment; else if(id == KeyAgreement_id) return KeyAgreement; else if(id == KeyCertificateSign_id) return KeyCertificateSign; else if(id == CRLSign_id) return CRLSign; else if(id == EncipherOnly_id) return EncipherOnly; else if(id == DecipherOnly_id) return DecipherOnly; else if(id == ServerAuth_id) return ServerAuth; else if(id == ClientAuth_id) return ClientAuth; else if(id == CodeSigning_id) return CodeSigning; else if(id == EmailProtection_id) return EmailProtection; else if(id == IPSecEndSystem_id) return IPSecEndSystem; else if(id == IPSecTunnel_id) return IPSecTunnel; else if(id == IPSecUser_id) return IPSecUser; else if(id == TimeStamping_id) return TimeStamping; else if(id == OCSPSigning_id) return OCSPSigning; else return -1; } static ConstraintType::Section constraintKnownToSection(ConstraintTypeKnown k) { switch(k) { case DigitalSignature: case NonRepudiation: case KeyEncipherment: case DataEncipherment: case KeyAgreement: case KeyCertificateSign: case CRLSign: case EncipherOnly: case DecipherOnly: return ConstraintType::KeyUsage; default: break; } return ConstraintType::ExtendedKeyUsage; } static QString dnLabel(const CertificateInfoType &type) { const char *str = knownToShortName(type.known()); if(str) return str; QString id = type.id(); // is it an oid? if(id[0].isDigit()) return QString("OID.") + id; return QString("qca.") + id; } QString orderedToDNString(const CertificateInfoOrdered &in) { QStringList parts; foreach(const CertificateInfoPair &i, in) { if(i.type().section() != CertificateInfoType::DN) continue; QString name = dnLabel(i.type()); parts += name + '=' + i.value(); } return parts.join(", "); } CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in) { CertificateInfoOrdered out; for(int n = 0; n < in.count(); ++n) { if(in[n].type().section() == CertificateInfoType::DN) out += in[n]; } return out; } static QString baseCertName(const CertificateInfo &info) { QString str = info.value(CommonName); if(str.isEmpty()) { str = info.value(Organization); if(str.isEmpty()) str = "Unnamed"; } return str; } static QList findSameName(const QString &name, const QStringList &list) { QList out; for(int n = 0; n < list.count(); ++n) { if(list[n] == name) out += n; } return out; } static QString uniqueSubjectValue(const CertificateInfoType &type, const QList items, const QList &certs, int i) { QStringList vals = certs[items[i]].subjectInfo().values(type); if(!vals.isEmpty()) { foreach(int n, items) { if(n == items[i]) continue; QStringList other_vals = certs[n].subjectInfo().values(type); for(int k = 0; k < vals.count(); ++k) { if(other_vals.contains(vals[k])) { vals.removeAt(k); break; } } if(vals.isEmpty()) break; } if(!vals.isEmpty()) return vals[0]; } return QString(); } static QString uniqueIssuerName(const QList items, const QList &certs, int i) { QString val = baseCertName(certs[items[i]].issuerInfo()); bool found = false; foreach(int n, items) { if(n == items[i]) continue; QString other_val = baseCertName(certs[n].issuerInfo()); if(other_val == val) { found = true; break; } } if(!found) return val; return QString(); } static const char *constraintToString(const ConstraintType &type) { switch(type.known()) { case DigitalSignature: return "DigitalSignature"; case NonRepudiation: return "NonRepudiation"; case KeyEncipherment: return "KeyEncipherment"; case DataEncipherment: return "DataEncipherment"; case KeyAgreement: return "KeyAgreement"; case KeyCertificateSign: return "KeyCertificateSign"; case CRLSign: return "CRLSign"; case EncipherOnly: return "EncipherOnly"; case DecipherOnly: return "DecipherOnly"; case ServerAuth: return "ServerAuth"; case ClientAuth: return "ClientAuth"; case CodeSigning: return "CodeSigning"; case EmailProtection: return "EmailProtection"; case IPSecEndSystem: return "IPSecEndSystem"; case IPSecTunnel: return "IPSecTunnel"; case IPSecUser: return "IPSecUser"; case TimeStamping: return "TimeStamping"; case OCSPSigning: return "OCSPSigning"; } return 0; } static QString uniqueConstraintValue(const ConstraintType &type, const QList items, const QList &certs, int i) { ConstraintType val = type; if(certs[items[i]].constraints().contains(type)) { bool found = false; foreach(int n, items) { if(n == items[i]) continue; Constraints other_vals = certs[n].constraints(); if(other_vals.contains(val)) { found = true; break; } } if(!found) return QString(constraintToString(val)); } return QString(); } static QString makeUniqueName(const QList &items, const QStringList &list, const QList &certs, int i) { QString str, name; // different organization? str = uniqueSubjectValue(Organization, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" of ") + str; goto end; } // different organizational unit? str = uniqueSubjectValue(OrganizationalUnit, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" of ") + str; goto end; } // different email address? str = uniqueSubjectValue(Email, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" <") + str + '>'; goto end; } // different xmpp addresses? str = uniqueSubjectValue(XMPP, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" '; goto end; } // different issuers? str = uniqueIssuerName(items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" by ") + str; goto end; } // different usages? // DigitalSignature str = uniqueConstraintValue(DigitalSignature, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" for ") + str; goto end; } // ClientAuth str = uniqueConstraintValue(ClientAuth, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" for ") + str; goto end; } // EmailProtection str = uniqueConstraintValue(EmailProtection, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" for ") + str; goto end; } // DataEncipherment str = uniqueConstraintValue(DataEncipherment, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" for ") + str; goto end; } // EncipherOnly str = uniqueConstraintValue(EncipherOnly, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" for ") + str; goto end; } // DecipherOnly str = uniqueConstraintValue(DecipherOnly, items, certs, i); if(!str.isEmpty()) { name = list[items[i]] + QString(" for ") + str; goto end; } // if there's nothing easily unique, then do a DN string name = certs[items[i]].subjectInfoOrdered().toString(); end: return name; } QStringList makeFriendlyNames(const QList &list) { QStringList names; // give a base name to all certs first foreach(const Certificate &cert, list) names += baseCertName(cert.subjectInfo()); // come up with a collision list QList< QList > itemCollisions; foreach(const QString &name, names) { // anyone else using this name? QList items = findSameName(name, names); if(items.count() > 1) { // don't save duplicate collisions bool haveAlready = false; foreach(const QList &other, itemCollisions) { foreach(int n, items) { if(other.contains(n)) { haveAlready = true; break; } } if(haveAlready) break; } if(haveAlready) continue; itemCollisions += items; } } // resolve collisions by providing extra details foreach(const QList &items, itemCollisions) { //printf("%d items are using [%s]\n", items.count(), qPrintable(names[items[0]])); for(int n = 0; n < items.count(); ++n) { names[items[n]] = makeUniqueName(items, names, list, n); //printf(" %d: reassigning: [%s]\n", items[n], qPrintable(names[items[n]])); } } return names; } //---------------------------------------------------------------------------- // CertificateInfoType //---------------------------------------------------------------------------- class CertificateInfoType::Private : public QSharedData { public: CertificateInfoType::Section section; int known; QString id; Private() : section(CertificateInfoType::DN), known(-1) { } }; CertificateInfoType::CertificateInfoType() :d(new Private) { } CertificateInfoType::CertificateInfoType(CertificateInfoTypeKnown known) :d(new Private) { d->section = knownToSection(known); d->known = known; d->id = knownToId(known); // always valid } CertificateInfoType::CertificateInfoType(const QString &id, Section section) :d(new Private) { d->section = section; d->known = idToKnown(id); // can be -1 for unknown d->id = id; } CertificateInfoType::CertificateInfoType(const CertificateInfoType &from) :d(from.d) { } CertificateInfoType::~CertificateInfoType() { } CertificateInfoType & CertificateInfoType::operator=(const CertificateInfoType &from) { d = from.d; return *this; } CertificateInfoType::Section CertificateInfoType::section() const { return d->section; } CertificateInfoTypeKnown CertificateInfoType::known() const { return (CertificateInfoTypeKnown)d->known; } QString CertificateInfoType::id() const { return d->id; } bool CertificateInfoType::operator<(const CertificateInfoType &other) const { // sort by knowns (in enum order), then by ids (in string order) if(d->known != -1) { if(other.d->known == -1) return true; else if(d->known < other.d->known) return true; else return false; } else { if(other.d->known != -1) return false; else if(d->id < other.d->id) return true; else return false; } } bool CertificateInfoType::operator==(const CertificateInfoType &other) const { // are both known types? if(d->known != -1 && other.d->known != -1) { // if so, compare the ints if(d->known != other.d->known) return false; } else { // otherwise, compare the string ids if(d->id != other.d->id) return false; } if(d->section != other.d->section) return false; return true; } //---------------------------------------------------------------------------- // CertificateInfoPair //---------------------------------------------------------------------------- class CertificateInfoPair::Private : public QSharedData { public: CertificateInfoType type; QString value; }; CertificateInfoPair::CertificateInfoPair() :d(new Private) { } CertificateInfoPair::CertificateInfoPair(const CertificateInfoType &type, const QString &value) :d(new Private) { d->type = type; d->value = value; } CertificateInfoPair::CertificateInfoPair(const CertificateInfoPair &from) :d(from.d) { } CertificateInfoPair::~CertificateInfoPair() { } CertificateInfoPair & CertificateInfoPair::operator=(const CertificateInfoPair &from) { d = from.d; return *this; } CertificateInfoType CertificateInfoPair::type() const { return d->type; } QString CertificateInfoPair::value() const { return d->value; } bool CertificateInfoPair::operator==(const CertificateInfoPair &other) const { if(d->type == other.d->type && d->value == other.d->value) return true; return false; } //---------------------------------------------------------------------------- // ConstraintType //---------------------------------------------------------------------------- class ConstraintType::Private : public QSharedData { public: ConstraintType::Section section; int known; QString id; Private() : section(ConstraintType::KeyUsage), known(-1) { } }; ConstraintType::ConstraintType() :d(new Private) { } ConstraintType::ConstraintType(ConstraintTypeKnown known) :d(new Private) { d->section = constraintKnownToSection(known); d->known = known; d->id = constraintKnownToId(known); // always valid } ConstraintType::ConstraintType(const QString &id, Section section) :d(new Private) { d->section = section; d->known = constraintIdToKnown(id); // can be -1 for unknown d->id = id; } ConstraintType::ConstraintType(const ConstraintType &from) :d(from.d) { } ConstraintType::~ConstraintType() { } ConstraintType & ConstraintType::operator=(const ConstraintType &from) { d = from.d; return *this; } ConstraintType::Section ConstraintType::section() const { return d->section; } ConstraintTypeKnown ConstraintType::known() const { return (ConstraintTypeKnown)d->known; } QString ConstraintType::id() const { return d->id; } bool ConstraintType::operator<(const ConstraintType &other) const { // sort by knowns (in enum order), then by ids (in string order) if(d->known != -1) { if(other.d->known == -1) return true; else if(d->known < other.d->known) return true; else return false; } else { if(other.d->known != -1) return false; else if(d->id < other.d->id) return true; else return false; } } bool ConstraintType::operator==(const ConstraintType &other) const { // are both known types? if(d->known != -1 && other.d->known != -1) { // if so, compare the ints if(d->known != other.d->known) return false; } else { // otherwise, compare the string ids if(d->id != other.d->id) return false; } if(d->section != other.d->section) return false; return true; } //---------------------------------------------------------------------------- // CertificateOptions //---------------------------------------------------------------------------- class CertificateOptions::Private { public: CertificateRequestFormat format; QString challenge; CertificateInfoOrdered info; CertificateInfo infoMap; Constraints constraints; QStringList policies; QStringList crlLocations, issuerLocations, ocspLocations; bool isCA; int pathLimit; BigInteger serial; QDateTime start, end; Private() : isCA(false), pathLimit(0) { } }; CertificateOptions::CertificateOptions(CertificateRequestFormat f) { d = new Private; d->format = f; } CertificateOptions::CertificateOptions(const CertificateOptions &from) { d = new Private(*from.d); } CertificateOptions::~CertificateOptions() { delete d; } CertificateOptions & CertificateOptions::operator=(const CertificateOptions &from) { *d = *from.d; return *this; } CertificateRequestFormat CertificateOptions::format() const { return d->format; } void CertificateOptions::setFormat(CertificateRequestFormat f) { d->format = f; } bool CertificateOptions::isValid() const { // logic from Botan if(d->infoMap.value(CommonName).isEmpty() || d->infoMap.value(Country).isEmpty()) return false; if(d->infoMap.value(Country).length() != 2) return false; if(d->start >= d->end) return false; return true; } QString CertificateOptions::challenge() const { return d->challenge; } CertificateInfo CertificateOptions::info() const { return d->infoMap; } CertificateInfoOrdered CertificateOptions::infoOrdered() const { return d->info; } Constraints CertificateOptions::constraints() const { return d->constraints; } QStringList CertificateOptions::policies() const { return d->policies; } QStringList CertificateOptions::crlLocations() const { return d->crlLocations; } QStringList CertificateOptions::issuerLocations() const { return d->issuerLocations; } QStringList CertificateOptions::ocspLocations() const { return d->ocspLocations; } bool CertificateOptions::isCA() const { return d->isCA; } int CertificateOptions::pathLimit() const { return d->pathLimit; } BigInteger CertificateOptions::serialNumber() const { return d->serial; } QDateTime CertificateOptions::notValidBefore() const { return d->start; } QDateTime CertificateOptions::notValidAfter() const { return d->end; } void CertificateOptions::setChallenge(const QString &s) { d->challenge = s; } void CertificateOptions::setInfo(const CertificateInfo &info) { d->info = mapToOrdered(info); d->infoMap = info; } void CertificateOptions::setInfoOrdered(const CertificateInfoOrdered &info) { d->info = info; d->infoMap = orderedToMap(info); } void CertificateOptions::setConstraints(const Constraints &constraints) { d->constraints = constraints; } void CertificateOptions::setPolicies(const QStringList &policies) { d->policies = policies; } void CertificateOptions::setCRLLocations(const QStringList &locations) { d->crlLocations = locations; } void CertificateOptions::setIssuerLocations(const QStringList &locations) { d->issuerLocations = locations; } void CertificateOptions::setOCSPLocations(const QStringList &locations) { d->ocspLocations = locations; } void CertificateOptions::setAsCA(int pathLimit) { d->isCA = true; d->pathLimit = pathLimit; } void CertificateOptions::setAsUser() { d->isCA = false; d->pathLimit = 0; } void CertificateOptions::setSerialNumber(const BigInteger &i) { d->serial = i; } void CertificateOptions::setValidityPeriod(const QDateTime &start, const QDateTime &end) { d->start = start; d->end = end; } //---------------------------------------------------------------------------- // Certificate //---------------------------------------------------------------------------- // ip address string to binary (msb), adapted from jdns (adapted from qt) // return: size 4 = ipv4, size 16 = ipv6, size 0 = error static QByteArray ipaddr_str2bin(const QString &str) { // ipv6 if(str.contains(':')) { QStringList parts = str.split(':', QString::KeepEmptyParts); if(parts.count() < 3 || parts.count() > 8) return QByteArray(); QByteArray ipv6(16, 0); int at = 16; int fill = 9 - parts.count(); for(int n = parts.count() - 1; n >= 0; --n) { if(at <= 0) return QByteArray(); if(parts[n].isEmpty()) { if(n == parts.count() - 1) { if(!parts[n - 1].isEmpty()) return QByteArray(); ipv6[--at] = 0; ipv6[--at] = 0; } else if(n == 0) { if(!parts[n + 1].isEmpty()) return QByteArray(); ipv6[--at] = 0; ipv6[--at] = 0; } else { for(int i = 0; i < fill; ++i) { if(at <= 0) return QByteArray(); ipv6[--at] = 0; ipv6[--at] = 0; } } } else { if(parts[n].indexOf('.') == -1) { bool ok; int x = parts[n].toInt(&ok, 16); if(!ok || x < 0 || x > 0xffff) return QByteArray(); ipv6[--at] = x & 0xff; ipv6[--at] = (x >> 8) & 0xff; } else { if(n != parts.count() - 1) return QByteArray(); QByteArray buf = ipaddr_str2bin(parts[n]); if(buf.isEmpty()) return QByteArray(); ipv6[--at] = buf[3]; ipv6[--at] = buf[2]; ipv6[--at] = buf[1]; ipv6[--at] = buf[0]; --fill; } } } return ipv6; } else if(str.contains('.')) { QStringList parts = str.split('.', QString::KeepEmptyParts); if(parts.count() != 4) return QByteArray(); QByteArray out(4, 0); for(int n = 0; n < 4; ++n) { bool ok; int x = parts[n].toInt(&ok); if(!ok || x < 0 || x > 0xff) return QByteArray(); out[n] = (unsigned char)x; } return out; } else return QByteArray(); } // acedomain must be all lowercase, with no trailing dot or wildcards static bool cert_match_domain(const QString &certname, const QString &acedomain) { // KSSL strips start/end whitespace, even though such whitespace is // probably not legal anyway. (compat) QString name = certname.trimmed(); // KSSL strips trailing dot, even though the dot is probably not // legal anyway. (compat) if(name.length() > 0 && name[name.length()-1] == '.') name.truncate(name.length()-1); // after our compatibility modifications, make sure the name isn't // empty. if(name.isEmpty()) return false; // lowercase, for later performing case insensitive matching name = name.toLower(); // ensure the cert field contains valid characters only if(QRegExp("[^a-z0-9\\.\\*\\-]").indexIn(name) >= 0) return false; // hack into parts, and require at least 1 part QStringList parts_name = name.split('.', QString::KeepEmptyParts); if(parts_name.isEmpty()) return false; // KSSL checks to make sure the last two parts don't contain // wildcards. I don't know where it is written that this // should be done, but for compat sake we'll do it. if(parts_name[parts_name.count()-1].contains('*')) return false; if(parts_name.count() >= 2 && parts_name[parts_name.count()-2].contains('*')) return false; QStringList parts_compare = acedomain.split('.', QString::KeepEmptyParts); if(parts_compare.isEmpty()) return false; // don't allow empty parts foreach(const QString &s, parts_name) { if(s.isEmpty()) return false; } foreach(const QString &s, parts_compare) { if(s.isEmpty()) return false; } // RFC2818: "Names may contain the wildcard character * which is // considered to match any single domain name component or // component fragment. E.g., *.a.com matches foo.a.com but not // bar.foo.a.com. f*.com matches foo.com but not bar.com." // // This means that for the domain to match it must have the // same number of components, wildcards or not. If there are // wildcards, their scope must only be within the component // they reside in. // // First, make sure the number of parts is equal. if(parts_name.count() != parts_compare.count()) return false; // Now compare each part for(int n = 0; n < parts_name.count(); ++n) { const QString &p1 = parts_name[n]; const QString &p2 = parts_compare[n]; if(!QRegExp(p1, Qt::CaseSensitive, QRegExp::Wildcard).exactMatch(p2)) return false; } return true; } // ipaddress must be an ipv4 or ipv6 address in binary format static bool cert_match_ipaddress(const QString &certname, const QByteArray &ipaddress) { // KSSL strips start/end whitespace, even though such whitespace is // probably not legal anyway. (compat) QString name = certname.trimmed(); // KSSL accepts IPv6 in brackets, which is usually done for URIs, but // IMO sounds very strange for a certificate. We'll follow this // behavior anyway. (compat) if(name.length() >= 2 && name[0] == '[' && name[name.length()-1] == ']') name = name.mid(1, name.length() - 2); // chop off brackets // after our compatibility modifications, make sure the name isn't // empty. if(name.isEmpty()) return false; // convert to binary form QByteArray addr = ipaddr_str2bin(name); if(addr.isEmpty()) return false; // not the same? if(addr != ipaddress) return false; return true; } class Certificate::Private : public QSharedData { public: CertificateInfo subjectInfoMap, issuerInfoMap; void update(CertContext *c) { if(c) { subjectInfoMap = orderedToMap(c->props()->subject); issuerInfoMap = orderedToMap(c->props()->issuer); } else { subjectInfoMap = CertificateInfo(); issuerInfoMap = CertificateInfo(); } } }; Certificate::Certificate() :d(new Private) { } Certificate::Certificate(const QString &fileName) :d(new Private) { *this = fromPEMFile(fileName, 0, QString()); } Certificate::Certificate(const CertificateOptions &opts, const PrivateKey &key, const QString &provider) :d(new Private) { CertContext *c = static_cast(getContext("cert", provider)); if(c->createSelfSigned(opts, *(static_cast(key.context())))) change(c); else delete c; } Certificate::Certificate(const Certificate &from) :Algorithm(from), d(from.d) { } Certificate::~Certificate() { } Certificate & Certificate::operator=(const Certificate &from) { Algorithm::operator=(from); d = from.d; return *this; } bool Certificate::isNull() const { return (!context() ? true : false); } QDateTime Certificate::notValidBefore() const { return static_cast(context())->props()->start; } QDateTime Certificate::notValidAfter() const { return static_cast(context())->props()->end; } CertificateInfo Certificate::subjectInfo() const { return d->subjectInfoMap; } CertificateInfoOrdered Certificate::subjectInfoOrdered() const { return static_cast(context())->props()->subject; } CertificateInfo Certificate::issuerInfo() const { return d->issuerInfoMap; } CertificateInfoOrdered Certificate::issuerInfoOrdered() const { return static_cast(context())->props()->issuer; } Constraints Certificate::constraints() const { return static_cast(context())->props()->constraints; } QStringList Certificate::policies() const { return static_cast(context())->props()->policies; } QStringList Certificate::crlLocations() const { return static_cast(context())->props()->crlLocations; } QStringList Certificate::issuerLocations() const { return static_cast(context())->props()->issuerLocations; } QStringList Certificate::ocspLocations() const { return static_cast(context())->props()->ocspLocations; } QString Certificate::commonName() const { return d->subjectInfoMap.value(CommonName); } BigInteger Certificate::serialNumber() const { return static_cast(context())->props()->serial; } PublicKey Certificate::subjectPublicKey() const { PKeyContext *c = static_cast(context())->subjectPublicKey(); PublicKey key; key.change(c); return key; } bool Certificate::isCA() const { return static_cast(context())->props()->isCA; } bool Certificate::isSelfSigned() const { return static_cast(context())->props()->isSelfSigned; } bool Certificate::isIssuerOf(const Certificate &other) const { const CertContext *cc = static_cast(other.context()); return static_cast(context())->isIssuerOf(cc); } int Certificate::pathLimit() const { return static_cast(context())->props()->pathLimit; } SignatureAlgorithm Certificate::signatureAlgorithm() const { return static_cast(context())->props()->sigalgo; } QByteArray Certificate::subjectKeyId() const { return static_cast(context())->props()->subjectId; } QByteArray Certificate::issuerKeyId() const { return static_cast(context())->props()->issuerId; } Validity Certificate::validate(const CertificateCollection &trusted, const CertificateCollection &untrusted, UsageMode u, ValidateFlags vf) const { QList issuers = trusted.certificates() + untrusted.certificates(); CertificateChain chain; chain += *this; Validity result; chain = chain.complete(issuers, &result); if(result != ValidityGood) return result; return chain.validate(trusted, untrusted.crls(), u, vf); } QByteArray Certificate::toDER() const { return static_cast(context())->toDER(); } QString Certificate::toPEM() const { return static_cast(context())->toPEM(); } bool Certificate::toPEMFile(const QString &fileName) const { return stringToFile(fileName, toPEM()); } Certificate Certificate::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) { Certificate c; CertContext *cc = static_cast(getContext("cert", provider)); ConvertResult r = cc->fromDER(a); if(result) *result = r; if(r == ConvertGood) c.change(cc); else delete cc; return c; } Certificate Certificate::fromPEM(const QString &s, ConvertResult *result, const QString &provider) { Certificate c; CertContext *cc = static_cast(getContext("cert", provider)); ConvertResult r = cc->fromPEM(s); if(result) *result = r; if(r == ConvertGood) c.change(cc); else delete cc; return c; } Certificate Certificate::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) { QString pem; if(!stringFromFile(fileName, &pem)) { if(result) *result = ErrorFile; return Certificate(); } return fromPEM(pem, result, provider); } // check for ip addresses in iPAddress, dNSName, then commonName // for all else, check in dNSName, then commonName bool Certificate::matchesHostName(const QString &host) const { QByteArray ipaddr = ipaddr_str2bin(host); if(!ipaddr.isEmpty()) // ip address { // check iPAddress foreach(const QString &s, subjectInfo().values(IPAddress)) { if(cert_match_ipaddress(s, ipaddr)) return true; } // check dNSName foreach(const QString &s, subjectInfo().values(DNS)) { if(cert_match_ipaddress(s, ipaddr)) return true; } // check commonName foreach(const QString &s, subjectInfo().values(CommonName)) { if(cert_match_ipaddress(s, ipaddr)) return true; } } else // domain { // lowercase QString name = host.toLower(); // ACE name = QString::fromLatin1(QUrl::toAce(name)); // don't allow wildcards in the comparison host if(name.contains('*')) return false; // strip out trailing dot if(name.length() > 0 && name[name.length()-1] == '.') name.truncate(name.length()-1); // make sure the name is not empty after our modifications if(name.isEmpty()) return false; // check dNSName foreach(const QString &s, subjectInfo().values(DNS)) { if(cert_match_domain(s, name)) return true; } // check commonName foreach(const QString &s, subjectInfo().values(CommonName)) { if(cert_match_domain(s, name)) return true; } } return false; } bool Certificate::operator==(const Certificate &otherCert) const { if(isNull()) { if(otherCert.isNull()) return true; else return false; } else if(otherCert.isNull()) return false; const CertContext *other = static_cast(otherCert.context()); return static_cast(context())->compare(other); } void Certificate::change(CertContext *c) { Algorithm::change(c); d->update(static_cast(context())); } Validity Certificate::chain_validate(const CertificateChain &chain, const CertificateCollection &trusted, const QList &untrusted_crls, UsageMode u, ValidateFlags vf) const { QList chain_list; QList trusted_list; QList crl_list; QList chain_certs = chain; QList trusted_certs = trusted.certificates(); QList crls = trusted.crls() + untrusted_crls; for(int n = 0; n < chain_certs.count(); ++n) { CertContext *c = static_cast(chain_certs[n].context()); chain_list += c; } for(int n = 0; n < trusted_certs.count(); ++n) { CertContext *c = static_cast(trusted_certs[n].context()); trusted_list += c; } for(int n = 0; n < crls.count(); ++n) { CRLContext *c = static_cast(crls[n].context()); crl_list += c; } return static_cast(context())->validate_chain(chain_list, trusted_list, crl_list, u, vf); } CertificateChain Certificate::chain_complete(const CertificateChain &chain, const QList &issuers, Validity *result) const { CertificateChain out; QList pool = issuers + chain.mid(1); out += chain.first(); if(result) *result = ValidityGood; while(!out.last().isSelfSigned()) { // try to get next in chain int at = -1; for(int n = 0; n < pool.count(); ++n) { //QString str = QString("[%1] issued by [%2] ? ").arg(out.last().commonName()).arg(pool[n].commonName()); if(pool[n].isIssuerOf(out.last())) { //printf("%s yes\n", qPrintable(str)); at = n; break; } //printf("%s no\n", qPrintable(str)); } if(at == -1) { if(result) *result = ErrorInvalidCA; break; } // take it out of the pool Certificate next = pool.takeAt(at); // make sure it isn't in the chain already (avoid loops) if(out.contains(next)) break; // append to the chain out += next; } return out; } //---------------------------------------------------------------------------- // CertificateRequest //---------------------------------------------------------------------------- class CertificateRequest::Private : public QSharedData { public: CertificateInfo subjectInfoMap; void update(CSRContext *c) { if(c) subjectInfoMap = orderedToMap(c->props()->subject); else subjectInfoMap = CertificateInfo(); } }; CertificateRequest::CertificateRequest() :d(new Private) { } CertificateRequest::CertificateRequest(const QString &fileName) :d(new Private) { *this = fromPEMFile(fileName, 0, QString()); } CertificateRequest::CertificateRequest(const CertificateOptions &opts, const PrivateKey &key, const QString &provider) :d(new Private) { CSRContext *c = static_cast(getContext("csr", provider)); if(c->createRequest(opts, *(static_cast(key.context())))) change(c); else delete c; } CertificateRequest::CertificateRequest(const CertificateRequest &from) :Algorithm(from), d(from.d) { } CertificateRequest::~CertificateRequest() { } CertificateRequest & CertificateRequest::operator=(const CertificateRequest &from) { Algorithm::operator=(from); d = from.d; return *this; } bool CertificateRequest::isNull() const { return (!context() ? true : false); } bool CertificateRequest::canUseFormat(CertificateRequestFormat f, const QString &provider) { CSRContext *c = static_cast(getContext("csr", provider)); bool ok = c->canUseFormat(f); delete c; return ok; } CertificateRequestFormat CertificateRequest::format() const { if(isNull()) return PKCS10; // some default so we don't explode return static_cast(context())->props()->format; } CertificateInfo CertificateRequest::subjectInfo() const { return d->subjectInfoMap; } CertificateInfoOrdered CertificateRequest::subjectInfoOrdered() const { return static_cast(context())->props()->subject; } Constraints CertificateRequest::constraints() const { return static_cast(context())->props()->constraints; } QStringList CertificateRequest::policies() const { return static_cast(context())->props()->policies; } PublicKey CertificateRequest::subjectPublicKey() const { PKeyContext *c = static_cast(context())->subjectPublicKey(); PublicKey key; key.change(c); return key; } bool CertificateRequest::isCA() const { return static_cast(context())->props()->isCA; } int CertificateRequest::pathLimit() const { return static_cast(context())->props()->pathLimit; } QString CertificateRequest::challenge() const { return static_cast(context())->props()->challenge; } SignatureAlgorithm CertificateRequest::signatureAlgorithm() const { return static_cast(context())->props()->sigalgo; } bool CertificateRequest::operator==(const CertificateRequest &otherCsr) const { if(isNull()) { if(otherCsr.isNull()) return true; else return false; } else if(otherCsr.isNull()) return false; const CSRContext *other = static_cast(otherCsr.context()); return static_cast(context())->compare(other); } QByteArray CertificateRequest::toDER() const { return static_cast(context())->toDER(); } QString CertificateRequest::toPEM() const { return static_cast(context())->toPEM(); } bool CertificateRequest::toPEMFile(const QString &fileName) const { return stringToFile(fileName, toPEM()); } CertificateRequest CertificateRequest::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) { CertificateRequest c; CSRContext *csr = static_cast(getContext("csr", provider)); ConvertResult r = csr->fromDER(a); if(result) *result = r; if(r == ConvertGood) c.change(csr); else delete csr; return c; } CertificateRequest CertificateRequest::fromPEM(const QString &s, ConvertResult *result, const QString &provider) { CertificateRequest c; CSRContext *csr = static_cast(getContext("csr", provider)); ConvertResult r = csr->fromPEM(s); if(result) *result = r; if(r == ConvertGood) c.change(csr); else delete csr; return c; } CertificateRequest CertificateRequest::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) { QString pem; if(!stringFromFile(fileName, &pem)) { if(result) *result = ErrorFile; return CertificateRequest(); } return fromPEM(pem, result, provider); } QString CertificateRequest::toString() const { return static_cast(context())->toSPKAC(); } CertificateRequest CertificateRequest::fromString(const QString &s, ConvertResult *result, const QString &provider) { CertificateRequest c; CSRContext *csr = static_cast(getContext("csr", provider)); ConvertResult r = csr->fromSPKAC(s); if(result) *result = r; if(r == ConvertGood) c.change(csr); else delete csr; return c; } void CertificateRequest::change(CSRContext *c) { Algorithm::change(c); d->update(static_cast(context())); } //---------------------------------------------------------------------------- // CRLEntry //---------------------------------------------------------------------------- CRLEntry::CRLEntry() { _reason = Unspecified; } CRLEntry::CRLEntry(const Certificate &c, Reason r) { _serial = c.serialNumber(); _time = QDateTime::currentDateTime(); _reason = r; } CRLEntry::CRLEntry(const BigInteger serial, const QDateTime &time, Reason r) { _serial = serial; _time = time; _reason = r; } CRLEntry::CRLEntry(const CRLEntry &from) :_serial(from._serial), _time(from._time), _reason(from._reason) { } CRLEntry::~CRLEntry() { } CRLEntry & CRLEntry::operator=(const CRLEntry &from) { _serial = from._serial; _time = from._time; _reason = from._reason; return *this; } bool CRLEntry::isNull() const { return (_time.isNull()); } BigInteger CRLEntry::serialNumber() const { return _serial; } QDateTime CRLEntry::time() const { return _time; } CRLEntry::Reason CRLEntry::reason() const { return _reason; } bool CRLEntry::operator==(const CRLEntry &otherEntry) const { if(isNull()) { if(otherEntry.isNull()) return true; else return false; } else if(otherEntry.isNull()) return false; if((_serial != otherEntry._serial) || (_time != otherEntry._time) || (_reason != otherEntry._reason)) { return false; } return true; } bool CRLEntry::operator<(const CRLEntry &otherEntry) const { if(isNull() || otherEntry.isNull()) return false; if(_serial < otherEntry._serial) return true; return false; } //---------------------------------------------------------------------------- // CRL //---------------------------------------------------------------------------- class CRL::Private : public QSharedData { public: CertificateInfo issuerInfoMap; void update(CRLContext *c) { if(c) issuerInfoMap = orderedToMap(c->props()->issuer); else issuerInfoMap = CertificateInfo(); } }; CRL::CRL() :d(new Private) { } CRL::CRL(const CRL &from) :Algorithm(from), d(from.d) { } CRL::~CRL() { } CRL & CRL::operator=(const CRL &from) { Algorithm::operator=(from); d = from.d; return *this; } bool CRL::isNull() const { return (!context() ? true : false); } CertificateInfo CRL::issuerInfo() const { return d->issuerInfoMap; } CertificateInfoOrdered CRL::issuerInfoOrdered() const { return static_cast(context())->props()->issuer; } int CRL::number() const { return static_cast(context())->props()->number; } QDateTime CRL::thisUpdate() const { return static_cast(context())->props()->thisUpdate; } QDateTime CRL::nextUpdate() const { return static_cast(context())->props()->nextUpdate; } QList CRL::revoked() const { return static_cast(context())->props()->revoked; } SignatureAlgorithm CRL::signatureAlgorithm() const { return static_cast(context())->props()->sigalgo; } QByteArray CRL::issuerKeyId() const { return static_cast(context())->props()->issuerId; } QByteArray CRL::toDER() const { return static_cast(context())->toDER(); } QString CRL::toPEM() const { return static_cast(context())->toPEM(); } bool CRL::operator==(const CRL &otherCrl) const { if(isNull()) { if(otherCrl.isNull()) return true; else return false; } else if(otherCrl.isNull()) return false; const CRLContext *other = static_cast(otherCrl.context()); return static_cast(context())->compare(other); } CRL CRL::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) { CRL c; CRLContext *cc = static_cast(getContext("crl", provider)); ConvertResult r = cc->fromDER(a); if(result) *result = r; if(r == ConvertGood) c.change(cc); else delete cc; return c; } CRL CRL::fromPEM(const QString &s, ConvertResult *result, const QString &provider) { CRL c; CRLContext *cc = static_cast(getContext("crl", provider)); ConvertResult r = cc->fromPEM(s); if(result) *result = r; if(r == ConvertGood) c.change(cc); else delete cc; return c; } CRL CRL::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) { QString pem; if(!stringFromFile(fileName, &pem)) { if(result) *result = ErrorFile; return CRL(); } return fromPEM(pem, result, provider); } bool CRL::toPEMFile(const QString &fileName) const { return stringToFile(fileName, toPEM()); } void CRL::change(CRLContext *c) { Algorithm::change(c); d->update(static_cast(context())); } //---------------------------------------------------------------------------- // Store //---------------------------------------------------------------------------- // CRL / X509 CRL // CERTIFICATE / X509 CERTIFICATE static QString readNextPem(QTextStream *ts, bool *isCRL) { QString pem; bool crl = false; bool found = false; bool done = false; while(!ts->atEnd()) { QString line = ts->readLine(); if(!found) { if(line.startsWith("-----BEGIN ")) { if(line.contains("CERTIFICATE")) { found = true; pem += line + '\n'; crl = false; } else if(line.contains("CRL")) { found = true; pem += line + '\n'; crl = true; } } } else { pem += line + '\n'; if(line.startsWith("-----END ")) { done = true; break; } } } if(!done) return QString(); if(isCRL) *isCRL = crl; return pem; } class CertificateCollection::Private : public QSharedData { public: QList certs; QList crls; }; CertificateCollection::CertificateCollection() :d(new Private) { } CertificateCollection::CertificateCollection(const CertificateCollection &from) :d(from.d) { } CertificateCollection::~CertificateCollection() { } CertificateCollection & CertificateCollection::operator=(const CertificateCollection &from) { d = from.d; return *this; } void CertificateCollection::addCertificate(const Certificate &cert) { d->certs.append(cert); } void CertificateCollection::addCRL(const CRL &crl) { d->crls.append(crl); } QList CertificateCollection::certificates() const { return d->certs; } QList CertificateCollection::crls() const { return d->crls; } void CertificateCollection::append(const CertificateCollection &other) { d->certs += other.d->certs; d->crls += other.d->crls; } CertificateCollection CertificateCollection::operator+(const CertificateCollection &other) const { CertificateCollection c = *this; c.append(other); return c; } CertificateCollection & CertificateCollection::operator+=(const CertificateCollection &other) { append(other); return *this; } bool CertificateCollection::canUsePKCS7(const QString &provider) { return isSupported("certcollection", provider); } bool CertificateCollection::toFlatTextFile(const QString &fileName) { QFile f(fileName); if(!f.open(QFile::WriteOnly)) return false; QTextStream ts(&f); int n; for(n = 0; n < d->certs.count(); ++n) ts << d->certs[n].toPEM(); for(n = 0; n < d->crls.count(); ++n) ts << d->crls[n].toPEM(); return true; } bool CertificateCollection::toPKCS7File(const QString &fileName, const QString &provider) { CertCollectionContext *col = static_cast(getContext("certcollection", provider)); QList cert_list; QList crl_list; int n; for(n = 0; n < d->certs.count(); ++n) { CertContext *c = static_cast(d->certs[n].context()); cert_list += c; } for(n = 0; n < d->crls.count(); ++n) { CRLContext *c = static_cast(d->crls[n].context()); crl_list += c; } QByteArray result = col->toPKCS7(cert_list, crl_list); delete col; return arrayToFile(fileName, result); } CertificateCollection CertificateCollection::fromFlatTextFile(const QString &fileName, ConvertResult *result, const QString &provider) { QFile f(fileName); if(!f.open(QFile::ReadOnly)) { if(result) *result = ErrorFile; return CertificateCollection(); } CertificateCollection certs; QTextStream ts(&f); while(1) { bool isCRL = false; QString pem = readNextPem(&ts, &isCRL); if(pem.isNull()) break; if(isCRL) { CRL c = CRL::fromPEM(pem, 0, provider); if(!c.isNull()) certs.addCRL(c); } else { Certificate c = Certificate::fromPEM(pem, 0, provider); if(!c.isNull()) certs.addCertificate(c); } } if(result) *result = ConvertGood; return certs; } CertificateCollection CertificateCollection::fromPKCS7File(const QString &fileName, ConvertResult *result, const QString &provider) { QByteArray der; if(!arrayFromFile(fileName, &der)) { if(result) *result = ErrorFile; return CertificateCollection(); } CertificateCollection certs; QList cert_list; QList crl_list; CertCollectionContext *col = static_cast(getContext("certcollection", provider)); ConvertResult r = col->fromPKCS7(der, &cert_list, &crl_list); delete col; if(result) *result = r; if(r == ConvertGood) { int n; for(n = 0; n < cert_list.count(); ++n) { Certificate c; c.change(cert_list[n]); certs.addCertificate(c); } for(n = 0; n < crl_list.count(); ++n) { CRL c; c.change(crl_list[n]); certs.addCRL(c); } } return certs; } //---------------------------------------------------------------------------- // CertificateAuthority //---------------------------------------------------------------------------- CertificateAuthority::CertificateAuthority(const Certificate &cert, const PrivateKey &key, const QString &provider) :Algorithm("ca", provider) { static_cast(context())->setup(*(static_cast(cert.context())), *(static_cast(key.context()))); } CertificateAuthority::CertificateAuthority(const CertificateAuthority &from) :Algorithm(from) { } CertificateAuthority::~CertificateAuthority() { } CertificateAuthority & CertificateAuthority::operator=(const CertificateAuthority &from) { Algorithm::operator=(from); return *this; } Certificate CertificateAuthority::certificate() const { Certificate c; c.change(static_cast(context())->certificate()); return c; } Certificate CertificateAuthority::signRequest(const CertificateRequest &req, const QDateTime ¬ValidAfter) const { Certificate c; CertContext *cc = static_cast(context())->signRequest(*(static_cast(req.context())), notValidAfter); if(cc) c.change(cc); return c; } CRL CertificateAuthority::createCRL(const QDateTime &nextUpdate) const { CRL crl; CRLContext *cc = static_cast(context())->createCRL(nextUpdate); if(cc) crl.change(cc); return crl; } CRL CertificateAuthority::updateCRL(const CRL &crl, const QList &entries, const QDateTime &nextUpdate) const { CRL new_crl; CRLContext *cc = static_cast(context())->updateCRL(*(static_cast(crl.context())), entries, nextUpdate); if(cc) new_crl.change(cc); return new_crl; } //---------------------------------------------------------------------------- // KeyBundle //---------------------------------------------------------------------------- class KeyBundle::Private : public QSharedData { public: QString name; CertificateChain chain; PrivateKey key; }; KeyBundle::KeyBundle() :d(new Private) { } KeyBundle::KeyBundle(const QString &fileName, const SecureArray &passphrase) :d(new Private) { *this = fromFile(fileName, passphrase, 0, QString()); } KeyBundle::KeyBundle(const KeyBundle &from) :d(from.d) { } KeyBundle::~KeyBundle() { } KeyBundle & KeyBundle::operator=(const KeyBundle &from) { d = from.d; return *this; } bool KeyBundle::isNull() const { return d->chain.isEmpty(); } QString KeyBundle::name() const { return d->name; } CertificateChain KeyBundle::certificateChain() const { return d->chain; } PrivateKey KeyBundle::privateKey() const { return d->key; } void KeyBundle::setName(const QString &s) { d->name = s; } void KeyBundle::setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key) { d->chain = c; d->key = key; } QByteArray KeyBundle::toArray(const SecureArray &passphrase, const QString &provider) const { PKCS12Context *pix = static_cast(getContext("pkcs12", provider)); QList list; for(int n = 0; n < d->chain.count(); ++n) list.append(static_cast(d->chain[n].context())); QByteArray buf = pix->toPKCS12(d->name, list, *(static_cast(d->key.context())), passphrase); delete pix; return buf; } bool KeyBundle::toFile(const QString &fileName, const SecureArray &passphrase, const QString &provider) const { return arrayToFile(fileName, toArray(passphrase, provider)); } KeyBundle KeyBundle::fromArray(const QByteArray &a, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { KeyBundle bundle; get_pkcs12_der(a, QString(), (void *)&a, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key); return bundle; } KeyBundle KeyBundle::fromFile(const QString &fileName, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { QByteArray der; if(!arrayFromFile(fileName, &der)) { if(result) *result = ErrorFile; return KeyBundle(); } KeyBundle bundle; get_pkcs12_der(der, fileName, 0, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key); return bundle; } //---------------------------------------------------------------------------- // PGPKey //---------------------------------------------------------------------------- PGPKey::PGPKey() { } PGPKey::PGPKey(const QString &fileName) { *this = fromFile(fileName, 0, QString()); } PGPKey::PGPKey(const PGPKey &from) :Algorithm(from) { } PGPKey::~PGPKey() { } PGPKey & PGPKey::operator=(const PGPKey &from) { Algorithm::operator=(from); return *this; } bool PGPKey::isNull() const { return (!context() ? true : false); } QString PGPKey::keyId() const { return static_cast(context())->props()->keyId; } QString PGPKey::primaryUserId() const { return static_cast(context())->props()->userIds.first(); } QStringList PGPKey::userIds() const { return static_cast(context())->props()->userIds; } bool PGPKey::isSecret() const { return static_cast(context())->props()->isSecret; } QDateTime PGPKey::creationDate() const { return static_cast(context())->props()->creationDate; } QDateTime PGPKey::expirationDate() const { return static_cast(context())->props()->expirationDate; } QString PGPKey::fingerprint() const { return static_cast(context())->props()->fingerprint; } bool PGPKey::inKeyring() const { return static_cast(context())->props()->inKeyring; } bool PGPKey::isTrusted() const { return static_cast(context())->props()->isTrusted; } QByteArray PGPKey::toArray() const { return static_cast(context())->toBinary(); } QString PGPKey::toString() const { return static_cast(context())->toAscii(); } bool PGPKey::toFile(const QString &fileName) const { return stringToFile(fileName, toString()); } PGPKey PGPKey::fromArray(const QByteArray &a, ConvertResult *result, const QString &provider) { PGPKey k; PGPKeyContext *kc = static_cast(getContext("pgpkey", provider)); ConvertResult r = kc->fromBinary(a); if(result) *result = r; if(r == ConvertGood) k.change(kc); else delete kc; return k; } PGPKey PGPKey::fromString(const QString &s, ConvertResult *result, const QString &provider) { PGPKey k; PGPKeyContext *kc = static_cast(getContext("pgpkey", provider)); ConvertResult r = kc->fromAscii(s); if(result) *result = r; if(r == ConvertGood) k.change(kc); else delete kc; return k; } PGPKey PGPKey::fromFile(const QString &fileName, ConvertResult *result, const QString &provider) { QString str; if(!stringFromFile(fileName, &str)) { if(result) *result = ErrorFile; return PGPKey(); } return fromString(str, result, provider); } //---------------------------------------------------------------------------- // KeyLoader //---------------------------------------------------------------------------- class KeyLoaderThread : public QThread { Q_OBJECT public: enum Type { PKPEMFile, PKPEM, PKDER, KBDERFile, KBDER }; class In { public: Type type; QString fileName, pem; SecureArray der; QByteArray kbder; }; class Out { public: ConvertResult convertResult; PrivateKey privateKey; KeyBundle keyBundle; }; In in; Out out; KeyLoaderThread(QObject *parent = 0) : QThread(parent) { } protected: virtual void run() { if(in.type == PKPEMFile) out.privateKey = PrivateKey::fromPEMFile(in.fileName, SecureArray(), &out.convertResult); else if(in.type == PKPEM) out.privateKey = PrivateKey::fromPEM(in.pem, SecureArray(), &out.convertResult); else if(in.type == PKDER) out.privateKey = PrivateKey::fromDER(in.der, SecureArray(), &out.convertResult); else if(in.type == KBDERFile) out.keyBundle = KeyBundle::fromFile(in.fileName, SecureArray(), &out.convertResult); else if(in.type == KBDER) out.keyBundle = KeyBundle::fromArray(in.kbder, SecureArray(), &out.convertResult); } }; class KeyLoader::Private : public QObject { Q_OBJECT public: KeyLoader *q; bool active; KeyLoaderThread *thread; KeyLoaderThread::In in; KeyLoaderThread::Out out; Private(KeyLoader *_q) : QObject(_q), q(_q) { active = false; } void reset() { in = KeyLoaderThread::In(); out = KeyLoaderThread::Out(); } void start() { active = true; thread = new KeyLoaderThread(this); // used queued for signal-safety connect(thread, SIGNAL(finished()), SLOT(thread_finished()), Qt::QueuedConnection); thread->in = in; thread->start(); } private slots: void thread_finished() { out = thread->out; delete thread; thread = 0; active = false; emit q->finished(); } }; KeyLoader::KeyLoader(QObject *parent) :QObject(parent) { d = new Private(this); } KeyLoader::~KeyLoader() { delete d; } void KeyLoader::loadPrivateKeyFromPEMFile(const QString &fileName) { Q_ASSERT(!d->active); if(d->active) return; d->reset(); d->in.type = KeyLoaderThread::PKPEMFile; d->in.fileName = fileName; d->start(); } void KeyLoader::loadPrivateKeyFromPEM(const QString &s) { Q_ASSERT(!d->active); if(d->active) return; d->reset(); d->in.type = KeyLoaderThread::PKPEM; d->in.pem = s; d->start(); } void KeyLoader::loadPrivateKeyFromDER(const SecureArray &a) { Q_ASSERT(!d->active); if(d->active) return; d->reset(); d->in.type = KeyLoaderThread::PKDER; d->in.der = a; d->start(); } void KeyLoader::loadKeyBundleFromFile(const QString &fileName) { Q_ASSERT(!d->active); if(d->active) return; d->reset(); d->in.type = KeyLoaderThread::KBDERFile; d->in.fileName = fileName; d->start(); } void KeyLoader::loadKeyBundleFromArray(const QByteArray &a) { Q_ASSERT(!d->active); if(d->active) return; d->reset(); d->in.type = KeyLoaderThread::KBDERFile; d->in.kbder = a; d->start(); } ConvertResult KeyLoader::convertResult() const { return d->out.convertResult; } PrivateKey KeyLoader::privateKey() const { return d->out.privateKey; } KeyBundle KeyLoader::keyBundle() const { return d->out.keyBundle; } } #include "qca_cert.moc" psi-0.14/third-party/qca/qca/src/qca_securemessage.cpp0000644000175000017500000003275611305557613021107 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_securemessage.h" #include "qcaprovider.h" #include "qca_safeobj.h" namespace QCA { Provider::Context *getContext(const QString &type, const QString &provider); //---------------------------------------------------------------------------- // SecureMessageKey //---------------------------------------------------------------------------- class SecureMessageKey::Private : public QSharedData { public: SecureMessageKey::Type type; PGPKey pgp_pub, pgp_sec; CertificateChain cert_pub; PrivateKey cert_sec; Private() { type = SecureMessageKey::None; } // set the proper type, and reset the opposite data structures if needed void ensureType(SecureMessageKey::Type t) { // if we were non-null and changed, we may need to reset some things if(type != SecureMessageKey::None && t != type) { if(type == SecureMessageKey::X509) { cert_pub = CertificateChain(); cert_sec = PrivateKey(); } else if(type == SecureMessageKey::PGP) { pgp_pub = PGPKey(); pgp_sec = PGPKey(); } } type = t; } }; SecureMessageKey::SecureMessageKey() :d(new Private) { } SecureMessageKey::SecureMessageKey(const SecureMessageKey &from) :d(from.d) { } SecureMessageKey::~SecureMessageKey() { } SecureMessageKey & SecureMessageKey::operator=(const SecureMessageKey &from) { d = from.d; return *this; } bool SecureMessageKey::isNull() const { return (d->type == None); } SecureMessageKey::Type SecureMessageKey::type() const { return d->type; } PGPKey SecureMessageKey::pgpPublicKey() const { return d->pgp_pub; } PGPKey SecureMessageKey::pgpSecretKey() const { return d->pgp_sec; } void SecureMessageKey::setPGPPublicKey(const PGPKey &pub) { d->ensureType(SecureMessageKey::PGP); d->pgp_pub = pub; } void SecureMessageKey::setPGPSecretKey(const PGPKey &sec) { d->ensureType(SecureMessageKey::PGP); Q_ASSERT(sec.isSecret()); d->pgp_sec = sec; } CertificateChain SecureMessageKey::x509CertificateChain() const { return d->cert_pub; } PrivateKey SecureMessageKey::x509PrivateKey() const { return d->cert_sec; } void SecureMessageKey::setX509CertificateChain(const CertificateChain &c) { d->ensureType(SecureMessageKey::X509); d->cert_pub = c; } void SecureMessageKey::setX509PrivateKey(const PrivateKey &k) { d->ensureType(SecureMessageKey::X509); d->cert_sec = k; } void SecureMessageKey::setX509KeyBundle(const KeyBundle &kb) { setX509CertificateChain(kb.certificateChain()); setX509PrivateKey(kb.privateKey()); } bool SecureMessageKey::havePrivate() const { if(d->type == SecureMessageKey::PGP && !d->pgp_sec.isNull()) return true; else if(d->type == SecureMessageKey::X509 && !d->cert_sec.isNull()) return true; return false; } QString SecureMessageKey::name() const { if(d->type == SecureMessageKey::PGP && !d->pgp_pub.isNull()) return d->pgp_pub.primaryUserId(); else if(d->type == SecureMessageKey::X509 && !d->cert_pub.isEmpty()) return d->cert_pub.primary().commonName(); else return QString(); } //---------------------------------------------------------------------------- // SecureMessageSignature //---------------------------------------------------------------------------- class SecureMessageSignature::Private : public QSharedData { public: SecureMessageSignature::IdentityResult r; Validity v; SecureMessageKey key; QDateTime ts; Private() { r = SecureMessageSignature::NoKey; v = ErrorValidityUnknown; } }; SecureMessageSignature::SecureMessageSignature() :d(new Private) { } SecureMessageSignature::SecureMessageSignature(IdentityResult r, Validity v, const SecureMessageKey &key, const QDateTime &ts) :d(new Private) { d->r = r; d->v = v; d->key = key; d->ts = ts; } SecureMessageSignature::SecureMessageSignature(const SecureMessageSignature &from) :d(from.d) { } SecureMessageSignature::~SecureMessageSignature() { } SecureMessageSignature & SecureMessageSignature::operator=(const SecureMessageSignature &from) { d = from.d; return *this; } SecureMessageSignature::IdentityResult SecureMessageSignature::identityResult() const { return d->r; } Validity SecureMessageSignature::keyValidity() const { return d->v; } SecureMessageKey SecureMessageSignature::key() const { return d->key; } QDateTime SecureMessageSignature::timestamp() const { return d->ts; } //---------------------------------------------------------------------------- // SecureMessage //---------------------------------------------------------------------------- enum ResetMode { ResetSession = 0, ResetSessionAndData = 1, ResetAll = 2 }; class SecureMessage::Private : public QObject { Q_OBJECT public: SecureMessage *q; MessageContext *c; SecureMessageSystem *system; bool bundleSigner, smime; SecureMessage::Format format; SecureMessageKeyList to; SecureMessageKeyList from; QByteArray in; bool success; SecureMessage::Error errorCode; QByteArray detachedSig; QString hashName; SecureMessageSignatureList signers; QString dtext; QList bytesWrittenArgs; SafeTimer readyReadTrigger, bytesWrittenTrigger, finishedTrigger; Private(SecureMessage *_q) : readyReadTrigger(this), bytesWrittenTrigger(this), finishedTrigger(this) { q = _q; c = 0; system = 0; readyReadTrigger.setSingleShot(true); bytesWrittenTrigger.setSingleShot(true); finishedTrigger.setSingleShot(true); connect(&readyReadTrigger, SIGNAL(timeout()), SLOT(t_readyRead())); connect(&bytesWrittenTrigger, SIGNAL(timeout()), SLOT(t_bytesWritten())); connect(&finishedTrigger, SIGNAL(timeout()), SLOT(t_finished())); reset(ResetAll); } void init() { connect(c, SIGNAL(updated()), SLOT(updated())); } void reset(ResetMode mode) { if(c) c->reset(); bytesWrittenArgs.clear(); readyReadTrigger.stop(); bytesWrittenTrigger.stop(); finishedTrigger.stop(); if(mode >= ResetSessionAndData) { in.clear(); success = false; errorCode = SecureMessage::ErrorUnknown; detachedSig.clear(); hashName = QString(); signers.clear(); } if(mode >= ResetAll) { bundleSigner = true; format = SecureMessage::Binary; to.clear(); from.clear(); } } public slots: void updated() { bool sig_read = false; bool sig_written = false; bool sig_done = false; int written = 0; { QByteArray a = c->read(); if(!a.isEmpty()) { sig_read = true; in.append(a); } int x = c->written(); if(x > 0) { sig_written = true; written = x; } } if(c->finished()) { sig_done = true; success = c->success(); errorCode = c->errorCode(); dtext = c->diagnosticText(); if(success) { detachedSig = c->signature(); hashName = c->hashName(); signers = c->signers(); } reset(ResetSession); } if(sig_read) readyReadTrigger.start(); if(sig_written) { bytesWrittenArgs += written; bytesWrittenTrigger.start(); } if(sig_done) finishedTrigger.start(); } void t_readyRead() { emit q->readyRead(); } void t_bytesWritten() { emit q->bytesWritten(bytesWrittenArgs.takeFirst()); } void t_finished() { emit q->finished(); } }; SecureMessage::SecureMessage(SecureMessageSystem *system) { d = new Private(this); d->system = system; d->c = static_cast(d->system->context())->createMessage(); change(d->c); d->init(); } SecureMessage::~SecureMessage() { delete d; } SecureMessage::Type SecureMessage::type() const { return d->c->type(); } bool SecureMessage::canSignMultiple() const { return d->c->canSignMultiple(); } bool SecureMessage::canClearsign() const { return (type() == OpenPGP); } bool SecureMessage::canSignAndEncrypt() const { return (type() == OpenPGP); } void SecureMessage::reset() { d->reset(ResetAll); } bool SecureMessage::bundleSignerEnabled() const { return d->bundleSigner; } bool SecureMessage::smimeAttributesEnabled() const { return d->smime; } SecureMessage::Format SecureMessage::format() const { return d->format; } SecureMessageKeyList SecureMessage::recipientKeys() const { return d->to; } SecureMessageKeyList SecureMessage::signerKeys() const { return d->from; } void SecureMessage::setBundleSignerEnabled(bool b) { d->bundleSigner = b; } void SecureMessage::setSMIMEAttributesEnabled(bool b) { d->smime = b; } void SecureMessage::setFormat(Format f) { d->format = f; } void SecureMessage::setRecipient(const SecureMessageKey &key) { d->to = SecureMessageKeyList() << key; } void SecureMessage::setRecipients(const SecureMessageKeyList &keys) { d->to = keys; } void SecureMessage::setSigner(const SecureMessageKey &key) { d->from = SecureMessageKeyList() << key; } void SecureMessage::setSigners(const SecureMessageKeyList &keys) { d->from = keys; } void SecureMessage::startEncrypt() { d->reset(ResetSessionAndData); d->c->setupEncrypt(d->to); d->c->start(d->format, MessageContext::Encrypt); } void SecureMessage::startDecrypt() { d->reset(ResetSessionAndData); d->c->start(d->format, MessageContext::Decrypt); } void SecureMessage::startSign(SignMode m) { d->reset(ResetSessionAndData); d->c->setupSign(d->from, m, d->bundleSigner, d->smime); d->c->start(d->format, MessageContext::Sign); } void SecureMessage::startVerify(const QByteArray &sig) { d->reset(ResetSessionAndData); if(!sig.isEmpty()) d->c->setupVerify(sig); d->c->start(d->format, MessageContext::Verify); } void SecureMessage::startSignAndEncrypt() { d->reset(ResetSessionAndData); d->c->setupEncrypt(d->to); d->c->setupSign(d->from, Message, d->bundleSigner, d->smime); d->c->start(d->format, MessageContext::SignAndEncrypt); } void SecureMessage::update(const QByteArray &in) { d->c->update(in); } QByteArray SecureMessage::read() { QByteArray a = d->in; d->in.clear(); return a; } int SecureMessage::bytesAvailable() const { return d->in.size(); } void SecureMessage::end() { d->c->end(); } bool SecureMessage::waitForFinished(int msecs) { d->c->waitForFinished(msecs); d->updated(); return d->success; } bool SecureMessage::success() const { return d->success; } SecureMessage::Error SecureMessage::errorCode() const { return d->errorCode; } QByteArray SecureMessage::signature() const { return d->detachedSig; } QString SecureMessage::hashName() const { return d->hashName; } bool SecureMessage::wasSigned() const { return !d->signers.isEmpty(); } bool SecureMessage::verifySuccess() const { // if we're not done or there were no signers, then return false if(!d->success || d->signers.isEmpty()) return false; // make sure all signers have a valid signature for(int n = 0; n < d->signers.count(); ++n) { if(d->signers[n].identityResult() != SecureMessageSignature::Valid) return false; } return true; } SecureMessageSignature SecureMessage::signer() const { if(d->signers.isEmpty()) return SecureMessageSignature(); return d->signers.first(); } SecureMessageSignatureList SecureMessage::signers() const { return d->signers; } QString SecureMessage::diagnosticText() const { return d->dtext; } //---------------------------------------------------------------------------- // SecureMessageSystem //---------------------------------------------------------------------------- SecureMessageSystem::SecureMessageSystem(QObject *parent, const QString &type, const QString &provider) :QObject(parent), Algorithm(type, provider) { } SecureMessageSystem::~SecureMessageSystem() { } //---------------------------------------------------------------------------- // OpenPGP //---------------------------------------------------------------------------- OpenPGP::OpenPGP(QObject *parent, const QString &provider) :SecureMessageSystem(parent, "openpgp", provider) { } OpenPGP::~OpenPGP() { } //---------------------------------------------------------------------------- // CMS //---------------------------------------------------------------------------- class CMS::Private { public: CertificateCollection trusted, untrusted; SecureMessageKeyList privateKeys; }; CMS::CMS(QObject *parent, const QString &provider) :SecureMessageSystem(parent, "cms", provider) { d = new Private; } CMS::~CMS() { delete d; } CertificateCollection CMS::trustedCertificates() const { return d->trusted; } CertificateCollection CMS::untrustedCertificates() const { return d->untrusted; } SecureMessageKeyList CMS::privateKeys() const { return d->privateKeys; } void CMS::setTrustedCertificates(const CertificateCollection &trusted) { d->trusted = trusted; static_cast(context())->setTrustedCertificates(trusted); } void CMS::setUntrustedCertificates(const CertificateCollection &untrusted) { d->untrusted = untrusted; static_cast(context())->setUntrustedCertificates(untrusted); } void CMS::setPrivateKeys(const SecureMessageKeyList &keys) { d->privateKeys = keys; static_cast(context())->setPrivateKeys(keys); } } #include "qca_securemessage.moc" psi-0.14/third-party/qca/qca/src/qca_systemstore_flatfile.cpp0000644000175000017500000000216711305557613022514 0ustar janjan/* * Copyright (C) 2004,2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_systemstore.h" #include namespace QCA { bool qca_have_systemstore() { QFile f(QCA_SYSTEMSTORE_PATH); return f.open(QFile::ReadOnly); } CertificateCollection qca_get_systemstore(const QString &provider) { return CertificateCollection::fromFlatTextFile(QCA_SYSTEMSTORE_PATH, 0, provider); } } psi-0.14/third-party/qca/qca/src/qca_core.cpp0000644000175000017500000012354011305557613017174 0ustar janjan/* * Copyright (C) 2003-2008 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_core.h" #include "qca_plugin.h" #include "qca_textfilter.h" #include "qca_cert.h" #include "qca_keystore.h" #include "qcaprovider.h" // for qAddPostRoutine #include #include #include #include #include #ifdef Q_OS_UNIX # include #endif int qcaVersion() { return QCA_VERSION; } namespace QCA { // from qca_tools bool botan_init(int prealloc, bool mmap); void botan_deinit(); // from qca_default Provider *create_default_provider(); //---------------------------------------------------------------------------- // Global //---------------------------------------------------------------------------- class Global { public: int refs; bool secmem; bool loaded; bool first_scan; QString app_name; QMutex name_mutex; ProviderManager *manager; QMutex scan_mutex; Random *rng; QMutex rng_mutex; Logger *logger; QVariantMap properties; QMutex prop_mutex; QMap config; QMutex config_mutex; QMutex logger_mutex; Global() { refs = 0; secmem = false; loaded = false; first_scan = false; rng = 0; logger = 0; manager = new ProviderManager; } ~Global() { KeyStoreManager::shutdown(); delete rng; rng = 0; delete manager; manager = 0; delete logger; logger = 0; } void ensure_loaded() { // probably we shouldn't overload scan mutex, or else rename it QMutexLocker locker(&scan_mutex); if(!loaded) { loaded = true; manager->setDefault(create_default_provider()); // manager owns it } } bool ensure_first_scan() { scan_mutex.lock(); if(!first_scan) { first_scan = true; manager->scan(); scan_mutex.unlock(); return true; } scan_mutex.unlock(); return false; } void scan() { scan_mutex.lock(); first_scan = true; manager->scan(); scan_mutex.unlock(); } void ksm_scan() { KeyStoreManager::scan(); } Logger *get_logger() { QMutexLocker locker(&logger_mutex); if(!logger) { logger = new Logger; // needed so deinit may delete the logger regardless // of what thread the logger was created from logger->moveToThread(0); } return logger; } void unloadAllPlugins() { KeyStoreManager::shutdown(); // if the global_rng was owned by a plugin, then delete it rng_mutex.lock(); if(rng && (rng->provider() != manager->find("default"))) { delete rng; rng = 0; } rng_mutex.unlock(); manager->unloadAll(); } }; Q_GLOBAL_STATIC(QMutex, global_mutex) static Global *global = 0; static bool features_have(const QStringList &have, const QStringList &want) { foreach(const QString &i, want) { if(!have.contains(i)) return false; } return true; } void init(MemoryMode mode, int prealloc) { QMutexLocker locker(global_mutex()); if(global) { ++(global->refs); return; } bool allow_mmap_fallback = false; bool drop_root = false; if(mode == Practical) { allow_mmap_fallback = true; drop_root = true; } else if(mode == Locking) drop_root = true; bool secmem = botan_init(prealloc, allow_mmap_fallback); if(drop_root) { #ifdef Q_OS_UNIX setuid(getuid()); #endif } global = new Global; global->secmem = secmem; ++(global->refs); // for maximum setuid safety, qca should be initialized before qapp: // // int main(int argc, char **argv) // { // QCA::Initializer init; // QCoreApplication app(argc, argv); // return 0; // } // // however, the above code has the unfortunate side-effect of causing // qapp to deinit before qca, which can cause problems with any // plugins that have active objects (notably KeyStore). we'll use a // post routine to force qca to deinit first. qAddPostRoutine(deinit); } void init() { init(Practical, 64); } void deinit() { QMutexLocker locker(global_mutex()); if(!global) return; --(global->refs); if(global->refs == 0) { delete global; global = 0; botan_deinit(); } } static bool global_check() { Q_ASSERT(global); if(!global) return false; return true; } static bool global_check_load() { Q_ASSERT(global); if(!global) return false; global->ensure_loaded(); return true; } QMutex *global_random_mutex() { return &global->rng_mutex; } Random *global_random() { if(!global->rng) global->rng = new Random; return global->rng; } bool haveSecureMemory() { if(!global_check()) return false; return global->secmem; } bool haveSecureRandom() { if(!global_check_load()) return false; QMutexLocker locker(global_random_mutex()); if(global_random()->provider()->name() != "default") return true; return false; } bool isSupported(const QStringList &features, const QString &provider) { if(!global_check_load()) return false; // single if(!provider.isEmpty()) { Provider *p = global->manager->find(provider); if(!p) { // ok, try scanning for new stuff global->scan(); p = global->manager->find(provider); } if(p && features_have(p->features(), features)) return true; } // all else { if(features_have(global->manager->allFeatures(), features)) return true; global->manager->appendDiagnosticText(QString("Scanning to find features: %1\n").arg(features.join(" "))); // ok, try scanning for new stuff global->scan(); if(features_have(global->manager->allFeatures(), features)) return true; } return false; } bool isSupported(const char *features, const QString &provider) { return isSupported(QString(features).split(',', QString::SkipEmptyParts), provider); } QStringList supportedFeatures() { if(!global_check_load()) return QStringList(); // query all features global->scan(); return global->manager->allFeatures(); } QStringList defaultFeatures() { if(!global_check_load()) return QStringList(); return global->manager->find("default")->features(); } ProviderList providers() { if(!global_check_load()) return ProviderList(); global->ensure_first_scan(); return global->manager->providers(); } bool insertProvider(Provider *p, int priority) { if(!global_check_load()) return false; global->ensure_first_scan(); return global->manager->add(p, priority); } void setProviderPriority(const QString &name, int priority) { if(!global_check_load()) return; global->ensure_first_scan(); global->manager->changePriority(name, priority); } int providerPriority(const QString &name) { if(!global_check_load()) return -1; global->ensure_first_scan(); return global->manager->getPriority(name); } Provider *findProvider(const QString &name) { if(!global_check_load()) return 0; global->ensure_first_scan(); return global->manager->find(name); } Provider *defaultProvider() { if(!global_check_load()) return 0; return global->manager->find("default"); } void scanForPlugins() { if(!global_check_load()) return; global->scan(); global->ksm_scan(); } void unloadAllPlugins() { if(!global_check_load()) return; global->unloadAllPlugins(); } QString pluginDiagnosticText() { if(!global_check_load()) return QString(); return global->manager->diagnosticText(); } void clearPluginDiagnosticText() { if(!global_check_load()) return; global->manager->clearDiagnosticText(); } void appendPluginDiagnosticText(const QString &text) { if(!global_check_load()) return; global->manager->appendDiagnosticText(text); } void setProperty(const QString &name, const QVariant &value) { if(!global_check_load()) return; QMutexLocker locker(&global->prop_mutex); global->properties[name] = value; } QVariant getProperty(const QString &name) { if(!global_check_load()) return QVariant(); QMutexLocker locker(&global->prop_mutex); return global->properties.value(name); } static bool configIsValid(const QVariantMap &config) { if(!config.contains("formtype")) return false; QMapIterator it(config); while(it.hasNext()) { it.next(); const QVariant &v = it.value(); if(v.type() != QVariant::String && v.type() != QVariant::Int && v.type() != QVariant::Bool) return false; } return true; } static QVariantMap readConfig(const QString &name) { QSettings settings("Affinix", "QCA2"); settings.beginGroup("ProviderConfig"); QStringList providerNames = settings.value("providerNames").toStringList(); if(!providerNames.contains(name)) return QVariantMap(); settings.beginGroup(name); QStringList keys = settings.childKeys(); QVariantMap map; foreach(const QString &key, keys) map[key] = settings.value(key); settings.endGroup(); if(!configIsValid(map)) return QVariantMap(); return map; } static bool writeConfig(const QString &name, const QVariantMap &config, bool systemWide = false) { QSettings settings(QSettings::NativeFormat, systemWide ? QSettings::SystemScope : QSettings::UserScope, "Affinix", "QCA2"); settings.beginGroup("ProviderConfig"); // version settings.setValue("version", 2); // add the entry if needed QStringList providerNames = settings.value("providerNames").toStringList(); if(!providerNames.contains(name)) providerNames += name; settings.setValue("providerNames", providerNames); settings.beginGroup(name); QMapIterator it(config); while(it.hasNext()) { it.next(); settings.setValue(it.key(), it.value()); } settings.endGroup(); if(settings.status() == QSettings::NoError) return true; return false; } void setProviderConfig(const QString &name, const QVariantMap &config) { if(!global_check_load()) return; if(!configIsValid(config)) return; global->config_mutex.lock(); global->config[name] = config; global->config_mutex.unlock(); Provider *p = findProvider(name); if(p) p->configChanged(config); } QVariantMap getProviderConfig(const QString &name) { if(!global_check_load()) return QVariantMap(); QVariantMap conf; global->config_mutex.lock(); // try loading from persistent storage conf = readConfig(name); // if not, load the one from memory if(conf.isEmpty()) conf = global->config.value(name); global->config_mutex.unlock(); // if provider doesn't exist or doesn't have a valid config form, // use the config we loaded Provider *p = findProvider(name); if(!p) return conf; QVariantMap pconf = p->defaultConfig(); if(!configIsValid(pconf)) return conf; // if the config loaded was empty, use the provider's config if(conf.isEmpty()) return pconf; // if the config formtype doesn't match the provider's formtype, // then use the provider's if(pconf["formtype"] != conf["formtype"]) return pconf; // otherwise, use the config loaded return conf; } void saveProviderConfig(const QString &name) { if(!global_check_load()) return; QMutexLocker locker(&global->config_mutex); QVariantMap conf = global->config.value(name); if(conf.isEmpty()) return; writeConfig(name, conf); } QVariantMap getProviderConfig_internal(Provider *p) { QVariantMap conf; QString name = p->name(); global->config_mutex.lock(); // try loading from persistent storage conf = readConfig(name); // if not, load the one from memory if(conf.isEmpty()) conf = global->config.value(name); global->config_mutex.unlock(); // if provider doesn't exist or doesn't have a valid config form, // use the config we loaded QVariantMap pconf = p->defaultConfig(); if(!configIsValid(pconf)) return conf; // if the config loaded was empty, use the provider's config if(conf.isEmpty()) return pconf; // if the config formtype doesn't match the provider's formtype, // then use the provider's if(pconf["formtype"] != conf["formtype"]) return pconf; // otherwise, use the config loaded return conf; } QString globalRandomProvider() { QMutexLocker locker(global_random_mutex()); return global_random()->provider()->name(); } void setGlobalRandomProvider(const QString &provider) { QMutexLocker locker(global_random_mutex()); delete global->rng; global->rng = new Random(provider); } Logger *logger() { return global->get_logger(); } bool haveSystemStore() { // ensure the system store is loaded KeyStoreManager::start("default"); KeyStoreManager ksm; ksm.waitForBusyFinished(); QStringList list = ksm.keyStores(); for(int n = 0; n < list.count(); ++n) { KeyStore ks(list[n], &ksm); if(ks.type() == KeyStore::System && ks.holdsTrustedCertificates()) return true; } return false; } CertificateCollection systemStore() { // ensure the system store is loaded KeyStoreManager::start("default"); KeyStoreManager ksm; ksm.waitForBusyFinished(); CertificateCollection col; QStringList list = ksm.keyStores(); for(int n = 0; n < list.count(); ++n) { KeyStore ks(list[n], &ksm); // system store if(ks.type() == KeyStore::System && ks.holdsTrustedCertificates()) { // extract contents QList entries = ks.entryList(); for(int i = 0; i < entries.count(); ++i) { if(entries[i].type() == KeyStoreEntry::TypeCertificate) col.addCertificate(entries[i].certificate()); else if(entries[i].type() == KeyStoreEntry::TypeCRL) col.addCRL(entries[i].crl()); } break; } } return col; } QString appName() { if(!global_check()) return QString(); QMutexLocker locker(&global->name_mutex); return global->app_name; } void setAppName(const QString &s) { if(!global_check()) return; QMutexLocker locker(&global->name_mutex); global->app_name = s; } QString arrayToHex(const QByteArray &a) { return Hex().arrayToString(a); } QByteArray hexToArray(const QString &str) { return Hex().stringToArray(str).toByteArray(); } static Provider *getProviderForType(const QString &type, const QString &provider) { Provider *p = 0; bool scanned = global->ensure_first_scan(); if(!provider.isEmpty()) { // try using specific provider p = global->manager->findFor(provider, type); if(!p && !scanned) { // maybe this provider is new, so scan and try again global->scan(); scanned = true; p = global->manager->findFor(provider, type); } } if(!p) { // try using some other provider p = global->manager->findFor(QString(), type); // note: we used to rescan if no provider was found or if // the only found provider was 'default'. now we only // rescan if no provider was found. this optimizes lookups // for features that are in the default provider (such as // 'sha1') when no other plugin is available. the drawback // is that if a plugin is installed later during runtime, // then it won't be picked up without restarting the // application or manually calling QCA::scanForPlugins. //if((!p || p->name() == "default") && !scanned) if(!p && !scanned) { // maybe there are new providers, so scan and try again // before giving up or using default global->scan(); scanned = true; p = global->manager->findFor(QString(), type); } } return p; } static inline Provider::Context *doCreateContext(Provider *p, const QString &type) { return p->createContext(type); } Provider::Context *getContext(const QString &type, const QString &provider) { if(!global_check_load()) return 0; Provider *p; { p = getProviderForType(type, provider); if(!p) return 0; } return doCreateContext(p, type); } Provider::Context *getContext(const QString &type, Provider *_p) { if(!global_check_load()) return 0; Provider *p; { p = global->manager->find(_p); if(!p) return 0; } return doCreateContext(p, type); } //---------------------------------------------------------------------------- // Initializer //---------------------------------------------------------------------------- Initializer::Initializer(MemoryMode m, int prealloc) { init(m, prealloc); } Initializer::~Initializer() { deinit(); } //---------------------------------------------------------------------------- // Provider //---------------------------------------------------------------------------- Provider::~Provider() { } void Provider::init() { } void Provider::deinit() { } int Provider::version() const { return 0; } QString Provider::credit() const { return QString(); } QVariantMap Provider::defaultConfig() const { return QVariantMap(); } void Provider::configChanged(const QVariantMap &) { } Provider::Context::Context(Provider *parent, const QString &type) :QObject() { _provider = parent; _type = type; } Provider::Context::Context(const Context &from) :QObject() { _provider = from._provider; _type = from._type; } Provider::Context::~Context() { } Provider *Provider::Context::provider() const { return _provider; } QString Provider::Context::type() const { return _type; } bool Provider::Context::sameProvider(const Context *c) const { return (c->provider() == _provider); } //---------------------------------------------------------------------------- // BasicContext //---------------------------------------------------------------------------- BasicContext::BasicContext(Provider *parent, const QString &type) :Context(parent, type) { moveToThread(0); // no thread association } BasicContext::BasicContext(const BasicContext &from) :Context(from) { moveToThread(0); // no thread association } BasicContext::~BasicContext() { } //---------------------------------------------------------------------------- // InfoContext //---------------------------------------------------------------------------- QStringList InfoContext::supportedHashTypes() const { return QStringList(); } QStringList InfoContext::supportedCipherTypes() const { return QStringList(); } QStringList InfoContext::supportedMACTypes() const { return QStringList(); } //---------------------------------------------------------------------------- // PKeyBase //---------------------------------------------------------------------------- PKeyBase::PKeyBase(Provider *p, const QString &type) :BasicContext(p, type) { } int PKeyBase::maximumEncryptSize(EncryptionAlgorithm) const { return 0; } SecureArray PKeyBase::encrypt(const SecureArray &, EncryptionAlgorithm) { return SecureArray(); } bool PKeyBase::decrypt(const SecureArray &, SecureArray *, EncryptionAlgorithm) { return false; } void PKeyBase::startSign(SignatureAlgorithm, SignatureFormat) { } void PKeyBase::startVerify(SignatureAlgorithm, SignatureFormat) { } void PKeyBase::update(const MemoryRegion &) { } QByteArray PKeyBase::endSign() { return QByteArray(); } bool PKeyBase::endVerify(const QByteArray &) { return false; } SymmetricKey PKeyBase::deriveKey(const PKeyBase &) { return SymmetricKey(); } //---------------------------------------------------------------------------- // PKeyContext //---------------------------------------------------------------------------- QByteArray PKeyContext::publicToDER() const { return QByteArray(); } QString PKeyContext::publicToPEM() const { return QString(); } ConvertResult PKeyContext::publicFromDER(const QByteArray &) { return ErrorDecode; } ConvertResult PKeyContext::publicFromPEM(const QString &) { return ErrorDecode; } SecureArray PKeyContext::privateToDER(const SecureArray &, PBEAlgorithm) const { return SecureArray(); } QString PKeyContext::privateToPEM(const SecureArray &, PBEAlgorithm) const { return QString(); } ConvertResult PKeyContext::privateFromDER(const SecureArray &, const SecureArray &) { return ErrorDecode; } ConvertResult PKeyContext::privateFromPEM(const QString &, const SecureArray &) { return ErrorDecode; } //---------------------------------------------------------------------------- // KeyStoreEntryContext //---------------------------------------------------------------------------- bool KeyStoreEntryContext::isAvailable() const { return true; } KeyBundle KeyStoreEntryContext::keyBundle() const { return KeyBundle(); } Certificate KeyStoreEntryContext::certificate() const { return Certificate(); } CRL KeyStoreEntryContext::crl() const { return CRL(); } PGPKey KeyStoreEntryContext::pgpSecretKey() const { return PGPKey(); } PGPKey KeyStoreEntryContext::pgpPublicKey() const { return PGPKey(); } bool KeyStoreEntryContext::ensureAccess() { return true; } //---------------------------------------------------------------------------- // KeyStoreListContext //---------------------------------------------------------------------------- void KeyStoreListContext::start() { QMetaObject::invokeMethod(this, "busyEnd", Qt::QueuedConnection); } void KeyStoreListContext::setUpdatesEnabled(bool) { } bool KeyStoreListContext::isReadOnly(int) const { return true; } KeyStoreEntryContext *KeyStoreListContext::entry(int id, const QString &entryId) { KeyStoreEntryContext *out = 0; QList list = entryList(id); for(int n = 0; n < list.count(); ++n) { if(list[n]->id() == entryId) { out = list.takeAt(n); break; } } qDeleteAll(list); return out; } KeyStoreEntryContext *KeyStoreListContext::entryPassive(const QString &serialized) { Q_UNUSED(serialized); return 0; } QString KeyStoreListContext::writeEntry(int, const KeyBundle &) { return QString(); } QString KeyStoreListContext::writeEntry(int, const Certificate &) { return QString(); } QString KeyStoreListContext::writeEntry(int, const CRL &) { return QString(); } QString KeyStoreListContext::writeEntry(int, const PGPKey &) { return QString(); } bool KeyStoreListContext::removeEntry(int, const QString &) { return false; } //---------------------------------------------------------------------------- // TLSContext //---------------------------------------------------------------------------- void TLSContext::setMTU(int) { } //---------------------------------------------------------------------------- // MessageContext //---------------------------------------------------------------------------- QString MessageContext::diagnosticText() const { return QString(); } //---------------------------------------------------------------------------- // SMSContext //---------------------------------------------------------------------------- void SMSContext::setTrustedCertificates(const CertificateCollection &) { } void SMSContext::setUntrustedCertificates(const CertificateCollection &) { } void SMSContext::setPrivateKeys(const QList &) { } //---------------------------------------------------------------------------- // BufferedComputation //---------------------------------------------------------------------------- BufferedComputation::~BufferedComputation() { } MemoryRegion BufferedComputation::process(const MemoryRegion &a) { clear(); update(a); return final(); } //---------------------------------------------------------------------------- // Filter //---------------------------------------------------------------------------- Filter::~Filter() { } MemoryRegion Filter::process(const MemoryRegion &a) { clear(); MemoryRegion buf = update(a); if(!ok()) return MemoryRegion(); MemoryRegion fin = final(); if(!ok()) return MemoryRegion(); if(buf.isSecure() || fin.isSecure()) return (SecureArray(buf) + SecureArray(fin)); else return (buf.toByteArray() + fin.toByteArray()); } //---------------------------------------------------------------------------- // Algorithm //---------------------------------------------------------------------------- class Algorithm::Private : public QSharedData { public: Provider::Context *c; Private(Provider::Context *context) { c = context; //printf("** [%p] Algorithm Created\n", c); } Private(const Private &from) : QSharedData(from) { c = from.c->clone(); //printf("** [%p] Algorithm Copied (to [%p])\n", from.c, c); } ~Private() { //printf("** [%p] Algorithm Destroyed\n", c); delete c; } }; Algorithm::Algorithm() { } Algorithm::Algorithm(const QString &type, const QString &provider) { change(type, provider); } Algorithm::Algorithm(const Algorithm &from) { *this = from; } Algorithm::~Algorithm() { } Algorithm & Algorithm::operator=(const Algorithm &from) { d = from.d; return *this; } QString Algorithm::type() const { if(d) return d->c->type(); else return QString(); } Provider *Algorithm::provider() const { if(d) return d->c->provider(); else return 0; } Provider::Context *Algorithm::context() { if(d) return d->c; else return 0; } const Provider::Context *Algorithm::context() const { if(d) return d->c; else return 0; } void Algorithm::change(Provider::Context *c) { if(c) d = new Private(c); else d = 0; } void Algorithm::change(const QString &type, const QString &provider) { if(!type.isEmpty()) change(getContext(type, provider)); else change(0); } Provider::Context *Algorithm::takeContext() { if(d) { Provider::Context *c = d->c; // should cause a detach d->c = 0; d = 0; return c; } else return 0; } //---------------------------------------------------------------------------- // SymmetricKey //---------------------------------------------------------------------------- SymmetricKey::SymmetricKey() { } SymmetricKey::SymmetricKey(int size) { set(Random::randomArray(size)); } SymmetricKey::SymmetricKey(const SecureArray &a) { set(a); } SymmetricKey::SymmetricKey(const QByteArray &a) { set(SecureArray(a)); } /* from libgcrypt-1.2.0 */ static unsigned char desWeakKeyTable[64][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /*w*/ { 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e }, { 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0 }, { 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe }, { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e }, /*sw*/ { 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00 }, { 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe }, { 0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0 }, { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0 }, /*sw*/ { 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe }, { 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00 }, { 0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e }, { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe }, /*sw*/ { 0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0 }, { 0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e }, { 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00 }, { 0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e }, { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 }, /*sw*/ { 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe }, { 0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0 }, { 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00 }, { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e }, /*w*/ { 0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0 }, { 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe }, { 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe }, { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 }, /*sw*/ { 0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e }, { 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00 }, { 0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0 }, { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe }, /*sw*/ { 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00 }, { 0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e }, { 0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0 }, { 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe }, { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 }, /*sw*/ { 0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e }, { 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe }, { 0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0 }, { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e }, /*sw*/ { 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00 }, { 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00 }, { 0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e }, { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 }, /*w*/ { 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe }, { 0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e }, { 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00 }, { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe }, /*sw*/ { 0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0 }, { 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe }, { 0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0 }, { 0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e }, { 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00 }, /*sw*/ { 0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0 }, { 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe }, { 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00 }, { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e }, /*sw*/ { 0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e }, { 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00 }, { 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe }, { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 }, /*sw*/ { 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00 }, { 0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e }, { 0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0 }, { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe } /*w*/ }; bool SymmetricKey::isWeakDESKey() { if(size() != 8) return false; // dubious SecureArray workingCopy(8); // clear parity bits for(uint i = 0; i < 8; i++) workingCopy[i] = (data()[i]) & 0xfe; for(int n = 0; n < 64; n++) { if(memcmp(workingCopy.data(), desWeakKeyTable[n], 8) == 0) return true; } return false; } //---------------------------------------------------------------------------- // InitializationVector //---------------------------------------------------------------------------- InitializationVector::InitializationVector() { } InitializationVector::InitializationVector(int size) { set(Random::randomArray(size)); } InitializationVector::InitializationVector(const SecureArray &a) { set(a); } InitializationVector::InitializationVector(const QByteArray &a) { set(SecureArray(a)); } //---------------------------------------------------------------------------- // Event //---------------------------------------------------------------------------- class Event::Private : public QSharedData { public: Type type; Source source; PasswordStyle style; KeyStoreInfo ksi; KeyStoreEntry kse; QString fname; void *ptr; }; Event::Event() { } Event::Event(const Event &from) :d(from.d) { } Event::~Event() { } Event & Event::operator=(const Event &from) { d = from.d; return *this; } bool Event::isNull() const { return (d ? false : true); } Event::Type Event::type() const { return d->type; } Event::Source Event::source() const { return d->source; } Event::PasswordStyle Event::passwordStyle() const { return d->style; } KeyStoreInfo Event::keyStoreInfo() const { return d->ksi; } KeyStoreEntry Event::keyStoreEntry() const { return d->kse; } QString Event::fileName() const { return d->fname; } void *Event::ptr() const { return d->ptr; } void Event::setPasswordKeyStore(PasswordStyle pstyle, const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr) { if(!d) d = new Private; d->type = Password; d->source = KeyStore; d->style = pstyle; d->ksi = keyStoreInfo; d->kse = keyStoreEntry; d->fname = QString(); d->ptr = ptr; } void Event::setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr) { if(!d) d = new Private; d->type = Password; d->source = Data; d->style = pstyle; d->ksi = KeyStoreInfo(); d->kse = KeyStoreEntry(); d->fname = fileName; d->ptr = ptr; } void Event::setToken(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr) { if(!d) d = new Private; d->type = Token; d->source = KeyStore; d->style = StylePassword; d->ksi = keyStoreInfo; d->kse = keyStoreEntry; d->fname = QString(); d->ptr = ptr; } //---------------------------------------------------------------------------- // EventGlobal //---------------------------------------------------------------------------- class HandlerBase : public QObject { Q_OBJECT public: HandlerBase(QObject *parent = 0) : QObject(parent) { } protected slots: virtual void ask(int id, const QCA::Event &e) = 0; }; class AskerBase : public QObject { Q_OBJECT public: AskerBase(QObject *parent = 0) : QObject(parent) { } virtual void set_accepted(const SecureArray &password) = 0; virtual void set_rejected() = 0; }; static void handler_add(HandlerBase *h, int pos = -1); static void handler_remove(HandlerBase *h); static void handler_accept(HandlerBase *h, int id, const SecureArray &password); static void handler_reject(HandlerBase *h, int id); static bool asker_ask(AskerBase *a, const Event &e); static void asker_cancel(AskerBase *a); Q_GLOBAL_STATIC(QMutex, g_event_mutex) class EventGlobal; static EventGlobal *g_event = 0; class EventGlobal { public: class HandlerItem { public: HandlerBase *h; QList ids; }; class AskerItem { public: AskerBase *a; int id; Event event; int handler_pos; }; QList handlers; QList askers; int next_id; EventGlobal() { qRegisterMetaType("QCA::Event"); qRegisterMetaType("QCA::SecureArray"); next_id = 0; } int findHandlerItem(HandlerBase *h) { for(int n = 0; n < handlers.count(); ++n) { if(handlers[n].h == h) return n; } return -1; } int findAskerItem(AskerBase *a) { for(int n = 0; n < askers.count(); ++n) { if(askers[n].a == a) return n; } return -1; } int findAskerItemById(int id) { for(int n = 0; n < askers.count(); ++n) { if(askers[n].id == id) return n; } return -1; } void ask(int asker_at) { AskerItem &i = askers[asker_at]; g_event->handlers[i.handler_pos].ids += i.id; QMetaObject::invokeMethod(handlers[i.handler_pos].h, "ask", Qt::QueuedConnection, Q_ARG(int, i.id), Q_ARG(QCA::Event, i.event)); } void reject(int asker_at) { AskerItem &i = askers[asker_at]; // look for the next usable handler int pos = -1; for(int n = i.handler_pos + 1; n < g_event->handlers.count(); ++n) { // handler and asker can't be in the same thread //Q_ASSERT(g_event->handlers[n].h->thread() != i.a->thread()); //if(g_event->handlers[n].h->thread() != i.a->thread()) //{ pos = n; break; //} } // if there is one, try it if(pos != -1) { i.handler_pos = pos; ask(asker_at); } // if not, send official reject else { AskerBase *asker = i.a; askers.removeAt(asker_at); asker->set_rejected(); } } }; void handler_add(HandlerBase *h, int pos) { QMutexLocker locker(g_event_mutex()); if(!g_event) g_event = new EventGlobal; EventGlobal::HandlerItem i; i.h = h; if(pos != -1) { g_event->handlers.insert(pos, i); // adjust handler positions for(int n = 0; n < g_event->askers.count(); ++n) { if(g_event->askers[n].handler_pos >= pos) g_event->askers[n].handler_pos++; } } else g_event->handlers += i; } void handler_remove(HandlerBase *h) { QMutexLocker locker(g_event_mutex()); Q_ASSERT(g_event); if(!g_event) return; int at = g_event->findHandlerItem(h); Q_ASSERT(at != -1); if(at == -1) return; QList ids = g_event->handlers[at].ids; g_event->handlers.removeAt(at); // adjust handler positions within askers for(int n = 0; n < g_event->askers.count(); ++n) { if(g_event->askers[n].handler_pos >= at) g_event->askers[n].handler_pos--; } // reject all askers foreach(int id, ids) { int asker_at = g_event->findAskerItemById(id); Q_ASSERT(asker_at != -1); g_event->reject(asker_at); } if(g_event->handlers.isEmpty()) { delete g_event; g_event = 0; } } void handler_accept(HandlerBase *h, int id, const SecureArray &password) { QMutexLocker locker(g_event_mutex()); Q_ASSERT(g_event); if(!g_event) return; int at = g_event->findHandlerItem(h); Q_ASSERT(at != -1); if(at == -1) return; int asker_at = g_event->findAskerItemById(id); Q_ASSERT(asker_at != -1); if(asker_at == -1) return; g_event->handlers[at].ids.removeAll(g_event->askers[asker_at].id); AskerBase *asker = g_event->askers[asker_at].a; asker->set_accepted(password); } void handler_reject(HandlerBase *h, int id) { QMutexLocker locker(g_event_mutex()); Q_ASSERT(g_event); if(!g_event) return; int at = g_event->findHandlerItem(h); Q_ASSERT(at != -1); if(at == -1) return; int asker_at = g_event->findAskerItemById(id); Q_ASSERT(asker_at != -1); if(asker_at == -1) return; g_event->handlers[at].ids.removeAll(g_event->askers[asker_at].id); g_event->reject(asker_at); } bool asker_ask(AskerBase *a, const Event &e) { QMutexLocker locker(g_event_mutex()); if(!g_event) return false; int pos = -1; for(int n = 0; n < g_event->handlers.count(); ++n) { // handler and asker can't be in the same thread //Q_ASSERT(g_event->handlers[n].h->thread() != a->thread()); //if(g_event->handlers[n].h->thread() != a->thread()) //{ pos = n; break; //} } if(pos == -1) return false; EventGlobal::AskerItem i; i.a = a; i.id = g_event->next_id++; i.event = e; i.handler_pos = pos; g_event->askers += i; int asker_at = g_event->askers.count() - 1; g_event->ask(asker_at); return true; } void asker_cancel(AskerBase *a) { QMutexLocker locker(g_event_mutex()); if(!g_event) return; int at = g_event->findAskerItem(a); if(at == -1) return; for(int n = 0; n < g_event->handlers.count(); ++n) g_event->handlers[n].ids.removeAll(g_event->askers[at].id); g_event->askers.removeAt(at); } //---------------------------------------------------------------------------- // EventHandler //---------------------------------------------------------------------------- class EventHandler::Private : public HandlerBase { Q_OBJECT public: EventHandler *q; bool started; QList activeIds; Private(EventHandler *_q) : HandlerBase(_q), q(_q) { started = false; } public slots: virtual void ask(int id, const QCA::Event &e) { activeIds += id; emit q->eventReady(id, e); } }; EventHandler::EventHandler(QObject *parent) :QObject(parent) { d = new Private(this); } EventHandler::~EventHandler() { if(d->started) { foreach(int id, d->activeIds) handler_reject(d, id); handler_remove(d); } delete d; } void EventHandler::start() { d->started = true; handler_add(d); } void EventHandler::submitPassword(int id, const SecureArray &password) { if(!d->activeIds.contains(id)) return; d->activeIds.removeAll(id); handler_accept(d, id, password); } void EventHandler::tokenOkay(int id) { if(!d->activeIds.contains(id)) return; d->activeIds.removeAll(id); handler_accept(d, id, SecureArray()); } void EventHandler::reject(int id) { if(!d->activeIds.contains(id)) return; d->activeIds.removeAll(id); handler_reject(d, id); } //---------------------------------------------------------------------------- // PasswordAsker //---------------------------------------------------------------------------- class AskerPrivate : public AskerBase { Q_OBJECT public: enum Type { Password, Token }; Type type; PasswordAsker *passwordAsker; TokenAsker *tokenAsker; QMutex m; QWaitCondition w; bool accepted; SecureArray password; bool waiting; bool done; AskerPrivate(PasswordAsker *parent) : AskerBase(parent) { passwordAsker = parent; tokenAsker = 0; type = Password; accepted = false; waiting = false; done = true; } AskerPrivate(TokenAsker *parent) : AskerBase(parent) { passwordAsker = 0; tokenAsker = parent; type = Token; accepted = false; waiting = false; done = true; } void ask(const Event &e) { accepted = false; waiting = false; done = false; password.clear(); if(!asker_ask(this, e)) { done = true; QMetaObject::invokeMethod(this, "emitResponseReady", Qt::QueuedConnection); } } void cancel() { if(!done) asker_cancel(this); } virtual void set_accepted(const SecureArray &_password) { QMutexLocker locker(&m); accepted = true; password = _password; done = true; if(waiting) w.wakeOne(); else QMetaObject::invokeMethod(this, "emitResponseReady", Qt::QueuedConnection); } virtual void set_rejected() { QMutexLocker locker(&m); done = true; if(waiting) w.wakeOne(); else QMetaObject::invokeMethod(this, "emitResponseReady", Qt::QueuedConnection); } void waitForResponse() { QMutexLocker locker(&m); if(done) return; waiting = true; w.wait(&m); waiting = false; } public slots: virtual void emitResponseReady() = 0; }; class PasswordAsker::Private : public AskerPrivate { public: Private(PasswordAsker *_q) : AskerPrivate(_q) { } virtual void emitResponseReady() { emit passwordAsker->responseReady(); } }; PasswordAsker::PasswordAsker(QObject *parent) :QObject(parent) { d = new Private(this); } PasswordAsker::~PasswordAsker() { delete d; } void PasswordAsker::ask(Event::PasswordStyle pstyle, const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr) { Event e; e.setPasswordKeyStore(pstyle, keyStoreInfo, keyStoreEntry, ptr); d->ask(e); } void PasswordAsker::ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr) { Event e; e.setPasswordData(pstyle, fileName, ptr); d->ask(e); } void PasswordAsker::cancel() { d->cancel(); } void PasswordAsker::waitForResponse() { d->waitForResponse(); } bool PasswordAsker::accepted() const { return d->accepted; } SecureArray PasswordAsker::password() const { return d->password; } //---------------------------------------------------------------------------- // TokenAsker //---------------------------------------------------------------------------- class TokenAsker::Private : public AskerPrivate { public: Private(TokenAsker *_q) : AskerPrivate(_q) { } virtual void emitResponseReady() { emit tokenAsker->responseReady(); } }; TokenAsker::TokenAsker(QObject *parent) :QObject(parent) { d = new Private(this); } TokenAsker::~TokenAsker() { delete d; } void TokenAsker::ask(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr) { Event e; e.setToken(keyStoreInfo, keyStoreEntry, ptr); d->ask(e); } void TokenAsker::cancel() { d->cancel(); } void TokenAsker::waitForResponse() { d->waitForResponse(); } bool TokenAsker::accepted() const { return d->accepted; } } #include "qca_core.moc" psi-0.14/third-party/qca/qca/src/qca_textfilter.cpp0000644000175000017500000002265211305557613020440 0ustar janjan/* * Copyright (C) 2003-2005 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_textfilter.h" namespace QCA { //---------------------------------------------------------------------------- // TextFilter //---------------------------------------------------------------------------- TextFilter::TextFilter(Direction dir) { setup(dir); } void TextFilter::setup(Direction dir) { _dir = dir; } Direction TextFilter::direction() const { return _dir; } MemoryRegion TextFilter::encode(const MemoryRegion &a) { setup(Encode); return process(a); } MemoryRegion TextFilter::decode(const MemoryRegion &a) { setup(Decode); return process(a); } QString TextFilter::arrayToString(const MemoryRegion &a) { return QString::fromLatin1(encode(a).toByteArray()); } MemoryRegion TextFilter::stringToArray(const QString &s) { if(s.isEmpty()) return MemoryRegion(); return decode(s.toLatin1()); } QString TextFilter::encodeString(const QString &s) { return arrayToString(s.toUtf8()); } QString TextFilter::decodeString(const QString &s) { return QString::fromUtf8(stringToArray(s).toByteArray()); } //---------------------------------------------------------------------------- // Hex //---------------------------------------------------------------------------- static int enhex(uchar c) { if(c < 10) return c + '0'; else if(c < 16) return c - 10 + 'a'; else return -1; } static int dehex(char c) { if(c >= 'a' && c <= 'f') return c - 'a' + 10; else if(c >= 'A' && c <= 'F') return c - 'A' + 10; else if(c >= '0' && c <= '9') return c - '0'; else return -1; } Hex::Hex(Direction dir) :TextFilter(dir) { clear(); } void Hex::clear() { partial = false; _ok = true; } MemoryRegion Hex::update(const MemoryRegion &m) { QByteArray a = m.toByteArray(); if(_dir == Encode) { QByteArray out(a.size() * 2, 0); int at = 0; int c; for(int n = 0; n < (int)a.size(); ++n) { uchar lo = (uchar)a[n] & 0x0f; uchar hi = (uchar)a[n] >> 4; c = enhex(hi); if(c == -1) { _ok = false; break; } out[at++] = (char)c; c = enhex(lo); if(c == -1) { _ok = false; break; } out[at++] = (char)c; } if(!_ok) return MemoryRegion(); return out; } else { uchar lo = 0; uchar hi = 0; bool flag = false; if(partial) { hi = val; flag = true; } QByteArray out(a.size() / 2, 0); int at = 0; int c; for(int n = 0; n < (int)a.size(); ++n) { c = dehex((char)a[n]); if(c == -1) { _ok = false; break; } if(flag) { lo = (uchar)c; uchar full = ((hi & 0x0f) << 4) + (lo & 0x0f); out[at++] = full; flag = false; } else { hi = (uchar)c; flag = true; } } if(!_ok) return MemoryRegion(); if(flag) { val = hi; partial = true; } return out; } } MemoryRegion Hex::final() { if(partial) _ok = false; return MemoryRegion(); } bool Hex::ok() const { return _ok; } //---------------------------------------------------------------------------- // Base64 //---------------------------------------------------------------------------- Base64::Base64(Direction dir) :TextFilter(dir) { _lb_enabled = false; _lb_column = 76; } void Base64::clear() { partial.resize(0); _ok = true; col = 0; } bool Base64::lineBreaksEnabled() const { return _lb_enabled; } int Base64::lineBreaksColumn() const { return _lb_column; } void Base64::setLineBreaksEnabled(bool b) { _lb_enabled = b; } void Base64::setLineBreaksColumn(int column) { if(column > 0) _lb_column = column; else _lb_column = 76; } static QByteArray b64encode(const QByteArray &s) { int i; int len = s.size(); static char tbl[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" "ghijklmn" "opqrstuv" "wxyz0123" "456789+/" "="; int a, b, c; QByteArray p((len + 2) / 3 * 4, 0); int at = 0; for(i = 0; i < len; i += 3) { a = ((unsigned char)s[i] & 3) << 4; if(i + 1 < len) { a += (unsigned char)s[i + 1] >> 4; b = ((unsigned char)s[i + 1] & 0xf) << 2; if(i + 2 < len) { b += (unsigned char)s[i + 2] >> 6; c = (unsigned char)s[i + 2] & 0x3f; } else c = 64; } else b = c = 64; p[at++] = tbl[(unsigned char)s[i] >> 2]; p[at++] = tbl[a]; p[at++] = tbl[b]; p[at++] = tbl[c]; } return p; } static QByteArray b64decode(const QByteArray &s, bool *ok) { // -1 specifies invalid // 64 specifies eof // everything else specifies data static char tbl[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; // return value QByteArray p; *ok = true; // this should be a multiple of 4 int len = s.size(); if(len % 4) { *ok = false; return p; } p.resize(len / 4 * 3); int i; int at = 0; int a, b, c, d; c = d = 0; for(i = 0; i < len; i += 4) { a = tbl[(int)s[i]]; b = tbl[(int)s[i + 1]]; c = tbl[(int)s[i + 2]]; d = tbl[(int)s[i + 3]]; if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { p.resize(0); *ok = false; return p; } p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); } if(c & 64) p.resize(at - 2); else if(d & 64) p.resize(at - 1); return p; } static int findLF(const QByteArray &in, int offset) { for(int n = offset; n < in.size(); ++n) { if(in[n] == '\n') return n; } return -1; } static QByteArray insert_linebreaks(const QByteArray &s, int *col, int lfAt) { QByteArray out = s; int needed = (out.size() + *col) / lfAt; // how many newlines needed? if(needed > 0) { int firstlen = lfAt - *col; // length of first chunk int at = firstlen + (lfAt * (needed - 1)); // position of last newline int lastlen = out.size() - at; // length of last chunk //printf("size=%d,needed=%d,firstlen=%d,at=%d,lastlen=%d\n", out.size(), needed, firstlen, at, lastlen); // make room out.resize(out.size() + needed); // move backwards for(int n = 0; n < needed; ++n) { char *p = out.data() + at; int len; if(n == 0) len = lastlen; else len = lfAt; memmove(p + needed - n, p, len); p[needed - n - 1] = '\n'; at -= lfAt; } *col = lastlen; } else *col += out.size(); return out; } static QByteArray remove_linebreaks(const QByteArray &s) { QByteArray out = s; int removed = 0; int at = findLF(out, 0); while(at != -1) { int next = findLF(out, at + 1); int len; if(next != -1) len = next - at; else len = out.size() - at; if(len > 1) { char *p = out.data() + at; memmove(p - removed, p + 1, len - 1); } ++removed; at = next; } out.resize(out.size() - removed); return out; } static void appendArray(QByteArray *a, const QByteArray &b) { a->append(b); } MemoryRegion Base64::update(const MemoryRegion &m) { QByteArray in; if(_dir == Decode && _lb_enabled) in = remove_linebreaks(m.toByteArray()); else in = m.toByteArray(); if(in.isEmpty()) return MemoryRegion(); int chunk; if(_dir == Encode) chunk = 3; else chunk = 4; int size = partial.size() + in.size(); if(size < chunk) { appendArray(&partial, in); return MemoryRegion(); } int eat = size % chunk; // s = partial + a - eat QByteArray s(partial.size() + in.size() - eat, 0); memcpy(s.data(), partial.data(), partial.size()); memcpy(s.data() + partial.size(), in.data(), in.size() - eat); partial.resize(eat); memcpy(partial.data(), in.data() + in.size() - eat, eat); if(_dir == Encode) { if(_lb_enabled) return insert_linebreaks(b64encode(s), &col, _lb_column); else return b64encode(s); } else { bool ok; QByteArray out = b64decode(s, &ok); if(!ok) _ok = false; return out; } } MemoryRegion Base64::final() { if(_dir == Encode) { if(_lb_enabled) return insert_linebreaks(b64encode(partial), &col, _lb_column); else return b64encode(partial); } else { bool ok; QByteArray out = b64decode(partial, &ok); if(!ok) _ok = false; return out; } } bool Base64::ok() const { return _ok; } } psi-0.14/third-party/qca/qca/src/qca_safeobj.h0000644000175000017500000000553111305557613017321 0ustar janjan/* * qca_safeobj.h - Qt Cryptographic Architecture * Copyright (C) 2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef QCA_SAFEOBJ_H #define QCA_SAFEOBJ_H // NOTE: this API is private to QCA #include #include namespace QCA { // This function performs the following steps: // obj->disconnect(owner); // to prevent future signals to owner // obj->setParent(0); // to prevent delete if parent is deleted // obj->deleteLater(); // now we can forget about the object void releaseAndDeleteLater(QObject *owner, QObject *obj); class SafeTimer : public QObject { Q_OBJECT public: SafeTimer(QObject *parent = 0) : QObject(parent) { t = new QTimer(this); connect(t, SIGNAL(timeout()), SIGNAL(timeout())); } ~SafeTimer() { releaseAndDeleteLater(this, t); } int interval() const { return t->interval(); } bool isActive() const { return t->isActive(); } bool isSingleShot() const { return t->isSingleShot(); } void setInterval(int msec) { t->setInterval(msec); } void setSingleShot(bool singleShot) { t->setSingleShot(singleShot); } int timerId() const { return t->timerId(); } public slots: void start(int msec) { t->start(msec); } void start() { t->start(); } void stop() { t->stop(); } signals: void timeout(); private: QTimer *t; }; class SafeSocketNotifier : public QObject { Q_OBJECT public: SafeSocketNotifier(int socket, QSocketNotifier::Type type, QObject *parent = 0) : QObject(parent) { sn = new QSocketNotifier(socket, type, this); connect(sn, SIGNAL(activated(int)), SIGNAL(activated(int))); } ~SafeSocketNotifier() { sn->setEnabled(false); releaseAndDeleteLater(this, sn); } bool isEnabled() const { return sn->isEnabled(); } int socket() const { return sn->socket(); } QSocketNotifier::Type type() const { return sn->type(); } public slots: void setEnabled(bool enable) { sn->setEnabled(enable); } signals: void activated(int socket); private: QSocketNotifier *sn; }; } #endif psi-0.14/third-party/qca/qca/src/qca_safeobj.cpp0000644000175000017500000000202111305557613017643 0ustar janjan/* * qca_safeobj.cpp - Qt Cryptographic Architecture * Copyright (C) 2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_safeobj.h" namespace QCA { void releaseAndDeleteLater(QObject *owner, QObject *obj) { obj->disconnect(owner); obj->setParent(0); obj->deleteLater(); } } psi-0.14/third-party/qca/qca/src/qca_securelayer.cpp0000644000175000017500000011447111305557613020572 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_securelayer.h" #include "qcaprovider.h" #include "qca_safeobj.h" #include namespace QCA { Provider::Context *getContext(const QString &type, const QString &provider); enum ResetMode { ResetSession = 0, ResetSessionAndData = 1, ResetAll = 2 }; //---------------------------------------------------------------------------- // LayerTracker //---------------------------------------------------------------------------- class LayerTracker { private: struct Item { int plain; qint64 encoded; }; int p; QList list; public: LayerTracker() { p = 0; } void reset() { p = 0; list.clear(); } void addPlain(int plain) { p += plain; } void specifyEncoded(int encoded, int plain) { // can't specify more bytes than we have if(plain > p) plain = p; p -= plain; Item i; i.plain = plain; i.encoded = encoded; list += i; } int finished(qint64 encoded) { int plain = 0; for(QList::Iterator it = list.begin(); it != list.end();) { Item &i = *it; // not enough? if(encoded < i.encoded) { i.encoded -= encoded; break; } encoded -= i.encoded; plain += i.plain; it = list.erase(it); } return plain; } }; //---------------------------------------------------------------------------- // SecureLayer //---------------------------------------------------------------------------- SecureLayer::SecureLayer(QObject *parent) :QObject(parent) { } bool SecureLayer::isClosable() const { return false; } void SecureLayer::close() { } QByteArray SecureLayer::readUnprocessed() { return QByteArray(); } //---------------------------------------------------------------------------- // TLSSession //---------------------------------------------------------------------------- TLSSession::TLSSession() { } TLSSession::TLSSession(const TLSSession &from) :Algorithm(from) { } TLSSession::~TLSSession() { } TLSSession & TLSSession::operator=(const TLSSession &from) { Algorithm::operator=(from); return *this; } bool TLSSession::isNull() const { return (!context() ? true : false); } //---------------------------------------------------------------------------- // TLS //---------------------------------------------------------------------------- class TLS::Private : public QObject { Q_OBJECT public: enum { OpStart, OpUpdate }; enum State { Inactive, Initializing, Handshaking, Connected, Closing }; class Action { public: enum Type { ReadyRead, ReadyReadOutgoing, Handshaken, Close, CheckPeerCertificate, CertificateRequested, HostNameReceived }; int type; Action(int _type) : type(_type) { } }; TLS *q; TLSContext *c; TLS::Mode mode; // signal connected flags bool connect_hostNameReceived; bool connect_certificateRequested; bool connect_peerCertificateAvailable; bool connect_handshaken; // persistent settings (survives ResetSessionAndData) CertificateChain localCert; PrivateKey localKey; CertificateCollection trusted; bool con_ssfMode; int con_minSSF, con_maxSSF; QStringList con_cipherSuites; bool tryCompress; int packet_mtu; QList issuerList; TLSSession session; // session State state; bool blocked; bool server; QString host; TLSContext::SessionInfo sessionInfo; SafeTimer actionTrigger; int op; QList actionQueue; bool need_update; bool maybe_input; bool emitted_hostNameReceived; bool emitted_certificateRequested; bool emitted_peerCertificateAvailable; // data (survives ResetSession) CertificateChain peerCert; Validity peerValidity; bool hostMismatch; Error errorCode; // stream i/o QByteArray in, out; QByteArray to_net, from_net; QByteArray unprocessed; int out_pending; int to_net_encoded; LayerTracker layer; // datagram i/o QList packet_in, packet_out; QList packet_to_net, packet_from_net; int packet_out_pending; // packet count QList packet_to_net_encoded; Private(TLS *_q, TLS::Mode _mode) : QObject(_q), q(_q), mode(_mode), actionTrigger(this) { // c is 0 during initial reset, so we don't redundantly reset it c = 0; connect_hostNameReceived = false; connect_certificateRequested = false; connect_peerCertificateAvailable = false; connect_handshaken = false; server = false; connect(&actionTrigger, SIGNAL(timeout()), SLOT(doNextAction())); actionTrigger.setSingleShot(true); reset(ResetAll); c = static_cast(q->context()); // parent the context to us, so that moveToThread works c->setParent(this); connect(c, SIGNAL(resultsReady()), SLOT(tls_resultsReady())); connect(c, SIGNAL(dtlsTimeout()), SLOT(tls_dtlsTimeout())); } ~Private() { // context is owned by Algorithm, unparent so we don't double-delete c->setParent(0); } void reset(ResetMode mode) { if(c) c->reset(); // if we reset while in client mode, then clear this list // (it should only persist when used for server mode) if(!server) issuerList.clear(); state = Inactive; blocked = false; server = false; host = QString(); sessionInfo = TLSContext::SessionInfo(); actionTrigger.stop(); op = -1; actionQueue.clear(); need_update = false; maybe_input = false; emitted_hostNameReceived = false; emitted_certificateRequested = false; emitted_peerCertificateAvailable = false; out.clear(); out_pending = 0; packet_out.clear(); packet_out_pending = 0; if(mode >= ResetSessionAndData) { peerCert = CertificateChain(); peerValidity = ErrorValidityUnknown; hostMismatch = false; errorCode = (TLS::Error)-1; in.clear(); to_net.clear(); from_net.clear(); unprocessed.clear(); to_net_encoded = 0; layer.reset(); packet_in.clear(); packet_to_net.clear(); packet_from_net.clear(); packet_to_net_encoded.clear(); } if(mode >= ResetAll) { localCert = CertificateChain(); localKey = PrivateKey(); trusted = CertificateCollection(); con_ssfMode = true; con_minSSF = 128; con_maxSSF = -1; con_cipherSuites = QStringList(); tryCompress = false; packet_mtu = -1; issuerList.clear(); session = TLSSession(); } } void start(bool serverMode) { state = Initializing; server = serverMode; c->setup(serverMode, host, tryCompress); if(con_ssfMode) c->setConstraints(con_minSSF, con_maxSSF); else c->setConstraints(con_cipherSuites); c->setCertificate(localCert, localKey); c->setTrustedCertificates(trusted); if(serverMode) c->setIssuerList(issuerList); if(!session.isNull()) { TLSSessionContext *sc = static_cast(session.context()); c->setSessionId(*sc); } c->setMTU(packet_mtu); QCA_logTextMessage(QString("tls[%1]: c->start()").arg(q->objectName()), Logger::Information); op = OpStart; c->start(); } void close() { QCA_logTextMessage(QString("tls[%1]: close").arg(q->objectName()), Logger::Information); if(state != Connected) return; state = Closing; c->shutdown(); } void continueAfterStep() { QCA_logTextMessage(QString("tls[%1]: continueAfterStep").arg(q->objectName()), Logger::Information); if(!blocked) return; blocked = false; update(); } void processNextAction() { if(actionQueue.isEmpty()) { if(need_update) { QCA_logTextMessage(QString("tls[%1]: need_update").arg(q->objectName()), Logger::Information); update(); } return; } Action a = actionQueue.takeFirst(); // set up for the next one, if necessary if(!actionQueue.isEmpty() || need_update) { if(!actionTrigger.isActive()) actionTrigger.start(); } if(a.type == Action::ReadyRead) { emit q->readyRead(); } else if(a.type == Action::ReadyReadOutgoing) { emit q->readyReadOutgoing(); } else if(a.type == Action::Handshaken) { state = Connected; // write any app data waiting during handshake if(!out.isEmpty()) { need_update = true; if(!actionTrigger.isActive()) actionTrigger.start(); } QCA_logTextMessage(QString("tls[%1]: handshaken").arg(q->objectName()), Logger::Information); if(connect_handshaken) { blocked = true; emit q->handshaken(); } } else if(a.type == Action::Close) { unprocessed = c->unprocessed(); reset(ResetSession); emit q->closed(); } else if(a.type == Action::CheckPeerCertificate) { peerCert = c->peerCertificateChain(); if(!peerCert.isEmpty()) { peerValidity = c->peerCertificateValidity(); if(peerValidity == ValidityGood && !host.isEmpty() && !peerCert.primary().matchesHostName(host)) hostMismatch = true; } if(connect_peerCertificateAvailable) { blocked = true; emitted_peerCertificateAvailable = true; emit q->peerCertificateAvailable(); } } else if(a.type == Action::CertificateRequested) { issuerList = c->issuerList(); if(connect_certificateRequested) { blocked = true; emitted_certificateRequested = true; emit q->certificateRequested(); } } else if(a.type == Action::HostNameReceived) { if(connect_hostNameReceived) { blocked = true; emitted_hostNameReceived = true; emit q->hostNameReceived(); } } } void update() { QCA_logTextMessage(QString("tls[%1]: update").arg(q->objectName()), Logger::Information); if(blocked) { QCA_logTextMessage(QString("tls[%1]: ignoring update while blocked").arg(q->objectName()), Logger::Information); return; } if(!actionQueue.isEmpty()) { QCA_logTextMessage(QString("tls[%1]: ignoring update while processing actions").arg(q->objectName()), Logger::Information); need_update = true; return; } // only allow one operation at a time if(op != -1) { QCA_logTextMessage(QString("tls[%1]: ignoring update while operation active").arg(q->objectName()), Logger::Information); need_update = true; return; } need_update = false; QByteArray arg_from_net, arg_from_app; if(state == Handshaking) { // during handshake, only send from_net (no app data) if(mode == TLS::Stream) { arg_from_net = from_net; from_net.clear(); } else { // note: there may not be a packet if(!packet_from_net.isEmpty()) arg_from_net = packet_from_net.takeFirst(); } } else { if(mode == TLS::Stream) { if(!from_net.isEmpty()) { arg_from_net = from_net; from_net.clear(); } if(!out.isEmpty()) { out_pending += out.size(); arg_from_app = out; out.clear(); } } else { if(!packet_from_net.isEmpty()) arg_from_net = packet_from_net.takeFirst(); if(!packet_out.isEmpty()) { arg_from_app = packet_out.takeFirst(); ++packet_out_pending; } } } if(arg_from_net.isEmpty() && arg_from_app.isEmpty() && !maybe_input) { QCA_logTextMessage(QString("tls[%1]: ignoring update: no output and no expected input").arg(q->objectName()), Logger::Information); return; } // clear this flag maybe_input = false; QCA_logTextMessage(QString("tls[%1]: c->update").arg(q->objectName()), Logger::Information); op = OpUpdate; c->update(arg_from_net, arg_from_app); } void start_finished() { bool ok = c->result() == TLSContext::Success; if(!ok) { reset(ResetSession); errorCode = TLS::ErrorInit; emit q->error(); return; } state = Handshaking; // immediately update so we can get the first packet to send maybe_input = true; update(); } void update_finished() { TLSContext::Result r = c->result(); if(r == TLSContext::Error) { if(state == Handshaking || state == Closing) { reset(ResetSession); errorCode = ErrorHandshake; } else { reset(ResetSession); errorCode = ErrorCrypt; } emit q->error(); return; } QByteArray c_to_net = c->to_net(); if(!c_to_net.isEmpty()) { QCA_logTextMessage(QString("tls[%1]: to_net %2").arg(q->objectName(), QString::number(c_to_net.size())), Logger::Information); } if(state == Closing) { if(mode == TLS::Stream) to_net += c_to_net; else packet_to_net += c_to_net; if(!c_to_net.isEmpty()) actionQueue += Action(Action::ReadyReadOutgoing); if(r == TLSContext::Success) actionQueue += Action(Action::Close); processNextAction(); return; } else if(state == Handshaking) { if(mode == TLS::Stream) to_net += c_to_net; else packet_to_net += c_to_net; if(!c_to_net.isEmpty()) actionQueue += Action(Action::ReadyReadOutgoing); bool clientHello = false; bool serverHello = false; if(server) clientHello = c->clientHelloReceived(); else serverHello = c->serverHelloReceived(); // client specifies a host? if(!emitted_hostNameReceived && clientHello) { host = c->hostName(); if(!host.isEmpty()) actionQueue += Action(Action::HostNameReceived); } // successful handshake or server hello means there might be a peer cert if(!emitted_peerCertificateAvailable && (r == TLSContext::Success || (!server && serverHello))) actionQueue += Action(Action::CheckPeerCertificate); // server requests a cert from us? if(!emitted_certificateRequested && (serverHello && c->certificateRequested())) actionQueue += Action(Action::CertificateRequested); if(r == TLSContext::Success) { sessionInfo = c->sessionInfo(); if(sessionInfo.id) { TLSSessionContext *sc = static_cast(sessionInfo.id->clone()); session.change(sc); } actionQueue += Action(Action::Handshaken); } processNextAction(); return; } else // Connected { QByteArray c_to_app = c->to_app(); if(!c_to_app.isEmpty()) { QCA_logTextMessage(QString("tls[%1]: to_app %2").arg(q->objectName(), QString::number(c_to_app.size())), Logger::Information); } bool eof = c->eof(); int enc = -1; if(!c_to_net.isEmpty()) enc = c->encoded(); bool io_pending = false; if(mode == TLS::Stream) { if(!c_to_net.isEmpty()) out_pending -= enc; if(out_pending > 0) { maybe_input = true; io_pending = true; } if(!out.isEmpty()) io_pending = true; } else { if(!c_to_net.isEmpty()) --packet_out_pending; if(packet_out_pending > 0) { maybe_input = true; io_pending = true; } if(!packet_out.isEmpty()) io_pending = true; } if(mode == TLS::Stream) { to_net += c_to_net; in += c_to_app; to_net_encoded += enc; } else { packet_to_net += c_to_net; packet_in += c_to_app; } if(!c_to_net.isEmpty()) actionQueue += Action(Action::ReadyReadOutgoing); if(!c_to_app.isEmpty()) actionQueue += Action(Action::ReadyRead); if(eof) { close(); maybe_input = true; } if(eof || io_pending) { QCA_logTextMessage(QString("tls[%1]: eof || io_pending").arg(q->objectName()), Logger::Information); update(); } processNextAction(); return; } } private slots: void tls_resultsReady() { QCA_logTextMessage(QString("tls[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information); Q_ASSERT(op != -1); int last_op = op; op = -1; if(last_op == OpStart) start_finished(); else // OpUpdate update_finished(); } void tls_dtlsTimeout() { QCA_logTextMessage(QString("tls[%1]: c->dtlsTimeout()").arg(q->objectName()), Logger::Information); maybe_input = true; update(); } void doNextAction() { processNextAction(); } }; TLS::TLS(QObject *parent, const QString &provider) :SecureLayer(parent), Algorithm("tls", provider) { d = new Private(this, TLS::Stream); } TLS::TLS(Mode mode, QObject *parent, const QString &provider) :SecureLayer(parent), Algorithm(mode == Stream ? "tls" : "dtls", provider) { d = new Private(this, mode); } TLS::~TLS() { delete d; } void TLS::reset() { d->reset(ResetAll); } QStringList TLS::supportedCipherSuites(const Version &version) const { return d->c->supportedCipherSuites(version); } void TLS::setCertificate(const CertificateChain &cert, const PrivateKey &key) { d->localCert = cert; d->localKey = key; if(d->state != TLS::Private::Inactive) d->c->setCertificate(cert, key); } void TLS::setCertificate(const KeyBundle &kb) { setCertificate(kb.certificateChain(), kb.privateKey()); } CertificateCollection TLS::trustedCertificates() const { return d->trusted; } void TLS::setTrustedCertificates(const CertificateCollection &trusted) { d->trusted = trusted; if(d->state != TLS::Private::Inactive) d->c->setTrustedCertificates(trusted); } void TLS::setConstraints(SecurityLevel s) { int min = 128; switch(s) { case SL_None: min = 0; break; case SL_Integrity: min = 1; break; case SL_Export: min = 40; break; case SL_Baseline: min = 128; break; case SL_High: min = 129; break; case SL_Highest: min = qMax(129, d->c->maxSSF()); break; } d->con_ssfMode = true; d->con_minSSF = min; d->con_maxSSF = -1; if(d->state != TLS::Private::Inactive) d->c->setConstraints(d->con_minSSF, d->con_maxSSF); } void TLS::setConstraints(int minSSF, int maxSSF) { d->con_ssfMode = true; d->con_minSSF = minSSF; d->con_maxSSF = maxSSF; if(d->state != TLS::Private::Inactive) d->c->setConstraints(d->con_minSSF, d->con_maxSSF); } void TLS::setConstraints(const QStringList &cipherSuiteList) { d->con_ssfMode = false; d->con_cipherSuites = cipherSuiteList; if(d->state != TLS::Private::Inactive) d->c->setConstraints(d->con_cipherSuites); } QList TLS::issuerList() const { return d->issuerList; } void TLS::setIssuerList(const QList &issuers) { d->issuerList = issuers; if(d->state != TLS::Private::Inactive) d->c->setIssuerList(issuers); } void TLS::setSession(const TLSSession &session) { d->session = session; } bool TLS::canCompress() const { return d->c->canCompress(); } bool TLS::canSetHostName() const { return d->c->canSetHostName(); } bool TLS::compressionEnabled() const { return d->tryCompress; } void TLS::setCompressionEnabled(bool b) { d->tryCompress = b; } void TLS::startClient(const QString &host) { d->reset(ResetSessionAndData); d->host = host; d->issuerList.clear(); // client mode d->start(false); } void TLS::startServer() { d->reset(ResetSessionAndData); // server mode d->start(true); } void TLS::continueAfterStep() { d->continueAfterStep(); } bool TLS::isHandshaken() const { if(d->state == TLS::Private::Connected || d->state == TLS::Private::Closing) return true; else return false; } bool TLS::isCompressed() const { return d->sessionInfo.isCompressed; } TLS::Version TLS::version() const { return d->sessionInfo.version; } QString TLS::cipherSuite() const { return d->sessionInfo.cipherSuite; } int TLS::cipherBits() const { return d->sessionInfo.cipherBits; } int TLS::cipherMaxBits() const { return d->sessionInfo.cipherMaxBits; } TLSSession TLS::session() const { return d->session; } TLS::Error TLS::errorCode() const { return d->errorCode; } TLS::IdentityResult TLS::peerIdentityResult() const { if(d->peerCert.isEmpty()) return NoCertificate; if(d->peerValidity != ValidityGood) return InvalidCertificate; if(d->hostMismatch) return HostMismatch; return Valid; } Validity TLS::peerCertificateValidity() const { return d->peerValidity; } CertificateChain TLS::localCertificateChain() const { return d->localCert; } PrivateKey TLS::localPrivateKey() const { return d->localKey; } CertificateChain TLS::peerCertificateChain() const { return d->peerCert; } bool TLS::isClosable() const { return true; } int TLS::bytesAvailable() const { if(d->mode == Stream) return d->in.size(); else return 0; } int TLS::bytesOutgoingAvailable() const { if(d->mode == Stream) return d->to_net.size(); else return 0; } void TLS::close() { d->close(); d->update(); } void TLS::write(const QByteArray &a) { if(d->mode == Stream) { d->out.append(a); d->layer.addPlain(a.size()); } else d->packet_out.append(a); QCA_logTextMessage(QString("tls[%1]: write").arg(objectName()), Logger::Information); d->update(); } QByteArray TLS::read() { if(d->mode == Stream) { QByteArray a = d->in; d->in.clear(); return a; } else { if(!d->packet_in.isEmpty()) return d->packet_in.takeFirst(); else return QByteArray(); } } void TLS::writeIncoming(const QByteArray &a) { if(d->mode == Stream) d->from_net.append(a); else d->packet_from_net.append(a); QCA_logTextMessage(QString("tls[%1]: writeIncoming %2").arg(objectName(), QString::number(a.size())), Logger::Information); d->update(); } QByteArray TLS::readOutgoing(int *plainBytes) { if(d->mode == Stream) { QByteArray a = d->to_net; d->to_net.clear(); if(plainBytes) *plainBytes = d->to_net_encoded; d->layer.specifyEncoded(a.size(), d->to_net_encoded); d->to_net_encoded = 0; return a; } else { if(!d->packet_to_net.isEmpty()) { QByteArray a = d->packet_to_net.takeFirst(); int x = d->packet_to_net_encoded.takeFirst(); if(plainBytes) *plainBytes = x; return a; } else { if(plainBytes) *plainBytes = 0; return QByteArray(); } } } QByteArray TLS::readUnprocessed() { if(d->mode == Stream) { QByteArray a = d->unprocessed; d->unprocessed.clear(); return a; } else return QByteArray(); } int TLS::convertBytesWritten(qint64 bytes) { return d->layer.finished(bytes); } int TLS::packetsAvailable() const { return d->packet_in.count(); } int TLS::packetsOutgoingAvailable() const { return d->packet_to_net.count(); } int TLS::packetMTU() const { return d->packet_mtu; } void TLS::setPacketMTU(int size) const { d->packet_mtu = size; if(d->state != TLS::Private::Inactive) d->c->setMTU(size); } void TLS::connectNotify(const char *signal) { if(signal == QMetaObject::normalizedSignature(SIGNAL(hostNameReceived()))) d->connect_hostNameReceived = true; else if(signal == QMetaObject::normalizedSignature(SIGNAL(certificateRequested()))) d->connect_certificateRequested = true; else if(signal == QMetaObject::normalizedSignature(SIGNAL(peerCertificateAvailable()))) d->connect_peerCertificateAvailable = true; else if(signal == QMetaObject::normalizedSignature(SIGNAL(handshaken()))) d->connect_handshaken = true; } void TLS::disconnectNotify(const char *signal) { if(signal == QMetaObject::normalizedSignature(SIGNAL(hostNameReceived()))) d->connect_hostNameReceived = false; else if(signal == QMetaObject::normalizedSignature(SIGNAL(certificateRequested()))) d->connect_certificateRequested = false; else if(signal == QMetaObject::normalizedSignature(SIGNAL(peerCertificateAvailable()))) d->connect_peerCertificateAvailable = false; else if(signal == QMetaObject::normalizedSignature(SIGNAL(handshaken()))) d->connect_handshaken = false; } //---------------------------------------------------------------------------- // SASL::Params //---------------------------------------------------------------------------- class SASL::Params::Private { public: bool needUsername, canSendAuthzid, needPassword, canSendRealm; }; SASL::Params::Params() :d(new Private) { } SASL::Params::Params(bool user, bool authzid, bool pass, bool realm) :d(new Private) { d->needUsername = user; d->canSendAuthzid = authzid; d->needPassword = pass; d->canSendRealm = realm; } SASL::Params::Params(const SASL::Params &from) :d(new Private(*from.d)) { } SASL::Params::~Params() { delete d; } SASL::Params & SASL::Params::operator=(const SASL::Params &from) { *d = *from.d; return *this; } bool SASL::Params::needUsername() const { return d->needUsername; } bool SASL::Params::canSendAuthzid() const { return d->canSendAuthzid; } bool SASL::Params::needPassword() const { return d->needPassword; } bool SASL::Params::canSendRealm() const { return d->canSendRealm; } //---------------------------------------------------------------------------- // SASL //---------------------------------------------------------------------------- /* These don't map, but I don't think it matters much.. SASL_TRYAGAIN (-8) transient failure (e.g., weak key) SASL_BADMAC (-9) integrity check failed -- client only codes -- SASL_WRONGMECH (-11) mechanism doesn't support requested feature SASL_NEWSECRET (-12) new secret needed -- server only codes -- SASL_TRANS (-17) One time use of a plaintext password will enable requested mechanism for user SASL_PWLOCK (-21) password locked SASL_NOCHANGE (-22) requested change was not needed */ class SASL::Private : public QObject { Q_OBJECT public: enum { OpStart, OpServerFirstStep, OpNextStep, OpTryAgain, OpUpdate }; class Action { public: enum Type { ClientStarted, NextStep, Authenticated, ReadyRead, ReadyReadOutgoing }; int type; QByteArray stepData; bool haveInit; Action(int _type) : type(_type) { } Action(int _type, const QByteArray &_stepData) : type(_type), stepData(_stepData) { } Action(int _type, bool _haveInit, const QByteArray &_stepData) : type(_type), stepData(_stepData), haveInit(_haveInit) { } }; SASL *q; SASLContext *c; // persistent settings (survives ResetSessionAndData) AuthFlags auth_flags; int ssfmin, ssfmax; QString ext_authid; int ext_ssf; bool localSet, remoteSet; SASLContext::HostPort local, remote; bool set_username, set_authzid, set_password, set_realm; QString username, authzid, realm; SecureArray password; // session bool server; QStringList mechlist; QString server_realm; bool allowClientSendFirst; bool disableServerSendLast; SafeTimer actionTrigger; int op; QList actionQueue; bool need_update; bool first; bool authed; // data (survives ResetSession) QString mech; // selected mech Error errorCode; // stream i/o QByteArray in, out; QByteArray to_net, from_net; int out_pending; int to_net_encoded; LayerTracker layer; Private(SASL *_q) : QObject(_q), q(_q), actionTrigger(this) { c = 0; set_username = false; set_authzid = false; set_password = false; set_realm = false; connect(&actionTrigger, SIGNAL(timeout()), SLOT(doNextAction())); actionTrigger.setSingleShot(true); reset(ResetAll); c = static_cast(q->context()); // parent the context to us, so that moveToThread works c->setParent(this); connect(c, SIGNAL(resultsReady()), SLOT(sasl_resultsReady())); } ~Private() { // context is owned by Algorithm, unparent so we don't double-delete c->setParent(0); } void reset(ResetMode mode) { if(c) c->reset(); server = false; mechlist.clear(); server_realm = QString(); allowClientSendFirst = false; disableServerSendLast = true; actionTrigger.stop(); op = -1; actionQueue.clear(); need_update = false; first = false; authed = false; out.clear(); out_pending = 0; if(mode >= ResetSessionAndData) { mech = QString(); errorCode = (SASL::Error)-1; in.clear(); to_net.clear(); from_net.clear(); to_net_encoded = 0; layer.reset(); } if(mode >= ResetAll) { auth_flags = SASL::AuthFlagsNone; ssfmin = 0; ssfmax = 0; ext_authid = QString(); ext_ssf = 0; localSet = false; remoteSet = false; local = SASLContext::HostPort(); remote = SASLContext::HostPort(); set_username = false; username = QString(); set_authzid = false; authzid = QString(); set_password = false; password = SecureArray(); set_realm = false; realm = QString(); } } void setup(const QString &service, const QString &host) { c->setup(service, host, localSet ? &local : 0, remoteSet ? &remote : 0, ext_authid, ext_ssf); c->setConstraints(auth_flags, ssfmin, ssfmax); QString *p_username = 0; QString *p_authzid = 0; SecureArray *p_password = 0; QString *p_realm = 0; if(set_username) p_username = &username; if(set_authzid) p_authzid = &authzid; if(set_password) p_password = &password; if(set_realm) p_realm = &realm; c->setClientParams(p_username, p_authzid, p_password, p_realm); } void start() { op = OpStart; first = true; if(server) { QCA_logTextMessage(QString("sasl[%1]: c->startServer()").arg(q->objectName()), Logger::Information); c->startServer(server_realm, disableServerSendLast); } else { QCA_logTextMessage(QString("sasl[%1]: c->startClient()").arg(q->objectName()), Logger::Information); c->startClient(mechlist, allowClientSendFirst); } } void putServerFirstStep(const QString &mech, const QByteArray *clientInit) { if(op != -1) return; QCA_logTextMessage(QString("sasl[%1]: c->serverFirstStep()").arg(q->objectName()), Logger::Information); op = OpServerFirstStep; c->serverFirstStep(mech, clientInit); } void putStep(const QByteArray &stepData) { if(op != -1) return; QCA_logTextMessage(QString("sasl[%1]: c->nextStep()").arg(q->objectName()), Logger::Information); op = OpNextStep; c->nextStep(stepData); } void tryAgain() { if(op != -1) return; QCA_logTextMessage(QString("sasl[%1]: c->tryAgain()").arg(q->objectName()), Logger::Information); op = OpTryAgain; c->tryAgain(); } void processNextAction() { if(actionQueue.isEmpty()) { if(need_update) update(); return; } Action a = actionQueue.takeFirst(); // set up for the next one, if necessary if(!actionQueue.isEmpty() || need_update) { if(!actionTrigger.isActive()) actionTrigger.start(); } if(a.type == Action::ClientStarted) { emit q->clientStarted(a.haveInit, a.stepData); } else if(a.type == Action::NextStep) { emit q->nextStep(a.stepData); } else if(a.type == Action::Authenticated) { authed = true; // write any app data waiting during authentication if(!out.isEmpty()) { need_update = true; if(!actionTrigger.isActive()) actionTrigger.start(); } QCA_logTextMessage(QString("sasl[%1]: authenticated").arg(q->objectName()), Logger::Information); emit q->authenticated(); } else if(a.type == Action::ReadyRead) { emit q->readyRead(); } else if(a.type == Action::ReadyReadOutgoing) { emit q->readyReadOutgoing(); } } void update() { // defer writes while authenticating if(!authed) { QCA_logTextMessage(QString("sasl[%1]: ignoring update while not yet authenticated").arg(q->objectName()), Logger::Information); return; } if(!actionQueue.isEmpty()) { QCA_logTextMessage(QString("sasl[%1]: ignoring update while processing actions").arg(q->objectName()), Logger::Information); need_update = true; return; } // only allow one operation at a time if(op != -1) { QCA_logTextMessage(QString("sasl[%1]: ignoring update while operation active").arg(q->objectName()), Logger::Information); need_update = true; return; } need_update = false; QCA_logTextMessage(QString("sasl[%1]: c->update()").arg(q->objectName()), Logger::Information); op = OpUpdate; out_pending += out.size(); c->update(from_net, out); from_net.clear(); out.clear(); } private slots: void sasl_resultsReady() { QCA_logTextMessage(QString("sasl[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information); int last_op = op; op = -1; SASLContext::Result r = c->result(); if(last_op == OpStart) { if(server) { if(r != SASLContext::Success) { errorCode = SASL::ErrorInit; emit q->error(); return; } emit q->serverStarted(); return; } else // client { mech = c->mech(); // fall into this logic last_op = OpTryAgain; } } else if(last_op == OpServerFirstStep) { // fall into this logic last_op = OpTryAgain; } else if(last_op == OpNextStep) { // fall into this logic last_op = OpTryAgain; } if(last_op == OpTryAgain) { if(server) { if(r == SASLContext::Continue) { emit q->nextStep(c->stepData()); return; } else if(r == SASLContext::AuthCheck) { emit q->authCheck(c->username(), c->authzid()); return; } else if(r == SASLContext::Success) { if(!disableServerSendLast) actionQueue += Action(Action::NextStep, c->stepData()); actionQueue += Action(Action::Authenticated); processNextAction(); return; } else // error { errorCode = SASL::ErrorHandshake; emit q->error(); return; } } else // client { if(first) { if(r == SASLContext::Error) { if(first) errorCode = SASL::ErrorInit; else errorCode = SASL::ErrorHandshake; emit q->error(); return; } else if(r == SASLContext::Params) { Params np = c->clientParams(); emit q->needParams(np); return; } first = false; actionQueue += Action(Action::ClientStarted, c->haveClientInit(), c->stepData()); if(r == SASLContext::Success) actionQueue += Action(Action::Authenticated); processNextAction(); return; } else { if(r == SASLContext::Error) { errorCode = ErrorHandshake; emit q->error(); return; } else if(r == SASLContext::Params) { Params np = c->clientParams(); emit q->needParams(np); return; } else if(r == SASLContext::Continue) { emit q->nextStep(c->stepData()); return; } else if(r == SASLContext::Success) { actionQueue += Action(Action::NextStep, c->stepData()); actionQueue += Action(Action::Authenticated); processNextAction(); return; } } } } else if(last_op == OpUpdate) { if(r != SASLContext::Success) { errorCode = ErrorCrypt; emit q->error(); return; } QByteArray c_to_net = c->to_net(); QByteArray c_to_app = c->to_app(); int enc = -1; if(!c_to_net.isEmpty()) enc = c->encoded(); bool io_pending = false; if(!c_to_net.isEmpty()) out_pending -= enc; if(out_pending > 0) io_pending = true; if(!out.isEmpty()) io_pending = true; to_net += c_to_net; in += c_to_app; to_net_encoded += enc; if(!c_to_net.isEmpty()) actionQueue += Action(Action::ReadyReadOutgoing); if(!c_to_app.isEmpty()) actionQueue += Action(Action::ReadyRead); if(io_pending) update(); processNextAction(); return; } } void doNextAction() { processNextAction(); } }; SASL::SASL(QObject *parent, const QString &provider) :SecureLayer(parent), Algorithm("sasl", provider) { d = new Private(this); } SASL::~SASL() { delete d; } void SASL::reset() { d->reset(ResetAll); } SASL::Error SASL::errorCode() const { return d->errorCode; } SASL::AuthCondition SASL::authCondition() const { return d->c->authCondition(); } void SASL::setConstraints(AuthFlags f, SecurityLevel s) { int min = 0; if(s == SL_Integrity) min = 1; else if(s == SL_Export) min = 56; else if(s == SL_Baseline) min = 128; else if(s == SL_High) min = 192; else if(s == SL_Highest) min = 256; setConstraints(f, min, 256); } void SASL::setConstraints(AuthFlags f, int minSSF, int maxSSF) { d->auth_flags = f; d->ssfmin = minSSF; d->ssfmax = maxSSF; } void SASL::setExternalAuthId(const QString &authid) { d->ext_authid = authid; } void SASL::setExternalSSF(int strength) { d->ext_ssf = strength; } void SASL::setLocalAddress(const QString &addr, quint16 port) { d->localSet = true; d->local.addr = addr; d->local.port = port; } void SASL::setRemoteAddress(const QString &addr, quint16 port) { d->remoteSet = true; d->remote.addr = addr; d->remote.port = port; } void SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, ClientSendMode mode) { d->reset(ResetSessionAndData); d->setup(service, host); d->server = false; d->mechlist = mechlist; d->allowClientSendFirst = (mode == AllowClientSendFirst); d->start(); } void SASL::startServer(const QString &service, const QString &host, const QString &realm, ServerSendMode mode) { d->reset(ResetSessionAndData); d->setup(service, host); d->server = true; d->server_realm = realm; d->disableServerSendLast = (mode == DisableServerSendLast); d->start(); } void SASL::putServerFirstStep(const QString &mech) { d->putServerFirstStep(mech, 0); } void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit) { d->putServerFirstStep(mech, &clientInit); } void SASL::putStep(const QByteArray &stepData) { d->putStep(stepData); } void SASL::setUsername(const QString &user) { d->set_username = true; d->username = user; d->c->setClientParams(&user, 0, 0, 0); } void SASL::setAuthzid(const QString &authzid) { d->set_authzid = true; d->authzid = authzid; d->c->setClientParams(0, &authzid, 0, 0); } void SASL::setPassword(const SecureArray &pass) { d->set_password = true; d->password = pass; d->c->setClientParams(0, 0, &pass, 0); } void SASL::setRealm(const QString &realm) { d->set_realm = true; d->realm = realm; d->c->setClientParams(0, 0, 0, &realm); } void SASL::continueAfterParams() { d->tryAgain(); } void SASL::continueAfterAuthCheck() { d->tryAgain(); } QString SASL::mechanism() const { return d->mech; } QStringList SASL::mechanismList() const { return d->c->mechlist(); } QStringList SASL::realmList() const { return d->c->realmlist(); } int SASL::ssf() const { return d->c->ssf(); } int SASL::bytesAvailable() const { return d->in.size(); } int SASL::bytesOutgoingAvailable() const { return d->to_net.size(); } void SASL::write(const QByteArray &a) { d->out.append(a); d->layer.addPlain(a.size()); d->update(); } QByteArray SASL::read() { QByteArray a = d->in; d->in.clear(); return a; } void SASL::writeIncoming(const QByteArray &a) { d->from_net.append(a); d->update(); } QByteArray SASL::readOutgoing(int *plainBytes) { QByteArray a = d->to_net; d->to_net.clear(); if(plainBytes) *plainBytes = d->to_net_encoded; d->layer.specifyEncoded(a.size(), d->to_net_encoded); d->to_net_encoded = 0; return a; } int SASL::convertBytesWritten(qint64 bytes) { return d->layer.finished(bytes); } } #include "qca_securelayer.moc" psi-0.14/third-party/qca/qca/src/qca_publickey.cpp0000644000175000017500000010025511305557613020231 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_publickey.h" #include "qcaprovider.h" #include #include namespace QCA { Provider::Context *getContext(const QString &type, const QString &provider); Provider::Context *getContext(const QString &type, Provider *p); bool stringToFile(const QString &fileName, const QString &content) { QFile f(fileName); if(!f.open(QFile::WriteOnly)) return false; QTextStream ts(&f); ts << content; return true; } bool stringFromFile(const QString &fileName, QString *s) { QFile f(fileName); if(!f.open(QFile::ReadOnly)) return false; QTextStream ts(&f); *s = ts.readAll(); return true; } bool arrayToFile(const QString &fileName, const QByteArray &content) { QFile f(fileName); if(!f.open(QFile::WriteOnly)) return false; f.write(content.data(), content.size()); return true; } bool arrayFromFile(const QString &fileName, QByteArray *a) { QFile f(fileName); if(!f.open(QFile::ReadOnly)) return false; *a = f.readAll(); return true; } bool ask_passphrase(const QString &fname, void *ptr, SecureArray *answer) { PasswordAsker asker; asker.ask(Event::StylePassphrase, fname, ptr); asker.waitForResponse(); if(!asker.accepted()) return false; *answer = asker.password(); return true; } ProviderList allProviders() { ProviderList pl = providers(); pl += defaultProvider(); return pl; } Provider *providerForName(const QString &name) { ProviderList pl = allProviders(); for(int n = 0; n < pl.count(); ++n) { if(pl[n]->name() == name) return pl[n]; } return 0; } bool use_asker_fallback(ConvertResult r) { // FIXME: we should only do this if we get ErrorPassphrase? //if(r == ErrorPassphrase) if(r != ConvertGood) return true; return false; } class Getter_GroupSet { public: static QList getList(Provider *p) { QList list; const DLGroupContext *c = static_cast(getContext("dlgroup", p)); if(!c) return list; list = c->supportedGroupSets(); delete c; return list; } }; class Getter_PBE { public: static QList getList(Provider *p) { QList list; const PKeyContext *c = static_cast(getContext("pkey", p)); if(!c) return list; list = c->supportedPBEAlgorithms(); delete c; return list; } }; class Getter_Type { public: static QList getList(Provider *p) { QList list; const PKeyContext *c = static_cast(getContext("pkey", p)); if(!c) return list; list = c->supportedTypes(); delete c; return list; } }; class Getter_IOType { public: static QList getList(Provider *p) { QList list; const PKeyContext *c = static_cast(getContext("pkey", p)); if(!c) return list; list = c->supportedIOTypes(); delete c; return list; } }; template class Getter_PublicKey { public: // DER static ConvertResult fromData(PKeyContext *c, const QByteArray &in) { return c->publicFromDER(in); } // PEM static ConvertResult fromData(PKeyContext *c, const QString &in) { return c->publicFromPEM(in); } static PublicKey getKey(Provider *p, const I &in, const SecureArray &, ConvertResult *result) { PublicKey k; PKeyContext *c = static_cast(getContext("pkey", p)); if(!c) { if(result) *result = ErrorDecode; return k; } ConvertResult r = fromData(c, in); if(result) *result = r; if(r == ConvertGood) k.change(c); else delete c; return k; } }; template class Getter_PrivateKey { public: // DER static ConvertResult fromData(PKeyContext *c, const SecureArray &in, const SecureArray &passphrase) { return c->privateFromDER(in, passphrase); } // PEM static ConvertResult fromData(PKeyContext *c, const QString &in, const SecureArray &passphrase) { return c->privateFromPEM(in, passphrase); } static PrivateKey getKey(Provider *p, const I &in, const SecureArray &passphrase, ConvertResult *result) { PrivateKey k; PKeyContext *c = static_cast(getContext("pkey", p)); if(!c) { if(result) *result = ErrorDecode; return k; } ConvertResult r = fromData(c, in, passphrase); if(result) *result = r; if(r == ConvertGood) k.change(c); else delete c; return k; } }; Provider *providerForGroupSet(DLGroupSet set) { ProviderList pl = allProviders(); for(int n = 0; n < pl.count(); ++n) { if(Getter_GroupSet::getList(pl[n]).contains(set)) return pl[n]; } return 0; } Provider *providerForPBE(PBEAlgorithm alg, PKey::Type ioType, const PKeyContext *prefer = 0) { Provider *preferProvider = 0; if(prefer) { preferProvider = prefer->provider(); if(prefer->supportedPBEAlgorithms().contains(alg) && prefer->supportedIOTypes().contains(ioType)) return preferProvider; } ProviderList pl = allProviders(); for(int n = 0; n < pl.count(); ++n) { if(preferProvider && pl[n] == preferProvider) continue; if(Getter_PBE::getList(pl[n]).contains(alg) && Getter_IOType::getList(pl[n]).contains(ioType)) return pl[n]; } return 0; } Provider *providerForIOType(PKey::Type type, const PKeyContext *prefer = 0) { Provider *preferProvider = 0; if(prefer) { preferProvider = prefer->provider(); if(prefer && prefer->supportedIOTypes().contains(type)) return preferProvider; } ProviderList pl = allProviders(); for(int n = 0; n < pl.count(); ++n) { if(preferProvider && pl[n] == preferProvider) continue; if(Getter_IOType::getList(pl[n]).contains(type)) return pl[n]; } return 0; } template QList getList(const QString &provider) { QList list; // single if(!provider.isEmpty()) { Provider *p = providerForName(provider); if(p) list = G::getList(p); } // all else { ProviderList pl = allProviders(); for(int n = 0; n < pl.count(); ++n) { QList other = G::getList(pl[n]); for(int k = 0; k < other.count(); ++k) { // only add what we don't have in the list if(!list.contains(other[k])) list += other[k]; } } } return list; } template T getKey(const QString &provider, const I &in, const SecureArray &passphrase, ConvertResult *result) { T k; // single if(!provider.isEmpty()) { Provider *p = providerForName(provider); if(!p) return k; k = G::getKey(p, in, passphrase, result); } // all else { ProviderList pl = allProviders(); for(int n = 0; n < pl.count(); ++n) { ConvertResult r; k = G::getKey(pl[n], in, passphrase, &r); if(result) *result = r; if(!k.isNull()) break; if(r == ErrorPassphrase) // don't loop if we get this break; } } return k; } PBEAlgorithm get_pbe_default() { return PBES2_TripleDES_SHA1; } static PrivateKey get_privatekey_der(const SecureArray &der, const QString &fileName, void *ptr, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { PrivateKey out; ConvertResult r; out = getKey, SecureArray>(provider, der, passphrase, &r); // error converting without passphrase? maybe a passphrase is needed if(use_asker_fallback(r) && passphrase.isEmpty()) { SecureArray pass; if(ask_passphrase(fileName, ptr, &pass)) out = getKey, SecureArray>(provider, der, pass, &r); } if(result) *result = r; return out; } static PrivateKey get_privatekey_pem(const QString &pem, const QString &fileName, void *ptr, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { PrivateKey out; ConvertResult r; out = getKey, QString>(provider, pem, passphrase, &r); // error converting without passphrase? maybe a passphrase is needed if(use_asker_fallback(r) && passphrase.isEmpty()) { SecureArray pass; if(ask_passphrase(fileName, ptr, &pass)) out = getKey, QString>(provider, pem, pass, &r); } if(result) *result = r; return out; } //---------------------------------------------------------------------------- // Global //---------------------------------------------------------------------------- // adapted from Botan static const unsigned char pkcs_sha1[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 }; static const unsigned char pkcs_md5[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; static const unsigned char pkcs_md2[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 }; static const unsigned char pkcs_ripemd160[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; QByteArray get_hash_id(const QString &name) { if(name == "sha1") return QByteArray::fromRawData((const char *)pkcs_sha1, sizeof(pkcs_sha1)); else if(name == "md5") return QByteArray::fromRawData((const char *)pkcs_md5, sizeof(pkcs_md5)); else if(name == "md2") return QByteArray::fromRawData((const char *)pkcs_md2, sizeof(pkcs_md2)); else if(name == "ripemd160") return QByteArray::fromRawData((const char *)pkcs_ripemd160, sizeof(pkcs_ripemd160)); else return QByteArray(); } QByteArray emsa3Encode(const QString &hashName, const QByteArray &digest, int size) { QByteArray hash_id = get_hash_id(hashName); if(hash_id.isEmpty()) return QByteArray(); // logic adapted from Botan int basesize = hash_id.size() + digest.size() + 2; if(size == -1) size = basesize + 1; // default to 1-byte pad int padlen = size - basesize; if(padlen < 1) return QByteArray(); QByteArray out(size, (char)0xff); // pad with 0xff out[0] = 0x01; out[padlen + 1] = 0x00; int at = padlen + 2; memcpy(out.data() + at, hash_id.data(), hash_id.size()); at += hash_id.size(); memcpy(out.data() + at, digest.data(), digest.size()); return out; } //---------------------------------------------------------------------------- // DLGroup //---------------------------------------------------------------------------- class DLGroup::Private { public: BigInteger p, q, g; Private(const BigInteger &p1, const BigInteger &q1, const BigInteger &g1) :p(p1), q(q1), g(g1) { } }; DLGroup::DLGroup() { d = 0; } DLGroup::DLGroup(const BigInteger &p, const BigInteger &q, const BigInteger &g) { d = new Private(p, q, g); } DLGroup::DLGroup(const BigInteger &p, const BigInteger &g) { d = new Private(p, 0, g); } DLGroup::DLGroup(const DLGroup &from) { d = 0; *this = from; } DLGroup::~DLGroup() { delete d; } DLGroup & DLGroup::operator=(const DLGroup &from) { delete d; d = 0; if(from.d) d = new Private(*from.d); return *this; } QList DLGroup::supportedGroupSets(const QString &provider) { return getList(provider); } bool DLGroup::isNull() const { return (d ? false: true); } BigInteger DLGroup::p() const { return d->p; } BigInteger DLGroup::q() const { return d->q; } BigInteger DLGroup::g() const { return d->g; } //---------------------------------------------------------------------------- // PKey //---------------------------------------------------------------------------- class PKey::Private { public: }; PKey::PKey() { d = new Private; } PKey::PKey(const QString &type, const QString &provider) :Algorithm(type, provider) { d = new Private; } PKey::PKey(const PKey &from) :Algorithm(from) { d = new Private; *this = from; } PKey::~PKey() { delete d; } PKey & PKey::operator=(const PKey &from) { Algorithm::operator=(from); *d = *from.d; return *this; } void PKey::set(const PKey &k) { *this = k; } void PKey::assignToPublic(PKey *dest) const { dest->set(*this); // converting private to public if(dest->isPrivate()) static_cast(dest->context())->key()->convertToPublic(); } void PKey::assignToPrivate(PKey *dest) const { dest->set(*this); } QList PKey::supportedTypes(const QString &provider) { return getList(provider); } QList PKey::supportedIOTypes(const QString &provider) { return getList(provider); } bool PKey::isNull() const { return (!context() ? true : false); } PKey::Type PKey::type() const { if(isNull()) return RSA; // some default so we don't explode return static_cast(context())->key()->type(); } int PKey::bitSize() const { return static_cast(context())->key()->bits(); } bool PKey::isRSA() const { return (type() == RSA); } bool PKey::isDSA() const { return (type() == DSA); } bool PKey::isDH() const { return (type() == DH); } bool PKey::isPublic() const { if(isNull()) return false; return !isPrivate(); } bool PKey::isPrivate() const { if(isNull()) return false; return static_cast(context())->key()->isPrivate(); } bool PKey::canExport() const { return static_cast(context())->key()->canExport(); } bool PKey::canKeyAgree() const { return isDH(); } PublicKey PKey::toPublicKey() const { PublicKey k; if(!isNull()) assignToPublic(&k); return k; } PrivateKey PKey::toPrivateKey() const { PrivateKey k; if(!isNull() && isPrivate()) assignToPrivate(&k); return k; } RSAPublicKey PKey::toRSAPublicKey() const { RSAPublicKey k; if(!isNull() && isRSA()) assignToPublic(&k); return k; } RSAPrivateKey PKey::toRSAPrivateKey() const { RSAPrivateKey k; if(!isNull() && isRSA() && isPrivate()) assignToPrivate(&k); return k; } DSAPublicKey PKey::toDSAPublicKey() const { DSAPublicKey k; if(!isNull() && isDSA()) assignToPublic(&k); return k; } DSAPrivateKey PKey::toDSAPrivateKey() const { DSAPrivateKey k; if(!isNull() && isDSA() && isPrivate()) assignToPrivate(&k); return k; } DHPublicKey PKey::toDHPublicKey() const { DHPublicKey k; if(!isNull() && isDH()) assignToPublic(&k); return k; } DHPrivateKey PKey::toDHPrivateKey() const { DHPrivateKey k; if(!isNull() && isDH() && isPrivate()) assignToPrivate(&k); return k; } bool PKey::operator==(const PKey &a) const { if(isNull() || a.isNull() || type() != a.type()) return false; if(a.isPrivate()) return (toPrivateKey().toDER() == a.toPrivateKey().toDER()); else return (toPublicKey().toDER() == a.toPublicKey().toDER()); } bool PKey::operator!=(const PKey &a) const { return !(*this == a); } //---------------------------------------------------------------------------- // PublicKey //---------------------------------------------------------------------------- PublicKey::PublicKey() { } PublicKey::PublicKey(const QString &type, const QString &provider) :PKey(type, provider) { } PublicKey::PublicKey(const PrivateKey &k) { set(k.toPublicKey()); } PublicKey::PublicKey(const QString &fileName) { *this = fromPEMFile(fileName, 0, QString()); } PublicKey::PublicKey(const PublicKey &from) :PKey(from) { } PublicKey::~PublicKey() { } PublicKey & PublicKey::operator=(const PublicKey &from) { PKey::operator=(from); return *this; } RSAPublicKey PublicKey::toRSA() const { return toRSAPublicKey(); } DSAPublicKey PublicKey::toDSA() const { return toDSAPublicKey(); } DHPublicKey PublicKey::toDH() const { return toDHPublicKey(); } bool PublicKey::canEncrypt() const { return isRSA(); } bool PublicKey::canVerify() const { return (isRSA() || isDSA()); } int PublicKey::maximumEncryptSize(EncryptionAlgorithm alg) const { return static_cast(context())->key()->maximumEncryptSize(alg); } SecureArray PublicKey::encrypt(const SecureArray &a, EncryptionAlgorithm alg) { return static_cast(context())->key()->encrypt(a, alg); } void PublicKey::startVerify(SignatureAlgorithm alg, SignatureFormat format) { if(isDSA() && format == DefaultFormat) format = IEEE_1363; static_cast(context())->key()->startVerify(alg, format); } void PublicKey::update(const MemoryRegion &a) { static_cast(context())->key()->update(a); } bool PublicKey::validSignature(const QByteArray &sig) { return static_cast(context())->key()->endVerify(sig); } bool PublicKey::verifyMessage(const MemoryRegion &a, const QByteArray &sig, SignatureAlgorithm alg, SignatureFormat format) { startVerify(alg, format); update(a); return validSignature(sig); } QByteArray PublicKey::toDER() const { QByteArray out; const PKeyContext *cur = static_cast(context()); Provider *p = providerForIOType(type(), cur); if(!p) return out; if(cur->provider() == p) { out = cur->publicToDER(); } else { PKeyContext *pk = static_cast(getContext("pkey", p)); if(pk->importKey(cur->key())) out = pk->publicToDER(); delete pk; } return out; } QString PublicKey::toPEM() const { QString out; const PKeyContext *cur = static_cast(context()); Provider *p = providerForIOType(type(), cur); if(!p) return out; if(cur->provider() == p) { out = cur->publicToPEM(); } else { PKeyContext *pk = static_cast(getContext("pkey", p)); if(pk->importKey(cur->key())) out = pk->publicToPEM(); delete pk; } return out; } bool PublicKey::toPEMFile(const QString &fileName) const { return stringToFile(fileName, toPEM()); } PublicKey PublicKey::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) { return getKey, QByteArray>(provider, a, SecureArray(), result); } PublicKey PublicKey::fromPEM(const QString &s, ConvertResult *result, const QString &provider) { return getKey, QString>(provider, s, SecureArray(), result); } PublicKey PublicKey::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) { QString pem; if(!stringFromFile(fileName, &pem)) { if(result) *result = ErrorFile; return PublicKey(); } return fromPEM(pem, result, provider); } //---------------------------------------------------------------------------- // PrivateKey //---------------------------------------------------------------------------- PrivateKey::PrivateKey() { } PrivateKey::PrivateKey(const QString &type, const QString &provider) :PKey(type, provider) { } PrivateKey::PrivateKey(const QString &fileName, const SecureArray &passphrase) { *this = fromPEMFile(fileName, passphrase, 0, QString()); } PrivateKey::PrivateKey(const PrivateKey &from) :PKey(from) { } PrivateKey::~PrivateKey() { } PrivateKey & PrivateKey::operator=(const PrivateKey &from) { PKey::operator=(from); return *this; } RSAPrivateKey PrivateKey::toRSA() const { return toRSAPrivateKey(); } DSAPrivateKey PrivateKey::toDSA() const { return toDSAPrivateKey(); } DHPrivateKey PrivateKey::toDH() const { return toDHPrivateKey(); } bool PrivateKey::canDecrypt() const { return isRSA(); } bool PrivateKey::canSign() const { return (isRSA() || isDSA()); } bool PrivateKey::decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) { return static_cast(context())->key()->decrypt(in, out, alg); } void PrivateKey::startSign(SignatureAlgorithm alg, SignatureFormat format) { if(isDSA() && format == DefaultFormat) format = IEEE_1363; static_cast(context())->key()->startSign(alg, format); } void PrivateKey::update(const MemoryRegion &a) { static_cast(context())->key()->update(a); } QByteArray PrivateKey::signature() { return static_cast(context())->key()->endSign(); } QByteArray PrivateKey::signMessage(const MemoryRegion &a, SignatureAlgorithm alg, SignatureFormat format) { startSign(alg, format); update(a); return signature(); } SymmetricKey PrivateKey::deriveKey(const PublicKey &theirs) { const PKeyContext *theirContext = static_cast(theirs.context()); return static_cast(context())->key()->deriveKey(*(theirContext->key())); } QList PrivateKey::supportedPBEAlgorithms(const QString &provider) { return getList(provider); } SecureArray PrivateKey::toDER(const SecureArray &passphrase, PBEAlgorithm pbe) const { SecureArray out; if(pbe == PBEDefault) pbe = get_pbe_default(); const PKeyContext *cur = static_cast(context()); Provider *p = providerForPBE(pbe, type(), cur); if(!p) return out; if(cur->provider() == p) { out = cur->privateToDER(passphrase, pbe); } else { PKeyContext *pk = static_cast(getContext("pkey", p)); if(pk->importKey(cur->key())) out = pk->privateToDER(passphrase, pbe); delete pk; } return out; } QString PrivateKey::toPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const { QString out; if(pbe == PBEDefault) pbe = get_pbe_default(); const PKeyContext *cur = static_cast(context()); Provider *p = providerForPBE(pbe, type(), cur); if(!p) return out; if(cur->provider() == p) { out = cur->privateToPEM(passphrase, pbe); } else { PKeyContext *pk = static_cast(getContext("pkey", p)); if(pk->importKey(cur->key())) out = pk->privateToPEM(passphrase, pbe); delete pk; } return out; } bool PrivateKey::toPEMFile(const QString &fileName, const SecureArray &passphrase, PBEAlgorithm pbe) const { return stringToFile(fileName, toPEM(passphrase, pbe)); } PrivateKey PrivateKey::fromDER(const SecureArray &a, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { return get_privatekey_der(a, QString(), (void *)&a, passphrase, result, provider); } PrivateKey PrivateKey::fromPEM(const QString &s, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { return get_privatekey_pem(s, QString(), (void *)&s, passphrase, result, provider); } PrivateKey PrivateKey::fromPEMFile(const QString &fileName, const SecureArray &passphrase, ConvertResult *result, const QString &provider) { QString pem; if(!stringFromFile(fileName, &pem)) { if(result) *result = ErrorFile; return PrivateKey(); } return get_privatekey_pem(pem, fileName, 0, passphrase, result, provider); } //---------------------------------------------------------------------------- // KeyGenerator //---------------------------------------------------------------------------- class KeyGenerator::Private : public QObject { Q_OBJECT public: KeyGenerator *parent; bool blocking, wasBlocking; PrivateKey key; DLGroup group; PKeyBase *k; PKeyContext *dest; DLGroupContext *dc; Private(KeyGenerator *_parent) : QObject(_parent), parent(_parent) { k = 0; dest = 0; dc = 0; } ~Private() { delete k; delete dest; delete dc; } public slots: void done() { if(!k->isNull()) { if(!wasBlocking) { k->setParent(0); k->moveToThread(0); } dest->setKey(k); k = 0; key.change(dest); dest = 0; } else { delete k; k = 0; delete dest; dest = 0; } if(!wasBlocking) emit parent->finished(); } void done_group() { if(!dc->isNull()) { BigInteger p, q, g; dc->getResult(&p, &q, &g); group = DLGroup(p, q, g); } delete dc; dc = 0; if(!wasBlocking) emit parent->finished(); } }; KeyGenerator::KeyGenerator(QObject *parent) :QObject(parent) { d = new Private(this); d->blocking = true; } KeyGenerator::~KeyGenerator() { delete d; } bool KeyGenerator::blockingEnabled() const { return d->blocking; } void KeyGenerator::setBlockingEnabled(bool b) { d->blocking = b; } bool KeyGenerator::isBusy() const { return (d->k ? true: false); } PrivateKey KeyGenerator::createRSA(int bits, int exp, const QString &provider) { if(isBusy()) return PrivateKey(); d->key = PrivateKey(); d->wasBlocking = d->blocking; d->k = static_cast(getContext("rsa", provider)); d->dest = static_cast(getContext("pkey", d->k->provider())); if(!d->blocking) { d->k->moveToThread(thread()); d->k->setParent(d); connect(d->k, SIGNAL(finished()), d, SLOT(done())); static_cast(d->k)->createPrivate(bits, exp, false); } else { static_cast(d->k)->createPrivate(bits, exp, true); d->done(); } return d->key; } PrivateKey KeyGenerator::createDSA(const DLGroup &domain, const QString &provider) { if(isBusy()) return PrivateKey(); d->key = PrivateKey(); d->wasBlocking = d->blocking; d->k = static_cast(getContext("dsa", provider)); d->dest = static_cast(getContext("pkey", d->k->provider())); if(!d->blocking) { d->k->moveToThread(thread()); d->k->setParent(d); connect(d->k, SIGNAL(finished()), d, SLOT(done())); static_cast(d->k)->createPrivate(domain, false); } else { static_cast(d->k)->createPrivate(domain, true); d->done(); } return d->key; } PrivateKey KeyGenerator::createDH(const DLGroup &domain, const QString &provider) { if(isBusy()) return PrivateKey(); d->key = PrivateKey(); d->wasBlocking = d->blocking; d->k = static_cast(getContext("dh", provider)); d->dest = static_cast(getContext("pkey", d->k->provider())); if(!d->blocking) { d->k->moveToThread(thread()); d->k->setParent(d); connect(d->k, SIGNAL(finished()), d, SLOT(done())); static_cast(d->k)->createPrivate(domain, false); } else { static_cast(d->k)->createPrivate(domain, true); d->done(); } return d->key; } PrivateKey KeyGenerator::key() const { return d->key; } DLGroup KeyGenerator::createDLGroup(QCA::DLGroupSet set, const QString &provider) { if(isBusy()) return DLGroup(); Provider *p; if(!provider.isEmpty()) p = providerForName(provider); else p = providerForGroupSet(set); d->group = DLGroup(); d->wasBlocking = d->blocking; d->dc = static_cast(getContext("dlgroup", p)); if(!d->blocking) { connect(d->dc, SIGNAL(finished()), d, SLOT(done_group())); d->dc->fetchGroup(set, false); } else { d->dc->fetchGroup(set, true); d->done_group(); } return d->group; } DLGroup KeyGenerator::dlGroup() const { return d->group; } //---------------------------------------------------------------------------- // RSAPublicKey //---------------------------------------------------------------------------- RSAPublicKey::RSAPublicKey() { } RSAPublicKey::RSAPublicKey(const BigInteger &n, const BigInteger &e, const QString &provider) { RSAContext *k = static_cast(getContext("rsa", provider)); k->createPublic(n, e); PKeyContext *c = static_cast(getContext("pkey", k->provider())); c->setKey(k); change(c); } RSAPublicKey::RSAPublicKey(const RSAPrivateKey &k) :PublicKey(k) { } BigInteger RSAPublicKey::n() const { return static_cast(static_cast(context())->key())->n(); } BigInteger RSAPublicKey::e() const { return static_cast(static_cast(context())->key())->e(); } //---------------------------------------------------------------------------- // RSAPrivateKey //---------------------------------------------------------------------------- RSAPrivateKey::RSAPrivateKey() { } RSAPrivateKey::RSAPrivateKey(const BigInteger &n, const BigInteger &e, const BigInteger &p, const BigInteger &q, const BigInteger &d, const QString &provider) { RSAContext *k = static_cast(getContext("rsa", provider)); k->createPrivate(n, e, p, q, d); PKeyContext *c = static_cast(getContext("pkey", k->provider())); c->setKey(k); change(c); } BigInteger RSAPrivateKey::n() const { return static_cast(static_cast(context())->key())->n(); } BigInteger RSAPrivateKey::e() const { return static_cast(static_cast(context())->key())->e(); } BigInteger RSAPrivateKey::p() const { return static_cast(static_cast(context())->key())->p(); } BigInteger RSAPrivateKey::q() const { return static_cast(static_cast(context())->key())->q(); } BigInteger RSAPrivateKey::d() const { return static_cast(static_cast(context())->key())->d(); } //---------------------------------------------------------------------------- // DSAPublicKey //---------------------------------------------------------------------------- DSAPublicKey::DSAPublicKey() { } DSAPublicKey::DSAPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider) { DSAContext *k = static_cast(getContext("dsa", provider)); k->createPublic(domain, y); PKeyContext *c = static_cast(getContext("pkey", k->provider())); c->setKey(k); change(c); } DSAPublicKey::DSAPublicKey(const DSAPrivateKey &k) :PublicKey(k) { } DLGroup DSAPublicKey::domain() const { return static_cast(static_cast(context())->key())->domain(); } BigInteger DSAPublicKey::y() const { return static_cast(static_cast(context())->key())->y(); } //---------------------------------------------------------------------------- // DSAPrivateKey //---------------------------------------------------------------------------- DSAPrivateKey::DSAPrivateKey() { } DSAPrivateKey::DSAPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider) { DSAContext *k = static_cast(getContext("dsa", provider)); k->createPrivate(domain, y, x); PKeyContext *c = static_cast(getContext("pkey", k->provider())); c->setKey(k); change(c); } DLGroup DSAPrivateKey::domain() const { return static_cast(static_cast(context())->key())->domain(); } BigInteger DSAPrivateKey::y() const { return static_cast(static_cast(context())->key())->y(); } BigInteger DSAPrivateKey::x() const { return static_cast(static_cast(context())->key())->x(); } //---------------------------------------------------------------------------- // DHPublicKey //---------------------------------------------------------------------------- DHPublicKey::DHPublicKey() { } DHPublicKey::DHPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider) { DHContext *k = static_cast(getContext("dh", provider)); k->createPublic(domain, y); PKeyContext *c = static_cast(getContext("pkey", k->provider())); c->setKey(k); change(c); } DHPublicKey::DHPublicKey(const DHPrivateKey &k) :PublicKey(k) { } DLGroup DHPublicKey::domain() const { return static_cast(static_cast(context())->key())->domain(); } BigInteger DHPublicKey::y() const { return static_cast(static_cast(context())->key())->y(); } //---------------------------------------------------------------------------- // DHPrivateKey //---------------------------------------------------------------------------- DHPrivateKey::DHPrivateKey() { } DHPrivateKey::DHPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider) { DHContext *k = static_cast(getContext("dh", provider)); k->createPrivate(domain, y, x); PKeyContext *c = static_cast(getContext("pkey", k->provider())); c->setKey(k); change(c); } DLGroup DHPrivateKey::domain() const { return static_cast(static_cast(context())->key())->domain(); } BigInteger DHPrivateKey::y() const { return static_cast(static_cast(context())->key())->y(); } BigInteger DHPrivateKey::x() const { return static_cast(static_cast(context())->key())->x(); } } #include "qca_publickey.moc" psi-0.14/third-party/qca/qca/src/qca_systemstore_win.cpp0000644000175000017500000000347611305557613021527 0ustar janjan/* * Copyright (C) 2004,2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ // need to define this immediately #define _WIN32_WINNT 0x400 #include "qca_systemstore.h" #include #include namespace QCA { bool qca_have_systemstore() { bool ok = false; HCERTSTORE hSystemStore; hSystemStore = CertOpenSystemStoreA(0, "ROOT"); if(hSystemStore) ok = true; CertCloseStore(hSystemStore, 0); return ok; } CertificateCollection qca_get_systemstore(const QString &provider) { CertificateCollection col; HCERTSTORE hSystemStore; hSystemStore = CertOpenSystemStoreA(0, "ROOT"); if(!hSystemStore) return col; PCCERT_CONTEXT pc = NULL; while(1) { pc = CertFindCertificateInStore( hSystemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pc); if(!pc) break; int size = pc->cbCertEncoded; QByteArray der(size, 0); memcpy(der.data(), pc->pbCertEncoded, size); Certificate cert = Certificate::fromDER(der, 0, provider); if(!cert.isNull()) col.addCertificate(cert); } CertCloseStore(hSystemStore, 0); return col; } } psi-0.14/third-party/qca/qca/src/qca_plugin.cpp0000644000175000017500000004042211305557613017537 0ustar janjan/* * Copyright (C) 2004-2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ // Note: The basic thread-safety approach with the plugin manager is that // it is safe to add/get providers, however it is unsafe to remove them. // The expectation is that providers will almost always be unloaded on // application shutdown. For safe provider unload, ensure no threads are // using the manager, the provider in question, nor any sub-objects from // the provider. #include "qca_plugin.h" #include "qcaprovider.h" #include #include #include #include #include #define PLUGIN_SUBDIR "crypto" namespace QCA { // from qca_core.cpp QVariantMap getProviderConfig_internal(Provider *p); // from qca_default.cpp QStringList skip_plugins(Provider *defaultProvider); QStringList plugin_priorities(Provider *defaultProvider); // stupidly simple log truncation function. if the log exceeds size chars, // then throw out the top half, to nearest line. QString truncate_log(const QString &in, int size) { if(size < 2 || in.length() < size) return in; // start by pointing at the last chars int at = in.length() - (size / 2); // if the previous char is a newline, then this is a perfect cut. // otherwise, we need to skip to after the next newline. if(in[at - 1] != '\n') { while(at < in.length() && in[at] != '\n') { ++at; } // at this point we either reached a newline, or end of // the entire buffer if(in[at] == '\n') ++at; } return in.mid(at); } static ProviderManager *g_pluginman = 0; static void logDebug(const QString &str) { if(g_pluginman) g_pluginman->appendDiagnosticText(str + '\n'); } static bool validVersion(int ver) { // major version must be equal, minor version must be equal or lesser if((ver & 0xff0000) == (QCA_VERSION & 0xff0000) && (ver & 0xff00) <= (QCA_VERSION & 0xff00)) return true; return false; } class PluginInstance { private: QPluginLoader *_loader; QObject *_instance; bool _ownInstance; PluginInstance() { } public: static PluginInstance *fromFile(const QString &fname, QString *errstr = 0) { QPluginLoader *loader = new QPluginLoader(fname); if(!loader->load()) { if(errstr) *errstr = QString("failed to load: %1").arg(loader->errorString()); delete loader; return 0; } QObject *obj = loader->instance(); if(!obj) { if(errstr) *errstr = "failed to get instance"; loader->unload(); delete loader; return 0; } PluginInstance *i = new PluginInstance; i->_loader = loader; i->_instance = obj; i->_ownInstance = true; return i; } static PluginInstance *fromStatic(QObject *obj) { PluginInstance *i = new PluginInstance; i->_loader = 0; i->_instance = obj; i->_ownInstance = false; return i; } static PluginInstance *fromInstance(QObject *obj) { PluginInstance *i = new PluginInstance; i->_loader = 0; i->_instance = obj; i->_ownInstance = true; return i; } ~PluginInstance() { QString className = QString::fromLatin1(_instance->metaObject()->className()); if(_ownInstance) delete _instance; if(_loader) { _loader->unload(); delete _loader; } } void claim() { if(_loader) _loader->moveToThread(0); if(_ownInstance) _instance->moveToThread(0); } QObject *instance() { return _instance; } }; class ProviderItem { public: QString fname; Provider *p; int priority; QMutex m; static ProviderItem *load(const QString &fname, QString *out_errstr = 0) { QString errstr; PluginInstance *i = PluginInstance::fromFile(fname, &errstr); if(!i) { if(out_errstr) *out_errstr = errstr; return 0; } QCAPlugin *plugin = qobject_cast(i->instance()); if(!plugin) { if(out_errstr) *out_errstr = "does not offer QCAPlugin interface"; delete i; return 0; } Provider *p = plugin->createProvider(); if(!p) { if(out_errstr) *out_errstr = "unable to create provider"; delete i; return 0; } ProviderItem *pi = new ProviderItem(i, p); pi->fname = fname; return pi; } static ProviderItem *loadStatic(QObject *instance, QString *errstr = 0) { PluginInstance *i = PluginInstance::fromStatic(instance); QCAPlugin *plugin = qobject_cast(i->instance()); if(!plugin) { if(errstr) *errstr = "does not offer QCAPlugin interface"; delete i; return 0; } Provider *p = plugin->createProvider(); if(!p) { if(errstr) *errstr = "unable to create provider"; delete i; return 0; } ProviderItem *pi = new ProviderItem(i, p); return pi; } static ProviderItem *fromClass(Provider *p) { ProviderItem *pi = new ProviderItem(0, p); return pi; } ~ProviderItem() { delete p; delete instance; } void ensureInit() { QMutexLocker locker(&m); if(init_done) return; init_done = true; p->init(); // load config QVariantMap conf = getProviderConfig_internal(p); if(!conf.isEmpty()) p->configChanged(conf); } bool initted() const { return init_done; } // null if not a plugin QObject *objectInstance() const { if(instance) return instance->instance(); else return 0; } private: PluginInstance *instance; bool init_done; ProviderItem(PluginInstance *_instance, Provider *_p) { instance = _instance; p = _p; init_done = false; // disassociate from threads if(instance) instance->claim(); } }; ProviderManager::ProviderManager() { g_pluginman = this; def = 0; scanned_static = false; } ProviderManager::~ProviderManager() { if(def) def->deinit(); unloadAll(); delete def; g_pluginman = 0; } void ProviderManager::scan() { QMutexLocker locker(&providerMutex); // check static first, but only once if(!scanned_static) { logDebug("Checking Qt static plugins:"); QObjectList list = QPluginLoader::staticInstances(); if(list.isEmpty()) logDebug(" (none)"); for(int n = 0; n < list.count(); ++n) { QObject *instance = list[n]; QString className = QString::fromLatin1(instance->metaObject()->className()); QString errstr; ProviderItem *i = ProviderItem::loadStatic(instance, &errstr); if(!i) { logDebug(QString(" %1: %2").arg(className, errstr)); continue; } QString providerName = i->p->name(); if(haveAlready(providerName)) { logDebug(QString(" %1: (as %2) already loaded provider, skipping").arg(className, providerName)); delete i; continue; } int ver = i->p->qcaVersion(); if(!validVersion(ver)) { errstr.sprintf("plugin version 0x%06x is in the future", ver); logDebug(QString(" %1: (as %2) %3").arg(className, providerName, errstr)); delete i; continue; } addItem(i, get_default_priority(providerName)); logDebug(QString(" %1: loaded as %2").arg(className, providerName)); } scanned_static = true; } #ifndef QCA_NO_PLUGINS if(qgetenv("QCA_NO_PLUGINS") == "1") return; // check plugin files QStringList dirs = QCoreApplication::libraryPaths(); if(dirs.isEmpty()) logDebug("No Qt Library Paths"); for(QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { logDebug(QString("Checking Qt Library Path: %1").arg(*it)); QDir libpath(*it); QDir dir(libpath.filePath(PLUGIN_SUBDIR)); if(!dir.exists()) { logDebug(" (No 'crypto' subdirectory)"); continue; } QStringList entryList = dir.entryList(); // filter out "." and ".." to keep debug output cleaner entryList.removeAll("."); entryList.removeAll(".."); if(entryList.isEmpty()) { logDebug(" (No files in 'crypto' subdirectory)"); continue; } foreach(const QString &maybeFile, entryList) { QFileInfo fi(dir.filePath(maybeFile)); QString filePath = fi.filePath(); // file name with path QString fileName = fi.fileName(); // just file name if(!QLibrary::isLibrary(filePath)) { logDebug(QString(" %1: not a library, skipping").arg(fileName)); continue; } // make sure we haven't loaded this file before bool haveFile = false; for(int n = 0; n < providerItemList.count(); ++n) { ProviderItem *pi = providerItemList[n]; if(!pi->fname.isEmpty() && pi->fname == filePath) { haveFile = true; break; } } if(haveFile) { logDebug(QString(" %1: already loaded file, skipping").arg(fileName)); continue; } QString errstr; ProviderItem *i = ProviderItem::load(filePath, &errstr); if(!i) { logDebug(QString(" %1: %2").arg(fileName, errstr)); continue; } QString className = QString::fromLatin1(i->objectInstance()->metaObject()->className()); QString providerName = i->p->name(); if(haveAlready(providerName)) { logDebug(QString(" %1: (class: %2, as %3) already loaded provider, skipping").arg(fileName, className, providerName)); delete i; continue; } int ver = i->p->qcaVersion(); if(!validVersion(ver)) { errstr.sprintf("plugin version 0x%06x is in the future", ver); logDebug(QString(" %1: (class: %2, as %3) %4").arg(fileName, className, providerName, errstr)); delete i; continue; } if(skip_plugins(def).contains(providerName)) { logDebug(QString(" %1: (class: %2, as %3) explicitly disabled, skipping").arg(fileName, className, providerName)); delete i; continue; } addItem(i, get_default_priority(providerName)); logDebug(QString(" %1: (class: %2) loaded as %3").arg(fileName, className, providerName)); } } #endif } bool ProviderManager::add(Provider *p, int priority) { QMutexLocker locker(&providerMutex); QString providerName = p->name(); if(haveAlready(providerName)) { logDebug(QString("Directly adding: %1: already loaded provider, skipping").arg(providerName)); return false; } int ver = p->qcaVersion(); if(!validVersion(ver)) { QString errstr; errstr.sprintf("plugin version 0x%06x is in the future", ver); logDebug(QString("Directly adding: %1: %2").arg(providerName, errstr)); return false; } ProviderItem *i = ProviderItem::fromClass(p); addItem(i, priority); logDebug(QString("Directly adding: %1: loaded").arg(providerName)); return true; } void ProviderManager::unload(const QString &name) { for(int n = 0; n < providerItemList.count(); ++n) { ProviderItem *i = providerItemList[n]; if(i->p && i->p->name() == name) { delete i; providerItemList.removeAt(n); providerList.removeAt(n); logDebug(QString("Unloaded: %1").arg(name)); return; } } } void ProviderManager::unloadAll() { foreach(ProviderItem *i, providerItemList) { if(i->initted()) i->p->deinit(); } while(!providerItemList.isEmpty()) { ProviderItem *i = providerItemList.first(); QString name = i->p->name(); delete i; providerItemList.removeFirst(); providerList.removeFirst(); logDebug(QString("Unloaded: %1").arg(name)); } } void ProviderManager::setDefault(Provider *p) { QMutexLocker locker(&providerMutex); if(def) delete def; def = p; if(def) { def->init(); QVariantMap conf = getProviderConfig_internal(def); if(!conf.isEmpty()) def->configChanged(conf); } } Provider *ProviderManager::find(Provider *_p) const { ProviderItem *i = 0; Provider *p = 0; providerMutex.lock(); if(_p == def) { p = def; } else { for(int n = 0; n < providerItemList.count(); ++n) { ProviderItem *pi = providerItemList[n]; if(pi->p && pi->p == _p) { i = pi; p = pi->p; break; } } } providerMutex.unlock(); if(i) i->ensureInit(); return p; } Provider *ProviderManager::find(const QString &name) const { ProviderItem *i = 0; Provider *p = 0; providerMutex.lock(); if(def && name == def->name()) { p = def; } else { for(int n = 0; n < providerItemList.count(); ++n) { ProviderItem *pi = providerItemList[n]; if(pi->p && pi->p->name() == name) { i = pi; p = pi->p; break; } } } providerMutex.unlock(); if(i) i->ensureInit(); return p; } Provider *ProviderManager::findFor(const QString &name, const QString &type) const { if(name.isEmpty()) { providerMutex.lock(); QList list = providerItemList; providerMutex.unlock(); // find the first one that can do it for(int n = 0; n < list.count(); ++n) { ProviderItem *pi = list[n]; pi->ensureInit(); if(pi->p && pi->p->features().contains(type)) return pi->p; } // try the default provider as a last resort providerMutex.lock(); Provider *p = def; providerMutex.unlock(); if(p && p->features().contains(type)) return p; return 0; } else { Provider *p = find(name); if(p && p->features().contains(type)) return p; return 0; } } void ProviderManager::changePriority(const QString &name, int priority) { QMutexLocker locker(&providerMutex); ProviderItem *i = 0; int n = 0; for(; n < providerItemList.count(); ++n) { ProviderItem *pi = providerItemList[n]; if(pi->p && pi->p->name() == name) { i = pi; break; } } if(!i) return; providerItemList.removeAt(n); providerList.removeAt(n); addItem(i, priority); } int ProviderManager::getPriority(const QString &name) { QMutexLocker locker(&providerMutex); ProviderItem *i = 0; for(int n = 0; n < providerItemList.count(); ++n) { ProviderItem *pi = providerItemList[n]; if(pi->p && pi->p->name() == name) { i = pi; break; } } if(!i) return -1; return i->priority; } QStringList ProviderManager::allFeatures() const { QStringList featureList; providerMutex.lock(); Provider *p = def; providerMutex.unlock(); if(p) featureList = p->features(); providerMutex.lock(); QList list = providerItemList; providerMutex.unlock(); for(int n = 0; n < list.count(); ++n) { ProviderItem *i = list[n]; if(i->p) mergeFeatures(&featureList, i->p->features()); } return featureList; } ProviderList ProviderManager::providers() const { QMutexLocker locker(&providerMutex); return providerList; } QString ProviderManager::diagnosticText() const { QMutexLocker locker(&logMutex); return dtext; } void ProviderManager::appendDiagnosticText(const QString &str) { QMutexLocker locker(&logMutex); dtext += str; dtext = truncate_log(dtext, 20000); } void ProviderManager::clearDiagnosticText() { QMutexLocker locker(&logMutex); dtext = QString(); } void ProviderManager::addItem(ProviderItem *item, int priority) { if(priority < 0) { // for -1, make the priority the same as the last item if(!providerItemList.isEmpty()) { ProviderItem *last = providerItemList.last(); item->priority = last->priority; } else item->priority = 0; providerItemList.append(item); providerList.append(item->p); } else { // place the item before any other items with same or greater priority int n = 0; for(; n < providerItemList.count(); ++n) { ProviderItem *i = providerItemList[n]; if(i->priority >= priority) break; } item->priority = priority; providerItemList.insert(n, item); providerList.insert(n, item->p); } } bool ProviderManager::haveAlready(const QString &name) const { if(def && name == def->name()) return true; for(int n = 0; n < providerItemList.count(); ++n) { ProviderItem *pi = providerItemList[n]; if(pi->p && pi->p->name() == name) return true; } return false; } void ProviderManager::mergeFeatures(QStringList *a, const QStringList &b) { for(QStringList::ConstIterator it = b.begin(); it != b.end(); ++it) { if(!a->contains(*it)) a->append(*it); } } int ProviderManager::get_default_priority(const QString &name) const { QStringList list = plugin_priorities(def); foreach(const QString &s, list) { // qca_default already sanity checks the strings int n = s.indexOf(':'); QString sname = s.mid(0, n); int spriority = s.mid(n + 1).toInt(); if(sname == name) return spriority; } return -1; } } psi-0.14/third-party/qca/qca/src/botantools/0000755000175000017500000000000011305557613017073 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/btest.cpp0000644000175000017500000000164211305557613020723 0ustar janjan/* * btest.cpp - test to ensure botantools compiles properly * Copyright (C) 2004-2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #include "botantools.h" int main() { return 0; } psi-0.14/third-party/qca/qca/src/botantools/btest.pro0000644000175000017500000000014011305557613020731 0ustar janjanCONFIG += console CONFIG -= app_bundle QT -= gui include(botantools.pri) SOURCES += btest.cpp psi-0.14/third-party/qca/qca/src/botantools/botan/0000755000175000017500000000000011305557613020176 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/botan/mp_asm.cpp0000644000175000017500000001575011305557613022166 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Lowest Level MPI Algorithms Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { extern "C" { /************************************************* * Two Operand Addition, No Carry * *************************************************/ word bigint_add2_nc(word x[], u32bit x_size, const word y[], u32bit y_size) { word carry = 0; const u32bit blocks = y_size - (y_size % 8); for(u32bit j = 0; j != blocks; j += 8) carry = word8_add2(x + j, y + j, carry); for(u32bit j = blocks; j != y_size; ++j) x[j] = word_add(x[j], y[j], &carry); if(!carry) return 0; for(u32bit j = y_size; j != x_size; ++j) if(++x[j]) return 0; return 1; } /************************************************* * Three Operand Addition, No Carry * *************************************************/ word bigint_add3_nc(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) { if(x_size < y_size) { return bigint_add3_nc(z, y, y_size, x, x_size); } word carry = 0; const u32bit blocks = y_size - (y_size % 8); for(u32bit j = 0; j != blocks; j += 8) carry = word8_add3(z + j, x + j, y + j, carry); for(u32bit j = blocks; j != y_size; ++j) z[j] = word_add(x[j], y[j], &carry); for(u32bit j = y_size; j != x_size; ++j) { word x_j = x[j] + carry; if(carry && x_j) carry = 0; z[j] = x_j; } return carry; } /************************************************* * Two Operand Addition * *************************************************/ void bigint_add2(word x[], u32bit x_size, const word y[], u32bit y_size) { if(bigint_add2_nc(x, x_size, y, y_size)) ++x[x_size]; } /************************************************* * Three Operand Addition * *************************************************/ void bigint_add3(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) { if(bigint_add3_nc(z, x, x_size, y, y_size)) ++z[(x_size > y_size ? x_size : y_size)]; } /************************************************* * Two Operand Subtraction * *************************************************/ void bigint_sub2(word x[], u32bit x_size, const word y[], u32bit y_size) { word carry = 0; const u32bit blocks = y_size - (y_size % 8); for(u32bit j = 0; j != blocks; j += 8) carry = word8_sub2(x + j, y + j, carry); for(u32bit j = blocks; j != y_size; ++j) x[j] = word_sub(x[j], y[j], &carry); if(!carry) return; for(u32bit j = y_size; j != x_size; ++j) { --x[j]; if(x[j] != MP_WORD_MAX) return; } } /************************************************* * Three Operand Subtraction * *************************************************/ void bigint_sub3(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) { word carry = 0; const u32bit blocks = y_size - (y_size % 8); for(u32bit j = 0; j != blocks; j += 8) carry = word8_sub3(z + j, x + j, y + j, carry); for(u32bit j = blocks; j != y_size; ++j) z[j] = word_sub(x[j], y[j], &carry); for(u32bit j = y_size; j != x_size; ++j) { word x_j = x[j] - carry; if(carry && x_j != MP_WORD_MAX) carry = 0; z[j] = x_j; } } /************************************************* * Two Operand Linear Multiply * *************************************************/ void bigint_linmul2(word x[], u32bit x_size, word y) { const u32bit blocks = x_size - (x_size % 8); word carry = 0; for(u32bit j = 0; j != blocks; j += 8) carry = word8_linmul2(x + j, y, carry); for(u32bit j = blocks; j != x_size; ++j) x[j] = word_madd2(x[j], y, carry, &carry); x[x_size] = carry; } /************************************************* * Three Operand Linear Multiply * *************************************************/ void bigint_linmul3(word z[], const word x[], u32bit x_size, word y) { const u32bit blocks = x_size - (x_size % 8); word carry = 0; for(u32bit j = 0; j != blocks; j += 8) carry = word8_linmul3(z + j, x + j, y, carry); for(u32bit j = blocks; j != x_size; ++j) z[j] = word_madd2(x[j], y, carry, &carry); z[x_size] = carry; } /************************************************* * Montgomery Reduction Algorithm * *************************************************/ #ifndef BOTAN_MINIMAL_BIGINT void bigint_monty_redc(word z[], u32bit z_size, const word x[], u32bit x_size, word u) { for(u32bit j = 0; j != x_size; ++j) { word* z_j = z + j; const word y = z_j[0] * u; word carry = bigint_mul_add_words(z_j, x, x_size, y); word z_sum = z_j[x_size] + carry; carry = (z_sum < z_j[x_size]); z_j[x_size] = z_sum; for(u32bit k = x_size + 1; carry && k != z_size - j; ++k) { ++z_j[k]; carry = !z_j[k]; } } if(bigint_cmp(z + x_size, x_size + 1, x, x_size) >= 0) bigint_sub2(z + x_size, x_size + 1, x, x_size); } #endif } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mp_shift.cpp0000644000175000017500000001063711305557613022522 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * MP Shift Algorithms Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { extern "C" { /************************************************* * Single Operand Left Shift * *************************************************/ void bigint_shl1(word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) { if(word_shift) { for(u32bit j = 1; j != x_size + 1; ++j) x[(x_size - j) + word_shift] = x[x_size - j]; clear_mem(x, word_shift); } if(bit_shift) { word carry = 0; for(u32bit j = word_shift; j != x_size + word_shift + 1; ++j) { word temp = x[j]; x[j] = (temp << bit_shift) | carry; carry = (temp >> (MP_WORD_BITS - bit_shift)); } } } /************************************************* * Single Operand Right Shift * *************************************************/ void bigint_shr1(word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) { if(x_size < word_shift) { clear_mem(x, x_size); return; } if(word_shift) { for(u32bit j = 0; j != x_size - word_shift; ++j) x[j] = x[j + word_shift]; for(u32bit j = x_size - word_shift; j != x_size; ++j) x[j] = 0; } if(bit_shift) { word carry = 0; for(u32bit j = x_size - word_shift; j > 0; --j) { word temp = x[j-1]; x[j-1] = (temp >> bit_shift) | carry; carry = (temp << (MP_WORD_BITS - bit_shift)); } } } /************************************************* * Two Operand Left Shift * *************************************************/ void bigint_shl2(word y[], const word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) { for(u32bit j = 0; j != x_size; ++j) y[j + word_shift] = x[j]; if(bit_shift) { word carry = 0; for(u32bit j = word_shift; j != x_size + word_shift + 1; ++j) { word temp = y[j]; y[j] = (temp << bit_shift) | carry; carry = (temp >> (MP_WORD_BITS - bit_shift)); } } } /************************************************* * Two Operand Right Shift * *************************************************/ void bigint_shr2(word y[], const word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) { if(x_size < word_shift) return; for(u32bit j = 0; j != x_size - word_shift; ++j) y[j] = x[j + word_shift]; if(bit_shift) { word carry = 0; for(u32bit j = x_size - word_shift; j > 0; --j) { word temp = y[j-1]; y[j-1] = (temp >> bit_shift) | carry; carry = (temp << (MP_WORD_BITS - bit_shift)); } } } } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mp_misc.cpp0000644000175000017500000001074311305557613022336 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * MP Misc Functions Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { extern "C" { /************************************************* * Core Division Operation * *************************************************/ u32bit bigint_divcore(word q, word y1, word y2, word x1, word x2, word x3) { word y0 = 0; y2 = word_madd2(q, y2, y0, &y0); y1 = word_madd2(q, y1, y0, &y0); if(y0 > x1) return 1; if(y0 < x1) return 0; if(y1 > x2) return 1; if(y1 < x2) return 0; if(y2 > x3) return 1; if(y2 < x3) return 0; return 0; } /************************************************* * Compare two MP integers * *************************************************/ s32bit bigint_cmp(const word x[], u32bit x_size, const word y[], u32bit y_size) { if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); } while(x_size > y_size) { if(x[x_size-1]) return 1; x_size--; } for(u32bit j = x_size; j > 0; --j) { if(x[j-1] > y[j-1]) return 1; if(x[j-1] < y[j-1]) return -1; } return 0; } /************************************************* * Do a 2-word/1-word Division * *************************************************/ word bigint_divop(word n1, word n0, word d) { word high = n1 % d, quotient = 0; for(u32bit j = 0; j != MP_WORD_BITS; ++j) { word high_top_bit = (high & MP_WORD_TOP_BIT); high <<= 1; high |= (n0 >> (MP_WORD_BITS-1-j)) & 1; quotient <<= 1; if(high_top_bit || high >= d) { high -= d; quotient |= 1; } } return quotient; } /************************************************* * Do a 2-word/1-word Modulo * *************************************************/ word bigint_modop(word n1, word n0, word d) { word z = bigint_divop(n1, n0, d); word dummy = 0; z = word_madd2(z, d, dummy, &dummy); return (n0-z); } /************************************************* * Do a word*word->2-word Multiply * *************************************************/ void bigint_wordmul(word a, word b, word* out_low, word* out_high) { const u32bit MP_HWORD_BITS = MP_WORD_BITS / 2; const word MP_HWORD_MASK = ((word)1 << MP_HWORD_BITS) - 1; const word a_hi = (a >> MP_HWORD_BITS); const word a_lo = (a & MP_HWORD_MASK); const word b_hi = (b >> MP_HWORD_BITS); const word b_lo = (b & MP_HWORD_MASK); word x0 = a_hi * b_hi; word x1 = a_lo * b_hi; word x2 = a_hi * b_lo; word x3 = a_lo * b_lo; x2 += x3 >> (MP_HWORD_BITS); x2 += x1; if(x2 < x1) x0 += ((word)1 << MP_HWORD_BITS); *out_high = x0 + (x2 >> MP_HWORD_BITS); *out_low = ((x2 & MP_HWORD_MASK) << MP_HWORD_BITS) + (x3 & MP_HWORD_MASK); } } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/util.cpp0000644000175000017500000000724711305557613021671 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Utility Functions Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Round up n to multiple of align_to * *************************************************/ u32bit round_up(u32bit n, u32bit align_to) { if(n % align_to || n == 0) n += align_to - (n % align_to); return n; } /************************************************* * Round down n to multiple of align_to * *************************************************/ u32bit round_down(u32bit n, u32bit align_to) { return (n - (n % align_to)); } #ifndef BOTAN_TOOLS_ONLY /************************************************* * Return the work required for solving DL * *************************************************/ u32bit dl_work_factor(u32bit n_bits) { const u32bit MIN_ESTIMATE = 64; if(n_bits < 32) return 0; const double log_x = n_bits / 1.44; u32bit estimate = (u32bit)(2.76 * std::pow(log_x, 1.0/3.0) * std::pow(std::log(log_x), 2.0/3.0)); return std::max(estimate, MIN_ESTIMATE); } /************************************************* * Estimate the entropy of the buffer * *************************************************/ u32bit entropy_estimate(const byte buffer[], u32bit length) { if(length <= 4) return 0; u32bit estimate = 0; byte last = 0, last_delta = 0, last_delta2 = 0; for(u32bit j = 0; j != length; ++j) { byte delta = last ^ buffer[j]; last = buffer[j]; byte delta2 = delta ^ last_delta; last_delta = delta; byte delta3 = delta2 ^ last_delta2; last_delta2 = delta2; byte min_delta = delta; if(min_delta > delta2) min_delta = delta2; if(min_delta > delta3) min_delta = delta3; estimate += hamming_weight(min_delta); } return (estimate / 2); } #endif } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/bit_ops.cpp0000644000175000017500000001017511305557613022345 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Bit/Word Operations Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * XOR arrays together * *************************************************/ void xor_buf(byte data[], const byte mask[], u32bit length) { while(length >= 8) { data[0] ^= mask[0]; data[1] ^= mask[1]; data[2] ^= mask[2]; data[3] ^= mask[3]; data[4] ^= mask[4]; data[5] ^= mask[5]; data[6] ^= mask[6]; data[7] ^= mask[7]; data += 8; mask += 8; length -= 8; } for(u32bit j = 0; j != length; ++j) data[j] ^= mask[j]; } void xor_buf(byte out[], const byte in[], const byte mask[], u32bit length) { while(length >= 8) { out[0] = in[0] ^ mask[0]; out[1] = in[1] ^ mask[1]; out[2] = in[2] ^ mask[2]; out[3] = in[3] ^ mask[3]; out[4] = in[4] ^ mask[4]; out[5] = in[5] ^ mask[5]; out[6] = in[6] ^ mask[6]; out[7] = in[7] ^ mask[7]; in += 8; out += 8; mask += 8; length -= 8; } for(u32bit j = 0; j != length; ++j) out[j] = in[j] ^ mask[j]; } /************************************************* * Return true iff arg is 2**n for some n > 0 * *************************************************/ bool power_of_2(u64bit arg) { if(arg == 0 || arg == 1) return false; if((arg & (arg-1)) == 0) return true; return false; } /************************************************* * Return the index of the highest set bit * *************************************************/ u32bit high_bit(u64bit n) { for(u32bit count = 64; count > 0; --count) if((n >> (count - 1)) & 0x01) return count; return 0; } /************************************************* * Return the index of the lowest set bit * *************************************************/ u32bit low_bit(u64bit n) { for(u32bit count = 0; count != 64; ++count) if((n >> count) & 0x01) return (count + 1); return 0; } /************************************************* * Return the number of significant bytes in n * *************************************************/ u32bit significant_bytes(u64bit n) { for(u32bit j = 0; j != 8; ++j) if(get_byte(j, n)) return 8-j; return 0; } /************************************************* * Return the Hamming weight of n * *************************************************/ u32bit hamming_weight(u64bit n) { u32bit weight = 0; for(u32bit j = 0; j != 64; ++j) if((n >> j) & 0x01) ++weight; return weight; } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/0000755000175000017500000000000011305557613021301 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/botan/botan/mem_ops.h0000644000175000017500000000464011305557613023115 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Memory Operations Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MEMORY_OPS_H__ #define BOTAN_MEMORY_OPS_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Memory Manipulation Functions * *************************************************/ template inline void copy_mem(T* out, const T* in, u32bit n) { memmove(out, in, sizeof(T)*n); } template inline void clear_mem(T* ptr, u32bit n) { memset(ptr, 0, sizeof(T)*n); } template inline void set_mem(T* ptr, u32bit n, byte val) { memset(ptr, val, sizeof(T)*n); } template inline bool same_mem(const T* p1, const T* p2, u32bit n) { return (memcmp(p1, p2, sizeof(T)*n) == 0); } } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/secmem.h0000644000175000017500000002013511305557613022724 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Secure Memory Buffers Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__ #define BOTAN_SECURE_MEMORY_BUFFERS_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Variable Length Memory Buffer * *************************************************/ template class MemoryRegion { public: u32bit size() const { return used; } u32bit is_empty() const { return (used == 0); } u32bit has_items() const { return (used != 0); } operator T* () { return buf; } operator const T* () const { return buf; } T* begin() { return buf; } const T* begin() const { return buf; } T* end() { return (buf + size()); } const T* end() const { return (buf + size()); } bool operator==(const MemoryRegion& other) const { return (size() == other.size() && same_mem(buf, other.buf, size())); } bool operator<(const MemoryRegion&) const; bool operator!=(const MemoryRegion& in) const { return (!(*this == in)); } MemoryRegion& operator=(const MemoryRegion& in) { if(this != &in) set(in); return (*this); } void copy(const T in[], u32bit n) { copy(0, in, n); } void copy(u32bit off, const T in[], u32bit n) { copy_mem(buf + off, in, (n > size() - off) ? (size() - off) : n); } void set(const T in[], u32bit n) { create(n); copy(in, n); } void set(const MemoryRegion& in) { set(in.begin(), in.size()); } void append(const T data[], u32bit n) { grow_to(size()+n); copy(size() - n, data, n); } void append(T x) { append(&x, 1); } void append(const MemoryRegion& x) { append(x.begin(), x.size()); } void clear() { clear_mem(buf, allocated); } void destroy() { create(0); } void create(u32bit); void grow_to(u32bit) const; void swap(MemoryRegion&); ~MemoryRegion() { deallocate(buf, allocated); } protected: MemoryRegion() { buf = 0; alloc = 0; used = allocated = 0; } MemoryRegion(const MemoryRegion& copy) { buf = 0; used = allocated = 0; alloc = copy.alloc; set(copy.buf, copy.used); } void init(bool locking, u32bit size = 0) { alloc = Allocator::get(locking); create(size); } private: T* allocate(u32bit n) const { return (T*)alloc->allocate(sizeof(T)*n); } void deallocate(T* p, u32bit n) const { alloc->deallocate(p, sizeof(T)*n); } mutable T* buf; mutable u32bit used; mutable u32bit allocated; mutable Allocator* alloc; }; /************************************************* * Create a new buffer * *************************************************/ template void MemoryRegion::create(u32bit n) { if(n <= allocated) { clear(); used = n; return; } deallocate(buf, allocated); buf = allocate(n); allocated = used = n; } /************************************************* * Increase the size of the buffer * *************************************************/ template void MemoryRegion::grow_to(u32bit n) const { if(n > used && n <= allocated) { clear_mem(buf + used, n - used); used = n; return; } else if(n > allocated) { T* new_buf = allocate(n); copy_mem(new_buf, buf, used); deallocate(buf, allocated); buf = new_buf; allocated = used = n; } } /************************************************* * Compare this buffer with another one * *************************************************/ template bool MemoryRegion::operator<(const MemoryRegion& in) const { if(size() < in.size()) return true; if(size() > in.size()) return false; for(u32bit j = 0; j != size(); j++) { if(buf[j] < in[j]) return true; if(buf[j] > in[j]) return false; } return false; } /************************************************* * Swap this buffer with another one * *************************************************/ template void MemoryRegion::swap(MemoryRegion& x) { std::swap(buf, x.buf); std::swap(used, x.used); std::swap(allocated, x.allocated); std::swap(alloc, x.alloc); } /************************************************* * Unlocked Variable Length Buffer * *************************************************/ template class MemoryVector : public MemoryRegion { public: MemoryVector& operator=(const MemoryRegion& in) { if(this != &in) set(in); return (*this); } MemoryVector(u32bit n = 0) { MemoryRegion::init(false, n); } MemoryVector(const T in[], u32bit n) { MemoryRegion::init(false); set(in, n); } MemoryVector(const MemoryRegion& in) { MemoryRegion::init(false); set(in); } MemoryVector(const MemoryRegion& in1, const MemoryRegion& in2) { MemoryRegion::init(false); set(in1); append(in2); } }; /************************************************* * Locked Variable Length Buffer * *************************************************/ template class SecureVector : public MemoryRegion { public: SecureVector& operator=(const MemoryRegion& in) { if(this != &in) set(in); return (*this); } SecureVector(u32bit n = 0) { MemoryRegion::init(true, n); } SecureVector(const T in[], u32bit n) { MemoryRegion::init(true); set(in, n); } SecureVector(const MemoryRegion& in) { MemoryRegion::init(true); set(in); } SecureVector(const MemoryRegion& in1, const MemoryRegion& in2) { MemoryRegion::init(true); set(in1); append(in2); } }; /************************************************* * Locked Fixed Length Buffer * *************************************************/ template class SecureBuffer : public MemoryRegion { public: SecureBuffer& operator=(const SecureBuffer& in) { if(this != &in) set(in); return (*this); } SecureBuffer() { MemoryRegion::init(true, L); } SecureBuffer(const T in[], u32bit n) { MemoryRegion::init(true, L); copy(in, n); } private: SecureBuffer& operator=(const MemoryRegion& in) { if(this != &in) set(in); return (*this); } }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/charset.h0000644000175000017500000000522011305557613023102 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Character Set Handling Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_CHARSET_H__ #define BOTAN_CHARSET_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Character Set Transcoder Interface * *************************************************/ #ifndef BOTAN_TOOLS_ONLY class Charset_Transcoder { public: virtual std::string transcode(const std::string&, Character_Set, Character_Set) const = 0; virtual ~Charset_Transcoder() {} }; #endif namespace Charset { /************************************************* * Character Set Handling * *************************************************/ #ifndef BOTAN_TOOLS_ONLY std::string transcode(const std::string&, Character_Set, Character_Set); #endif bool is_digit(char); bool is_space(char); bool caseless_cmp(char, char); byte char2digit(char); char digit2char(byte); } } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mp_types.h0000644000175000017500000000415111305557613023313 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Low Level MPI Types Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MPI_TYPES_H__ #define BOTAN_MPI_TYPES_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { #if (BOTAN_MP_WORD_BITS == 8) typedef byte word; #elif (BOTAN_MP_WORD_BITS == 16) typedef u16bit word; #elif (BOTAN_MP_WORD_BITS == 32) typedef u32bit word; #elif (BOTAN_MP_WORD_BITS == 64) typedef u64bit word; #else #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 #endif const word MP_WORD_MASK = ~((word)0); const word MP_WORD_TOP_BIT = (word)1 << (8*sizeof(word) - 1); const word MP_WORD_MAX = MP_WORD_MASK; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/stl_util.h0000644000175000017500000000746111305557613023321 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * STL Utility Functions Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_STL_UTIL_H__ #define BOTAN_STL_UTIL_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Copy-on-Predicate Algorithm * *************************************************/ template OutputIterator copy_if(InputIterator current, InputIterator end, OutputIterator dest, Predicate copy_p) { while(current != end) { if(copy_p(*current)) *dest++ = *current; ++current; } return dest; } /************************************************* * Searching through a std::map * *************************************************/ template inline V search_map(const std::map& mapping, const K& key, const V& null_result = V()) { typename std::map::const_iterator i = mapping.find(key); if(i == mapping.end()) return null_result; return i->second; } template inline R search_map(const std::map& mapping, const K& key, const R& null_result, const R& found_result) { typename std::map::const_iterator i = mapping.find(key); if(i == mapping.end()) return null_result; return found_result; } /************************************************* * Function adaptor for delete operation * *************************************************/ template class del_fun : public std::unary_function { public: void operator()(T* ptr) { delete ptr; } }; /************************************************* * Delete the second half of a pair of objects * *************************************************/ template void delete2nd(Pair& pair) { delete pair.second; } /************************************************* * Insert a key/value pair into a multimap * *************************************************/ template void multimap_insert(std::multimap& multimap, const K& key, const V& value) { multimap.insert(std::make_pair(key, value)); } } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/modules.h0000644000175000017500000000664511305557613023135 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Module Factory Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MODULE_FACTORIES_H__ #define BOTAN_MODULE_FACTORIES_H__ #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Module Builder Interface * *************************************************/ class Modules { public: virtual class Mutex_Factory* mutex_factory() const = 0; #ifndef BOTAN_TOOLS_ONLY virtual class Timer* timer() const = 0; virtual class Charset_Transcoder* transcoder() const = 0; #endif virtual std::string default_allocator() const = 0; virtual std::vector allocators() const = 0; #ifndef BOTAN_TOOLS_ONLY virtual std::vector entropy_sources() const = 0; virtual std::vector engines() const = 0; #endif virtual ~Modules() {} }; /************************************************* * Built In Modules * *************************************************/ class Builtin_Modules : public Modules { public: class Mutex_Factory* mutex_factory() const; #ifndef BOTAN_TOOLS_ONLY class Timer* timer() const; class Charset_Transcoder* transcoder() const; #endif std::string default_allocator() const; std::vector allocators() const; #ifndef BOTAN_TOOLS_ONLY std::vector entropy_sources() const; std::vector engines() const; #endif #ifdef BOTAN_TOOLS_ONLY Builtin_Modules(); #else Builtin_Modules(const InitializerOptions&); #endif private: #ifdef BOTAN_TOOLS_ONLY const bool should_lock; #else const bool should_lock, use_engines; #endif }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/bigint.h0000644000175000017500000001567411305557613022743 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * BigInt Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_BIGINT_H__ #define BOTAN_BIGINT_H__ #ifdef BOTAN_MINIMAL_BIGINT } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #else } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * BigInt * *************************************************/ class BigInt { public: enum Base { Octal = 8, Decimal = 10, Hexadecimal = 16, Binary = 256 }; enum Sign { Negative = 0, Positive = 1 }; enum NumberType { Random, Power2 }; struct DivideByZero : public Exception { DivideByZero() : Exception("BigInt divide by zero") {} }; BigInt& operator+=(const BigInt&); BigInt& operator-=(const BigInt&); BigInt& operator*=(const BigInt&); BigInt& operator/=(const BigInt&); BigInt& operator%=(const BigInt&); word operator%=(word); BigInt& operator<<=(u32bit); BigInt& operator>>=(u32bit); BigInt& operator++() { return (*this += 1); } BigInt& operator--() { return (*this -= 1); } BigInt operator++(int) { BigInt x = (*this); ++(*this); return x; } BigInt operator--(int) { BigInt x = (*this); --(*this); return x; } BigInt operator-() const; bool operator !() const { return (!is_nonzero()); } s32bit cmp(const BigInt&, bool = true) const; bool is_even() const { return (get_bit(0) == 0); } bool is_odd() const { return (get_bit(0) == 1); } bool is_nonzero() const { return (!is_zero()); } bool is_zero() const; void set_bit(u32bit); void clear_bit(u32bit); void mask_bits(u32bit); bool get_bit(u32bit) const; u32bit get_substring(u32bit, u32bit) const; byte byte_at(u32bit) const; word word_at(u32bit n) const { return ((n < size()) ? reg[n] : 0); } u32bit to_u32bit() const; bool is_negative() const { return (sign() == Negative); } bool is_positive() const { return (sign() == Positive); } Sign sign() const { return (signedness); } Sign reverse_sign() const; void flip_sign(); void set_sign(Sign); BigInt abs() const; u32bit size() const { return reg.size(); } u32bit sig_words() const; u32bit bytes() const; u32bit bits() const; const word* data() const { return reg.begin(); } SecureVector& get_reg() { return reg; } void grow_reg(u32bit) const; word& operator[](u32bit index) { return reg[index]; } word operator[](u32bit index) const { return reg[index]; } void clear() { reg.clear(); } #ifndef BOTAN_MINIMAL_BIGINT void randomize(u32bit = 0); #endif void binary_encode(byte[]) const; void binary_decode(const byte[], u32bit); u32bit encoded_size(Base = Binary) const; static SecureVector encode(const BigInt&, Base = Binary); static void encode(byte[], const BigInt&, Base = Binary); static BigInt decode(const byte[], u32bit, Base = Binary); static BigInt decode(const MemoryRegion&, Base = Binary); static SecureVector encode_1363(const BigInt&, u32bit); void swap(BigInt&); BigInt() { signedness = Positive; } BigInt(u64bit); BigInt(const BigInt&); BigInt(const std::string&); BigInt(const byte[], u32bit, Base = Binary); BigInt(Sign, u32bit); #ifndef BOTAN_MINIMAL_BIGINT BigInt(NumberType, u32bit); #endif private: void grow_to(u32bit) const; SecureVector reg; Sign signedness; }; /************************************************* * Arithmetic Operators * *************************************************/ BigInt operator+(const BigInt&, const BigInt&); BigInt operator-(const BigInt&, const BigInt&); BigInt operator*(const BigInt&, const BigInt&); BigInt operator/(const BigInt&, const BigInt&); BigInt operator%(const BigInt&, const BigInt&); word operator%(const BigInt&, word); BigInt operator<<(const BigInt&, u32bit); BigInt operator>>(const BigInt&, u32bit); /************************************************* * Comparison Operators * *************************************************/ inline bool operator==(const BigInt& a, const BigInt& b) { return (a.cmp(b) == 0); } inline bool operator!=(const BigInt& a, const BigInt& b) { return (a.cmp(b) != 0); } inline bool operator<=(const BigInt& a, const BigInt& b) { return (a.cmp(b) <= 0); } inline bool operator>=(const BigInt& a, const BigInt& b) { return (a.cmp(b) >= 0); } inline bool operator<(const BigInt& a, const BigInt& b) { return (a.cmp(b) < 0); } inline bool operator>(const BigInt& a, const BigInt& b) { return (a.cmp(b) > 0); } /************************************************* * I/O Operators * *************************************************/ #ifndef BOTAN_MINIMAL_BIGINT std::ostream& operator<<(std::ostream&, const BigInt&); std::istream& operator>>(std::istream&, BigInt&); #endif } #ifndef BOTAN_MINIMAL_BIGINT } // WRAPNS_LINE namespace std { inline void swap(Botan::BigInt& a, Botan::BigInt& b) { a.swap(b); } } namespace QCA { // WRAPNS_LINE #endif #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/bit_ops.h0000644000175000017500000000745211305557613023121 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Bit/Word Operations Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_BIT_OPS_H__ #define BOTAN_BIT_OPS_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Rotation Functions * *************************************************/ template inline T rotate_left(T input, u32bit rot) { return (T)((input << rot) | (input >> (8*sizeof(T)-rot))); } template inline T rotate_right(T input, u32bit rot) { return (T)((input >> rot) | (input << (8*sizeof(T)-rot))); } /************************************************* * Byte Extraction Function * *************************************************/ template inline byte get_byte(u32bit byte_num, T input) { return (byte)(input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3)); } /************************************************* * Byte to Word Conversions * *************************************************/ inline u16bit make_u16bit(byte input0, byte input1) { return (u16bit)(((u16bit)input0 << 8) | input1); } inline u32bit make_u32bit(byte input0, byte input1, byte input2, byte input3) { return (u32bit)(((u32bit)input0 << 24) | ((u32bit)input1 << 16) | ((u32bit)input2 << 8) | input3); } inline u64bit make_u64bit(byte input0, byte input1, byte input2, byte input3, byte input4, byte input5, byte input6, byte input7) { return (u64bit)(((u64bit)input0 << 56) | ((u64bit)input1 << 48) | ((u64bit)input2 << 40) | ((u64bit)input3 << 32) | ((u64bit)input4 << 24) | ((u64bit)input5 << 16) | ((u64bit)input6 << 8) | input7); } /************************************************* * XOR Functions * *************************************************/ void xor_buf(byte[], const byte[], u32bit); void xor_buf(byte[], const byte[], const byte[], u32bit); /************************************************* * Misc Utility Functions * *************************************************/ bool power_of_2(u64bit); u32bit high_bit(u64bit); u32bit low_bit(u64bit); u32bit significant_bytes(u64bit); u32bit hamming_weight(u64bit); } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mux_qt.h0000644000175000017500000000367011305557613022775 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Qt Mutex Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_EXT_MUTEX_QT_H__ #define BOTAN_EXT_MUTEX_QT_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Qt Mutex * *************************************************/ class Qt_Mutex_Factory : public Mutex_Factory { public: Mutex* make(); }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mutex.h0000644000175000017500000000610711305557613022620 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Mutex Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MUTEX_H__ #define BOTAN_MUTEX_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Mutex Base Class * *************************************************/ class Mutex { public: virtual void lock() = 0; virtual void unlock() = 0; virtual ~Mutex() {} }; /************************************************* * Mutex Factory * *************************************************/ class Mutex_Factory { public: virtual Mutex* make() = 0; virtual ~Mutex_Factory() {} }; /************************************************* * Default Mutex Factory * *************************************************/ class Default_Mutex_Factory : public Mutex_Factory { public: Mutex* make(); }; /************************************************* * Mutex Holding Class * *************************************************/ class Mutex_Holder { public: Mutex_Holder(Mutex*); ~Mutex_Holder(); private: Mutex* mux; }; /************************************************* * Named Mutex Holder * *************************************************/ #ifndef BOTAN_NO_LIBSTATE class Named_Mutex_Holder { public: Named_Mutex_Holder(const std::string&); ~Named_Mutex_Holder(); private: const std::string mutex_name; }; #endif } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/types.h0000644000175000017500000000464511305557613022627 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Low Level Types Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_TYPES_H__ #define BOTAN_TYPES_H__ #ifdef BOTAN_TYPES_QT } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #else } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif namespace Botan { #ifdef BOTAN_TYPES_QT typedef quint8 byte; typedef quint16 u16bit; typedef quint32 u32bit; typedef qint32 s32bit; typedef quint64 u64bit; #else typedef unsigned char byte; typedef unsigned short u16bit; typedef unsigned int u32bit; typedef signed int s32bit; #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 u64bit; #elif defined(__KCC) typedef unsigned __long_long u64bit; #elif defined(__GNUG__) __extension__ typedef unsigned long long u64bit; #else typedef unsigned long long u64bit; #endif #endif // BOTAN_TYPES_QT } namespace Botan_types { typedef Botan::byte byte; typedef Botan::u32bit u32bit; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mmap_mem.h0000644000175000017500000000421411305557613023243 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Memory Mapping Allocator Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_EXT_MMAP_ALLOCATOR_H__ #define BOTAN_EXT_MMAP_ALLOCATOR_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Memory Mapping Allocator * *************************************************/ class MemoryMapping_Allocator : public Pooling_Allocator { public: MemoryMapping_Allocator() : Pooling_Allocator(64*1024, false) {} std::string type() const { return "mmap"; } private: void* alloc_block(u32bit); void dealloc_block(void*, u32bit); }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mp_asm.h0000644000175000017500000000527111305557613022733 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Lowest Level MPI Algorithms Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MP_ASM_H__ #define BOTAN_MP_ASM_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #if (BOTAN_MP_WORD_BITS == 8) typedef Botan::u16bit dword; #elif (BOTAN_MP_WORD_BITS == 16) typedef Botan::u32bit dword; #elif (BOTAN_MP_WORD_BITS == 32) typedef Botan::u64bit dword; #elif (BOTAN_MP_WORD_BITS == 64) #error BOTAN_MP_WORD_BITS can be 64 only with assembly support #else #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 #endif namespace Botan { extern "C" { /************************************************* * Word Multiply/Add * *************************************************/ inline word word_madd2(word a, word b, word c, word* carry) { dword z = (dword)a * b + c; *carry = (word)(z >> BOTAN_MP_WORD_BITS); return (word)z; } /************************************************* * Word Multiply/Add * *************************************************/ inline word word_madd3(word a, word b, word c, word d, word* carry) { dword z = (dword)a * b + c + d; *carry = (word)(z >> BOTAN_MP_WORD_BITS); return (word)z; } } } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mp_asmi.h0000644000175000017500000001642611305557613023110 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Lowest Level MPI Algorithms Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MP_ASM_INTERNAL_H__ #define BOTAN_MP_ASM_INTERNAL_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { extern "C" { /************************************************* * Word Addition * *************************************************/ inline word word_add(word x, word y, word* carry) { word z = x + y; word c1 = (z < x); z += *carry; *carry = c1 | (z < *carry); return z; } /************************************************* * Eight Word Block Addition, Two Argument * *************************************************/ inline word word8_add2(word x[8], const word y[8], word carry) { x[0] = word_add(x[0], y[0], &carry); x[1] = word_add(x[1], y[1], &carry); x[2] = word_add(x[2], y[2], &carry); x[3] = word_add(x[3], y[3], &carry); x[4] = word_add(x[4], y[4], &carry); x[5] = word_add(x[5], y[5], &carry); x[6] = word_add(x[6], y[6], &carry); x[7] = word_add(x[7], y[7], &carry); return carry; } /************************************************* * Eight Word Block Addition, Three Argument * *************************************************/ inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) { z[0] = word_add(x[0], y[0], &carry); z[1] = word_add(x[1], y[1], &carry); z[2] = word_add(x[2], y[2], &carry); z[3] = word_add(x[3], y[3], &carry); z[4] = word_add(x[4], y[4], &carry); z[5] = word_add(x[5], y[5], &carry); z[6] = word_add(x[6], y[6], &carry); z[7] = word_add(x[7], y[7], &carry); return carry; } /************************************************* * Word Subtraction * *************************************************/ inline word word_sub(word x, word y, word* carry) { word t0 = x - y; word c1 = (t0 > x); word z = t0 - *carry; *carry = c1 | (z > t0); return z; } /************************************************* * Eight Word Block Subtraction, Two Argument * *************************************************/ inline word word8_sub2(word x[4], const word y[4], word carry) { x[0] = word_sub(x[0], y[0], &carry); x[1] = word_sub(x[1], y[1], &carry); x[2] = word_sub(x[2], y[2], &carry); x[3] = word_sub(x[3], y[3], &carry); x[4] = word_sub(x[4], y[4], &carry); x[5] = word_sub(x[5], y[5], &carry); x[6] = word_sub(x[6], y[6], &carry); x[7] = word_sub(x[7], y[7], &carry); return carry; } /************************************************* * Eight Word Block Subtraction, Three Argument * *************************************************/ inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry) { z[0] = word_sub(x[0], y[0], &carry); z[1] = word_sub(x[1], y[1], &carry); z[2] = word_sub(x[2], y[2], &carry); z[3] = word_sub(x[3], y[3], &carry); z[4] = word_sub(x[4], y[4], &carry); z[5] = word_sub(x[5], y[5], &carry); z[6] = word_sub(x[6], y[6], &carry); z[7] = word_sub(x[7], y[7], &carry); return carry; } /************************************************* * Eight Word Block Linear Multiplication * *************************************************/ inline word word8_linmul2(word x[4], word y, word carry) { x[0] = word_madd2(x[0], y, carry, &carry); x[1] = word_madd2(x[1], y, carry, &carry); x[2] = word_madd2(x[2], y, carry, &carry); x[3] = word_madd2(x[3], y, carry, &carry); x[4] = word_madd2(x[4], y, carry, &carry); x[5] = word_madd2(x[5], y, carry, &carry); x[6] = word_madd2(x[6], y, carry, &carry); x[7] = word_madd2(x[7], y, carry, &carry); return carry; } /************************************************* * Eight Word Block Linear Multiplication * *************************************************/ inline word word8_linmul3(word z[8], const word x[8], word y, word carry) { z[0] = word_madd2(x[0], y, carry, &carry); z[1] = word_madd2(x[1], y, carry, &carry); z[2] = word_madd2(x[2], y, carry, &carry); z[3] = word_madd2(x[3], y, carry, &carry); z[4] = word_madd2(x[4], y, carry, &carry); z[5] = word_madd2(x[5], y, carry, &carry); z[6] = word_madd2(x[6], y, carry, &carry); z[7] = word_madd2(x[7], y, carry, &carry); return carry; } /************************************************* * Eight Word Block Multiply/Add * *************************************************/ inline word word8_madd3(word z[8], const word x[8], word y, word carry) { z[0] = word_madd3(x[0], y, z[0], carry, &carry); z[1] = word_madd3(x[1], y, z[1], carry, &carry); z[2] = word_madd3(x[2], y, z[2], carry, &carry); z[3] = word_madd3(x[3], y, z[3], carry, &carry); z[4] = word_madd3(x[4], y, z[4], carry, &carry); z[5] = word_madd3(x[5], y, z[5], carry, &carry); z[6] = word_madd3(x[6], y, z[6], carry, &carry); z[7] = word_madd3(x[7], y, z[7], carry, &carry); return carry; } /************************************************* * Multiply-Add Accumulator * *************************************************/ inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b) { *w0 = word_madd2(a, b, *w0, &b); *w1 += b; *w2 += (*w1 < b) ? 1 : 0; } /************************************************* * Multiply-Add Accumulator * *************************************************/ inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b) { a = word_madd2(a, b, 0, &b); word top = (b >> (BOTAN_MP_WORD_BITS-1)); b <<= 1; b |= (a >> (BOTAN_MP_WORD_BITS-1)); a <<= 1; word carry = 0; *w0 = word_add(*w0, a, &carry); *w1 = word_add(*w1, b, &carry); *w2 = word_add(*w2, top, &carry); } } } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/numthry.h0000644000175000017500000001103011305557613023153 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Number Theory Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_NUMBTHRY_H__ #define BOTAN_NUMBTHRY_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_MINIMAL_BIGINT } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif namespace Botan { #ifndef BOTAN_MINIMAL_BIGINT /************************************************* * Fused Arithmetic Operations * *************************************************/ BigInt mul_add(const BigInt&, const BigInt&, const BigInt&); BigInt sub_mul(const BigInt&, const BigInt&, const BigInt&); /************************************************* * Number Theory Functions * *************************************************/ inline BigInt abs(const BigInt& n) { return n.abs(); } #endif void divide(const BigInt&, const BigInt&, BigInt&, BigInt&); #ifndef BOTAN_MINIMAL_BIGINT BigInt gcd(const BigInt&, const BigInt&); BigInt lcm(const BigInt&, const BigInt&); BigInt square(const BigInt&); BigInt inverse_mod(const BigInt&, const BigInt&); s32bit jacobi(const BigInt&, const BigInt&); BigInt power_mod(const BigInt&, const BigInt&, const BigInt&); /************************************************* * Utility Functions * *************************************************/ u32bit low_zero_bits(const BigInt&); /************************************************* * Primality Testing * *************************************************/ bool check_prime(const BigInt&); bool is_prime(const BigInt&); bool verify_prime(const BigInt&); s32bit simple_primality_tests(const BigInt&); bool passes_mr_tests(const BigInt&, u32bit = 1); bool run_primality_tests(const BigInt&, u32bit = 1); /************************************************* * Random Number Generation * *************************************************/ BigInt random_integer(u32bit); BigInt random_integer(const BigInt&, const BigInt&); BigInt random_prime(u32bit, const BigInt& = 1, u32bit = 1, u32bit = 2); BigInt random_safe_prime(u32bit); SecureVector generate_dsa_primes(BigInt&, BigInt&, u32bit); bool generate_dsa_primes(BigInt&, BigInt&, const byte[], u32bit, u32bit, u32bit = 0); /************************************************* * Prime Numbers * *************************************************/ const u32bit PRIME_TABLE_SIZE = 6541; const u32bit PRIME_PRODUCTS_TABLE_SIZE = 256; extern const u16bit PRIMES[]; extern const u64bit PRIME_PRODUCTS[]; /************************************************* * Miller-Rabin Primality Tester * *************************************************/ class MillerRabin_Test { public: bool passes_test(const BigInt&); MillerRabin_Test(const BigInt&); private: BigInt n, r, n_minus_1; u32bit s; Fixed_Exponent_Power_Mod pow_mod; Modular_Reducer reducer; }; #endif } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/parsing.h0000644000175000017500000000503511305557613023120 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Parser Functions Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_PARSER_H__ #define BOTAN_PARSER_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * String Parsing Functions * *************************************************/ #ifndef BOTAN_TOOLS_ONLY std::vector parse_algorithm_name(const std::string&); std::vector split_on(const std::string&, char); std::vector parse_asn1_oid(const std::string&); bool x500_name_cmp(const std::string&, const std::string&); u32bit parse_expr(const std::string&); #endif /************************************************* * String/Integer Conversions * *************************************************/ std::string to_string(u64bit, u32bit = 0); #ifndef BOTAN_TOOLS_ONLY u32bit to_u32bit(const std::string&); #endif } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mp_core.h0000644000175000017500000001120311305557613023073 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * MPI Algorithms Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_MP_CORE_H__ #define BOTAN_MP_CORE_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * The size of the word type, in bits * *************************************************/ const u32bit MP_WORD_BITS = BOTAN_MP_WORD_BITS; extern "C" { /************************************************* * Addition/Subtraction Operations * *************************************************/ void bigint_add2(word[], u32bit, const word[], u32bit); void bigint_add3(word[], const word[], u32bit, const word[], u32bit); word bigint_add2_nc(word[], u32bit, const word[], u32bit); word bigint_add3_nc(word[], const word[], u32bit, const word[], u32bit); void bigint_sub2(word[], u32bit, const word[], u32bit); void bigint_sub3(word[], const word[], u32bit, const word[], u32bit); /************************************************* * Shift Operations * *************************************************/ void bigint_shl1(word[], u32bit, u32bit, u32bit); void bigint_shl2(word[], const word[], u32bit, u32bit, u32bit); void bigint_shr1(word[], u32bit, u32bit, u32bit); void bigint_shr2(word[], const word[], u32bit, u32bit, u32bit); /************************************************* * Multiplication and Squaring Operations * *************************************************/ word bigint_mul_add_words(word[], const word[], u32bit, word); void bigint_linmul2(word[], u32bit, word); void bigint_linmul3(word[], const word[], u32bit, word); void bigint_linmul_add(word[], u32bit, const word[], u32bit, word); /************************************************* * Montgomery Reduction * *************************************************/ void bigint_monty_redc(word[], u32bit, const word[], u32bit, word); /************************************************* * Misc Utility Operations * *************************************************/ u32bit bigint_divcore(word, word, word, word, word, word); s32bit bigint_cmp(const word[], u32bit, const word[], u32bit); word bigint_divop(word, word, word); word bigint_modop(word, word, word); void bigint_wordmul(word, word, word*, word*); /************************************************* * Comba Multiplication / Squaring * *************************************************/ void bigint_comba_mul4(word[8], const word[4], const word[4]); void bigint_comba_mul6(word[12], const word[6], const word[6]); void bigint_comba_mul8(word[16], const word[8], const word[8]); void bigint_comba_sqr4(word[8], const word[4]); void bigint_comba_sqr6(word[12], const word[6]); void bigint_comba_sqr8(word[16], const word[8]); } /************************************************* * High Level Multiplication/Squaring Interfaces * *************************************************/ void bigint_mul(word[], u32bit, word[], const word[], u32bit, u32bit, const word[], u32bit, u32bit); void bigint_sqr(word[], u32bit, word[], const word[], u32bit, u32bit); } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/allocate.h0000644000175000017500000000454511305557613023246 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Allocator Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_ALLOCATOR_H__ #define BOTAN_ALLOCATOR_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Allocator * *************************************************/ class Allocator { public: static Allocator* get(bool); virtual void* allocate(u32bit) = 0; virtual void deallocate(void*, u32bit) = 0; virtual std::string type() const = 0; virtual void init() {} virtual void destroy() {} virtual ~Allocator() {} }; /************************************************* * Get an allocator * *************************************************/ } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/exceptn.h0000644000175000017500000002033111305557613023117 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Exceptions Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_EXCEPTION_H__ #define BOTAN_EXCEPTION_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Exception Base Class * *************************************************/ class Exception : public std::exception { public: const char* what() const throw() { return msg.c_str(); } Exception(const std::string& m = "Unknown error") { set_msg(m); } virtual ~Exception() throw() {} protected: void set_msg(const std::string& m) { msg = "Botan: " + m; } private: std::string msg; }; /************************************************* * Invalid_Argument Exception * *************************************************/ struct Invalid_Argument : public Exception { Invalid_Argument(const std::string& err = "") : Exception(err) {} }; /************************************************* * Invalid_Key_Length Exception * *************************************************/ struct Invalid_Key_Length : public Invalid_Argument { Invalid_Key_Length(const std::string&, u32bit); }; /************************************************* * Invalid_Block_Size Exception * *************************************************/ struct Invalid_Block_Size : public Invalid_Argument { Invalid_Block_Size(const std::string&, const std::string&); }; /************************************************* * Invalid_IV_Length Exception * *************************************************/ struct Invalid_IV_Length : public Invalid_Argument { Invalid_IV_Length(const std::string&, u32bit); }; /************************************************* * Invalid_Message_Number Exception * *************************************************/ struct Invalid_Message_Number : public Invalid_Argument { Invalid_Message_Number(const std::string&, u32bit); }; /************************************************* * Invalid_State Exception * *************************************************/ struct Invalid_State : public Exception { Invalid_State(const std::string& err) : Exception(err) {} }; /************************************************* * PRNG_Unseeded Exception * *************************************************/ struct PRNG_Unseeded : public Invalid_State { PRNG_Unseeded(const std::string& algo) : Invalid_State("PRNG not seeded: " + algo) {} }; /************************************************* * Policy_Violation Exception * *************************************************/ struct Policy_Violation : public Invalid_State { Policy_Violation(const std::string& err) : Invalid_State("Policy violation: " + err) {} }; /************************************************* * Lookup_Error Exception * *************************************************/ struct Lookup_Error : public Exception { Lookup_Error(const std::string& err) : Exception(err) {} }; /************************************************* * Algorithm_Not_Found Exception * *************************************************/ struct Algorithm_Not_Found : public Exception { Algorithm_Not_Found(const std::string&); }; /************************************************* * Format_Error Exception * *************************************************/ struct Format_Error : public Exception { Format_Error(const std::string& err = "") : Exception(err) {} }; /************************************************* * Invalid_Algorithm_Name Exception * *************************************************/ struct Invalid_Algorithm_Name : public Format_Error { Invalid_Algorithm_Name(const std::string&); }; /************************************************* * Encoding_Error Exception * *************************************************/ struct Encoding_Error : public Format_Error { Encoding_Error(const std::string& name) : Format_Error("Encoding error: " + name) {} }; /************************************************* * Decoding_Error Exception * *************************************************/ struct Decoding_Error : public Format_Error { Decoding_Error(const std::string& name) : Format_Error("Decoding error: " + name) {} }; /************************************************* * Invalid_OID Exception * *************************************************/ struct Invalid_OID : public Decoding_Error { Invalid_OID(const std::string& oid) : Decoding_Error("Invalid ASN.1 OID: " + oid) {} }; /************************************************* * Stream_IO_Error Exception * *************************************************/ struct Stream_IO_Error : public Exception { Stream_IO_Error(const std::string& err) : Exception("I/O error: " + err) {} }; /************************************************* * Configuration Error Exception * *************************************************/ struct Config_Error : public Format_Error { Config_Error(const std::string& err) : Format_Error("Config error: " + err) {} Config_Error(const std::string&, u32bit); }; /************************************************* * Integrity Failure Exception * *************************************************/ struct Integrity_Failure : public Exception { Integrity_Failure(const std::string& err) : Exception("Integrity failure: " + err) {} }; /************************************************* * Internal_Error Exception * *************************************************/ struct Internal_Error : public Exception { Internal_Error(const std::string& err) : Exception("Internal error: " + err) {} }; /************************************************* * Self Test Failure Exception * *************************************************/ struct Self_Test_Failure : public Internal_Error { Self_Test_Failure(const std::string& err) : Internal_Error("Self test failed: " + err) {} }; /************************************************* * Memory Allocation Exception * *************************************************/ struct Memory_Exhaustion : public Exception { Memory_Exhaustion() : Exception("Ran out of memory, allocation failed") {} }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/util.h0000644000175000017500000000525111305557613022432 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Utility Functions Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_UTIL_H__ #define BOTAN_UTIL_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Timer Access Functions * *************************************************/ #ifndef BOTAN_TOOLS_ONLY u64bit system_time(); u64bit system_clock(); #endif /************************************************* * Memory Locking Functions * *************************************************/ void lock_mem(void*, u32bit); void unlock_mem(void*, u32bit); /************************************************* * Misc Utility Functions * *************************************************/ u32bit round_up(u32bit, u32bit); u32bit round_down(u32bit, u32bit); #ifndef BOTAN_TOOLS_ONLY u64bit combine_timers(u32bit, u32bit, u32bit); #endif /************************************************* * Work Factor Estimates * *************************************************/ #ifndef BOTAN_TOOLS_ONLY u32bit entropy_estimate(const byte[], u32bit); u32bit dl_work_factor(u32bit); #endif } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/defalloc.h0000644000175000017500000000503711305557613023230 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Basic Allocators Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_BASIC_ALLOC_H__ #define BOTAN_BASIC_ALLOC_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Malloc Allocator * *************************************************/ class Malloc_Allocator : public Pooling_Allocator { public: Malloc_Allocator() : Pooling_Allocator(64*1024, false) {} std::string type() const { return "malloc"; } private: void* alloc_block(u32bit); void dealloc_block(void*, u32bit); }; /************************************************* * Locking Allocator * *************************************************/ class Locking_Allocator : public Pooling_Allocator { public: Locking_Allocator() : Pooling_Allocator(64*1024, true) {} std::string type() const { return "locking"; } private: void* alloc_block(u32bit); void dealloc_block(void*, u32bit); }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/mem_pool.h0000644000175000017500000000704611305557613023270 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Pooling Allocator Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_POOLING_ALLOCATOR_H__ #define BOTAN_POOLING_ALLOCATOR_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Pooling Allocator * *************************************************/ class Pooling_Allocator : public Allocator { public: void* allocate(u32bit); void deallocate(void*, u32bit); void destroy(); Pooling_Allocator(u32bit, bool); ~Pooling_Allocator(); private: void get_more_core(u32bit); byte* allocate_blocks(u32bit); virtual void* alloc_block(u32bit) = 0; virtual void dealloc_block(void*, u32bit) = 0; class Memory_Block { public: Memory_Block(void*); static u32bit bitmap_size() { return BITMAP_SIZE; } static u32bit block_size() { return BLOCK_SIZE; } bool contains(void*, u32bit) const throw(); byte* alloc(u32bit) throw(); void free(void*, u32bit) throw(); bool operator<(const Memory_Block& other) const { if(buffer < other.buffer && other.buffer < buffer_end) return false; return (buffer < other.buffer); } private: typedef u64bit bitmap_type; static const u32bit BITMAP_SIZE; static const u32bit BLOCK_SIZE; bitmap_type bitmap; byte* buffer, *buffer_end; }; const u32bit PREF_SIZE; std::vector blocks; std::vector::iterator last_used; std::vector > allocated; Mutex* mutex; }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/botan/libstate.h0000644000175000017500000001241611305557613023265 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Library Internal/Global State Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_LIB_STATE_H__ #define BOTAN_LIB_STATE_H__ #ifdef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #else } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Global State Container Base * *************************************************/ class Library_State { public: #ifndef BOTAN_TOOLS_ONLY class Engine_Iterator { public: class Engine* next(); Engine_Iterator(const Library_State& l) : lib(l) { n = 0; } private: const Library_State& lib; u32bit n; }; friend class Engine_Iterator; class UI { public: virtual void pulse(Pulse_Type) {} virtual ~UI() {} }; #endif int prealloc_size; Allocator* get_allocator(const std::string& = "") const; void add_allocator(Allocator*); #ifdef BOTAN_TOOLS_ONLY void set_default_allocator(const std::string&); #else void set_default_allocator(const std::string&) const; #endif #ifndef BOTAN_TOOLS_ONLY bool rng_is_seeded() const { return rng->is_seeded(); } void randomize(byte[], u32bit); void set_prng(RandomNumberGenerator*); void add_entropy_source(EntropySource*, bool = true); void add_entropy(const byte[], u32bit); void add_entropy(EntropySource&, bool); u32bit seed_prng(bool, u32bit); #endif void load(class Modules&); #ifndef BOTAN_TOOLS_ONLY void set_timer(class Timer*); u64bit system_clock() const; class Config& config() const; void add_engine(class Engine*); #endif class Mutex* get_mutex() const; class Mutex* get_named_mutex(const std::string&); #ifndef BOTAN_TOOLS_ONLY void set_x509_state(class X509_GlobalState*); class X509_GlobalState& x509_state(); void pulse(Pulse_Type) const; void set_ui(UI*); void set_transcoder(class Charset_Transcoder*); std::string transcode(const std::string, Character_Set, Character_Set) const; #endif Library_State(class Mutex_Factory*); ~Library_State(); private: Library_State(const Library_State&) {} Library_State& operator=(const Library_State&) { return (*this); } #ifndef BOTAN_TOOLS_ONLY class Engine* get_engine_n(u32bit) const; #endif class Mutex_Factory* mutex_factory; #ifndef BOTAN_TOOLS_ONLY class Timer* timer; class Config* config_obj; class X509_GlobalState* x509_state_obj; #endif std::map locks; std::map alloc_factory; mutable Allocator* cached_default_allocator; #ifdef BOTAN_TOOLS_ONLY std::string default_allocator_type; #endif #ifndef BOTAN_TOOLS_ONLY UI* ui; class Charset_Transcoder* transcoder; RandomNumberGenerator* rng; #endif std::vector allocators; #ifndef BOTAN_TOOLS_ONLY std::vector entropy_sources; std::vector engines; #endif }; /************************************************* * Global State * *************************************************/ Library_State& global_state(); void set_global_state(Library_State*); Library_State* swap_global_state(Library_State*); } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/divide.cpp0000644000175000017500000000762011305557613022153 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Division Algorithm Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { namespace { /************************************************* * Handle signed operands, if necessary * *************************************************/ void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) { if(x.sign() == BigInt::Negative) { q.flip_sign(); if(r.is_nonzero()) { --q; r = y.abs() - r; } } if(y.sign() == BigInt::Negative) q.flip_sign(); } } /************************************************* * Solve x = q * y + r * *************************************************/ void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r) { if(y_arg.is_zero()) throw BigInt::DivideByZero(); BigInt y = y_arg; const u32bit y_words = y.sig_words(); r = x; r.set_sign(BigInt::Positive); y.set_sign(BigInt::Positive); s32bit compare = r.cmp(y); if(compare < 0) q = 0; else if(compare == 0) { q = 1; r = 0; } else { u32bit shifts = 0; word y_top = y[y.sig_words()-1]; while(y_top < MP_WORD_TOP_BIT) { y_top <<= 1; ++shifts; } y <<= shifts; r <<= shifts; const u32bit n = r.sig_words() - 1, t = y_words - 1; q.get_reg().create(n - t + 1); if(n <= t) { while(r > y) { r -= y; q++; } r >>= shifts; sign_fixup(x, y_arg, q, r); return; } BigInt temp = y << (MP_WORD_BITS * (n-t)); while(r >= temp) { r -= temp; ++q[n-t]; } for(u32bit j = n; j != t; --j) { const word x_j0 = r.word_at(j); const word x_j1 = r.word_at(j-1); const word y_t = y.word_at(t); if(x_j0 == y_t) q[j-t-1] = MP_WORD_MAX; else q[j-t-1] = bigint_divop(x_j0, x_j1, y_t); while(bigint_divcore(q[j-t-1], y_t, y.word_at(t-1), x_j0, x_j1, r.word_at(j-2))) --q[j-t-1]; r -= (q[j-t-1] * y) << (MP_WORD_BITS * (j-t-1)); if(r.is_negative()) { r += y << (MP_WORD_BITS * (j-t-1)); --q[j-t-1]; } } r >>= shifts; } sign_fixup(x, y_arg, q, r); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/alloc_mmap/0000755000175000017500000000000011305557613022302 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/botan/alloc_mmap/mmap_mem.cpp0000644000175000017500000001220211305557613024573 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Memory Mapping Allocator Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED 1 #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef MAP_FAILED #define MAP_FAILED -1 #endif namespace Botan { namespace { /************************************************* * MemoryMapping_Allocator Exception * *************************************************/ class MemoryMapping_Failed : public Exception { public: MemoryMapping_Failed(const std::string& msg) : Exception("MemoryMapping_Allocator: " + msg) {} }; } /************************************************* * Memory Map a File into Memory * *************************************************/ void* MemoryMapping_Allocator::alloc_block(u32bit n) { class TemporaryFile { public: int get_fd() const { return fd; } const std::string path() const { return filepath; } TemporaryFile(const std::string& base) { const std::string path = base + "XXXXXX"; filepath = new char[path.length() + 1]; std::strcpy(filepath, path.c_str()); mode_t old_umask = umask(077); fd = mkstemp(filepath); umask(old_umask); } ~TemporaryFile() { delete[] filepath; if(fd != -1 && close(fd) == -1) throw MemoryMapping_Failed("Could not close file"); } private: int fd; char* filepath; }; TemporaryFile file("/tmp/botan_"); if(file.get_fd() == -1) throw MemoryMapping_Failed("Could not create file"); if(unlink(file.path().c_str())) throw MemoryMapping_Failed("Could not unlink file " + file.path()); lseek(file.get_fd(), n-1, SEEK_SET); if(write(file.get_fd(), "\0", 1) != 1) throw MemoryMapping_Failed("Could not write to file"); void* ptr = mmap(0, n, PROT_READ | PROT_WRITE, MAP_SHARED, file.get_fd(), 0); if(ptr == (void*)MAP_FAILED) throw MemoryMapping_Failed("Could not map file"); return ptr; } /************************************************* * Remove a Memory Mapping * *************************************************/ void MemoryMapping_Allocator::dealloc_block(void* ptr, u32bit n) { if(ptr == 0) return; #ifdef MLOCK_NOT_VOID_PTR # define MLOCK_TYPE_CAST (char *) #else # define MLOCK_TYPE_CAST #endif const u32bit OVERWRITE_PASSES = 12; const byte PATTERNS[] = { 0x00, 0xFF, 0xAA, 0x55, 0x73, 0x8C, 0x5F, 0xA0, 0x6E, 0x91, 0x30, 0xCF, 0xD3, 0x2C, 0xAC, 0x53 }; for(u32bit j = 0; j != OVERWRITE_PASSES; j++) { std::memset(ptr, PATTERNS[j % sizeof(PATTERNS)], n); if(msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) throw MemoryMapping_Failed("Sync operation failed"); } std::memset(ptr, 0, n); if(msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) throw MemoryMapping_Failed("Sync operation failed"); if(munmap(MLOCK_TYPE_CAST ptr, n)) throw MemoryMapping_Failed("Could not unmap file"); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/alloc_mmap/mmap_mem.h0000644000175000017500000000421411305557613024244 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Memory Mapping Allocator Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_EXT_MMAP_ALLOCATOR_H__ #define BOTAN_EXT_MMAP_ALLOCATOR_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Memory Mapping Allocator * *************************************************/ class MemoryMapping_Allocator : public Pooling_Allocator { public: MemoryMapping_Allocator() : Pooling_Allocator(64*1024, false) {} std::string type() const { return "mmap"; } private: void* alloc_block(u32bit); void dealloc_block(void*, u32bit); }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/big_ops2.cpp0000644000175000017500000001702311305557613022411 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * BigInt Assignment Operators Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Addition Operator * *************************************************/ BigInt& BigInt::operator+=(const BigInt& y) { const u32bit x_sw = sig_words(), y_sw = y.sig_words(); #ifdef BOTAN_TYPES_QT const u32bit reg_size = qMax(x_sw, y_sw) + 1; #else const u32bit reg_size = std::max(x_sw, y_sw) + 1; #endif grow_to(reg_size); if((sign() == y.sign())) bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); else { s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); if(relative_size < 0) { SecureVector z(reg_size - 1); bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); copy_mem(reg.begin(), z.begin(), z.size()); set_sign(y.sign()); } else if(relative_size == 0) { reg.clear(); set_sign(Positive); } else if(relative_size > 0) bigint_sub2(get_reg(), x_sw, y.data(), y_sw); } return (*this); } /************************************************* * Subtraction Operator * *************************************************/ BigInt& BigInt::operator-=(const BigInt& y) { const u32bit x_sw = sig_words(), y_sw = y.sig_words(); s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); #ifdef BOTAN_TYPES_QT const u32bit reg_size = qMax(x_sw, y_sw) + 1; #else const u32bit reg_size = std::max(x_sw, y_sw) + 1; #endif grow_to(reg_size); if(relative_size < 0) { if(sign() == y.sign()) { SecureVector z(reg_size - 1); bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); copy_mem(reg.begin(), z.begin(), z.size()); } else bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); set_sign(y.reverse_sign()); } else if(relative_size == 0) { if(sign() == y.sign()) { reg.clear(); set_sign(Positive); } else bigint_shl1(get_reg(), x_sw, 0, 1); } else if(relative_size > 0) { if(sign() == y.sign()) bigint_sub2(get_reg(), x_sw, y.data(), y_sw); else bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); } return (*this); } /************************************************* * Multiplication Operator * *************************************************/ BigInt& BigInt::operator*=(const BigInt& y) { const u32bit x_sw = sig_words(), y_sw = y.sig_words(); set_sign((sign() == y.sign()) ? Positive : Negative); if(x_sw == 0 || y_sw == 0) { reg.clear(); set_sign(Positive); } else if(x_sw == 1 && y_sw) { grow_to(y_sw + 2); bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0)); } else if(y_sw == 1 && x_sw) { grow_to(x_sw + 2); bigint_linmul2(get_reg(), x_sw, y.word_at(0)); } else { grow_to(size() + y.size()); SecureVector z(data(), x_sw); SecureVector workspace(size()); bigint_mul(get_reg(), size(), workspace, z, z.size(), x_sw, y.data(), y.size(), y_sw); } return (*this); } /************************************************* * Division Operator * *************************************************/ BigInt& BigInt::operator/=(const BigInt& y) { if(y.sig_words() == 1 && power_of_2(y.word_at(0))) (*this) >>= (y.bits() - 1); else (*this) = (*this) / y; return (*this); } /************************************************* * Modulo Operator * *************************************************/ BigInt& BigInt::operator%=(const BigInt& mod) { return (*this = (*this) % mod); } /************************************************* * Modulo Operator * *************************************************/ word BigInt::operator%=(word mod) { if(mod == 0) throw BigInt::DivideByZero(); if(power_of_2(mod)) { word result = (word_at(0) & (mod - 1)); clear(); grow_to(2); reg[0] = result; return result; } word remainder = 0; for(u32bit j = sig_words(); j > 0; --j) remainder = bigint_modop(remainder, word_at(j-1), mod); clear(); grow_to(2); if(remainder && sign() == BigInt::Negative) reg[0] = mod - remainder; else reg[0] = remainder; set_sign(BigInt::Positive); return word_at(0); } /************************************************* * Left Shift Operator * *************************************************/ BigInt& BigInt::operator<<=(u32bit shift) { if(shift) { const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS, words = sig_words(); grow_to(words + shift_words + (shift_bits ? 1 : 0)); bigint_shl1(get_reg(), words, shift_words, shift_bits); } return (*this); } /************************************************* * Right Shift Operator * *************************************************/ BigInt& BigInt::operator>>=(u32bit shift) { if(shift) { const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS; bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits); if(is_zero()) set_sign(Positive); } return (*this); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/big_io.cpp0000644000175000017500000000577111305557613022144 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * BigInt Input/Output Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { #ifndef BOTAN_MINIMAL_BIGINT /************************************************* * Write the BigInt into a stream * *************************************************/ std::ostream& operator<<(std::ostream& stream, const BigInt& n) { BigInt::Base base = BigInt::Decimal; if(stream.flags() & std::ios::hex) base = BigInt::Hexadecimal; else if(stream.flags() & std::ios::oct) base = BigInt::Octal; if(n == 0) stream.write("0", 1); else { if(n < 0) stream.write("-", 1); SecureVector buffer = BigInt::encode(n, base); u32bit skip = 0; while(buffer[skip] == '0' && skip < buffer.size()) ++skip; stream.write((const char*)buffer.begin() + skip, buffer.size() - skip); } if(!stream.good()) throw Stream_IO_Error("BigInt output operator has failed"); return stream; } /************************************************* * Read the BigInt from a stream * *************************************************/ std::istream& operator>>(std::istream& stream, BigInt& n) { std::string str; std::getline(stream, str); if(stream.bad() || (stream.fail() && !stream.eof())) throw Stream_IO_Error("BigInt input operator has failed"); n = BigInt(str); return stream; } #endif } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mp_mul.cpp0000644000175000017500000001462011305557613022176 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Karatsuba Multiplication Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { namespace { /************************************************* * Simple O(N^2) Multiplication * *************************************************/ void bigint_simple_mul(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) { clear_mem(z, x_size + y_size); for(u32bit j = 0; j != x_size; ++j) z[j+y_size] = bigint_mul_add_words(z + j, y, y_size, x[j]); } /************************************************* * Karatsuba Multiplication Operation * *************************************************/ void karatsuba_mul(word z[], const word x[], const word y[], u32bit N, word workspace[]) { const u32bit KARATSUBA_MUL_LOWER_SIZE = BOTAN_KARAT_MUL_THRESHOLD; if(N == 6) bigint_comba_mul6(z, x, y); else if(N == 8) bigint_comba_mul8(z, x, y); else if(N < KARATSUBA_MUL_LOWER_SIZE || N % 2) bigint_simple_mul(z, x, N, y, N); else { const u32bit N2 = N / 2; const word* x0 = x; const word* x1 = x + N2; const word* y0 = y; const word* y1 = y + N2; word* z0 = z; word* z1 = z + N; const s32bit cmp0 = bigint_cmp(x0, N2, x1, N2); const s32bit cmp1 = bigint_cmp(y1, N2, y0, N2); clear_mem(workspace, 2*N); if(cmp0 && cmp1) { if(cmp0 > 0) bigint_sub3(z0, x0, N2, x1, N2); else bigint_sub3(z0, x1, N2, x0, N2); if(cmp1 > 0) bigint_sub3(z1, y1, N2, y0, N2); else bigint_sub3(z1, y0, N2, y1, N2); karatsuba_mul(workspace, z0, z1, N2, workspace+N); } karatsuba_mul(z0, x0, y0, N2, workspace+N); karatsuba_mul(z1, x1, y1, N2, workspace+N); word carry = bigint_add3_nc(workspace+N, z0, N, z1, N); carry += bigint_add2_nc(z + N2, N, workspace + N, N); bigint_add2_nc(z + N + N2, N2, &carry, 1); if((cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0)) bigint_add2(z + N2, 2*N-N2, workspace, N); else bigint_sub2(z + N2, 2*N-N2, workspace, N); } } /************************************************* * Pick a good size for the Karatsuba multiply * *************************************************/ u32bit karatsuba_size(u32bit z_size, u32bit x_size, u32bit x_sw, u32bit y_size, u32bit y_sw) { if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) return 0; if(((x_size == x_sw) && (x_size % 2)) || ((y_size == y_sw) && (y_size % 2))) return 0; u32bit start = (x_sw > y_sw) ? x_sw : y_sw; u32bit end = (x_size < y_size) ? x_size : y_size; if(start == end) { if(start % 2) return 0; return start; } for(u32bit j = start; j <= end; ++j) { if(j % 2) continue; if(2*j > z_size) return 0; if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) { if(j % 4 == 2 && (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size) return j+2; return j; } } return 0; } /************************************************* * Handle small operand multiplies * *************************************************/ void handle_small_mul(word z[], u32bit z_size, const word x[], u32bit x_size, u32bit x_sw, const word y[], u32bit y_size, u32bit y_sw) { if(x_sw == 1) bigint_linmul3(z, y, y_sw, x[0]); else if(y_sw == 1) bigint_linmul3(z, x, x_sw, y[0]); else if(x_sw <= 4 && x_size >= 4 && y_sw <= 4 && y_size >= 4 && z_size >= 8) bigint_comba_mul4(z, x, y); else if(x_sw <= 6 && x_size >= 6 && y_sw <= 6 && y_size >= 6 && z_size >= 12) bigint_comba_mul6(z, x, y); else if(x_sw <= 8 && x_size >= 8 && y_sw <= 8 && y_size >= 8 && z_size >= 16) bigint_comba_mul8(z, x, y); else bigint_simple_mul(z, x, x_sw, y, y_sw); } } /************************************************* * Multiplication Algorithm Dispatcher * *************************************************/ void bigint_mul(word z[], u32bit z_size, word workspace[], const word x[], u32bit x_size, u32bit x_sw, const word y[], u32bit y_size, u32bit y_sw) { if(x_size <= 8 || y_size <= 8) { handle_small_mul(z, z_size, x, x_size, x_sw, y, y_size, y_sw); return; } const u32bit N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); if(N) { clear_mem(workspace, 2*N); karatsuba_mul(z, x, y, N, workspace); } else bigint_simple_mul(z, x, x_sw, y, y_sw); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/big_ops3.cpp0000644000175000017500000001615011305557613022412 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * BigInt Binary Operators Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Addition Operator * *************************************************/ BigInt operator+(const BigInt& x, const BigInt& y) { const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); #ifdef BOTAN_TYPES_QT BigInt z(x.sign(), qMax(x_sw, y_sw) + 1); #else BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); #endif if((x.sign() == y.sign())) bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); else { s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); if(relative_size < 0) { bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw); z.set_sign(y.sign()); } else if(relative_size == 0) z.set_sign(BigInt::Positive); else if(relative_size > 0) bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); } return z; } /************************************************* * Subtraction Operator * *************************************************/ BigInt operator-(const BigInt& x, const BigInt& y) { const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); #ifdef BOTAN_TYPES_QT BigInt z(BigInt::Positive, qMax(x_sw, y_sw) + 1); #else BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); #endif if(relative_size < 0) { if(x.sign() == y.sign()) bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw); else bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); z.set_sign(y.reverse_sign()); } else if(relative_size == 0) { if(x.sign() != y.sign()) bigint_shl2(z.get_reg(), x.data(), x_sw, 0, 1); } else if(relative_size > 0) { if(x.sign() == y.sign()) bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); else bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); z.set_sign(x.sign()); } return z; } /************************************************* * Multiplication Operator * *************************************************/ BigInt operator*(const BigInt& x, const BigInt& y) { const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); BigInt z(BigInt::Positive, x.size() + y.size()); if(x_sw == 1 && y_sw) bigint_linmul3(z.get_reg(), y.data(), y_sw, x.word_at(0)); else if(y_sw == 1 && x_sw) bigint_linmul3(z.get_reg(), x.data(), x_sw, y.word_at(0)); else if(x_sw && y_sw) { SecureVector workspace(z.size()); bigint_mul(z.get_reg(), z.size(), workspace, x.data(), x.size(), x_sw, y.data(), y.size(), y_sw); } if(x_sw && y_sw && x.sign() != y.sign()) z.flip_sign(); return z; } /************************************************* * Division Operator * *************************************************/ BigInt operator/(const BigInt& x, const BigInt& y) { BigInt q, r; divide(x, y, q, r); return q; } /************************************************* * Modulo Operator * *************************************************/ BigInt operator%(const BigInt& n, const BigInt& mod) { if(mod.is_zero()) throw BigInt::DivideByZero(); if(mod.is_negative()) throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); if(n.is_positive() && mod.is_positive() && n < mod) return n; BigInt q, r; divide(n, mod, q, r); return r; } /************************************************* * Modulo Operator * *************************************************/ word operator%(const BigInt& n, word mod) { if(mod == 0) throw BigInt::DivideByZero(); if(power_of_2(mod)) return (n.word_at(0) & (mod - 1)); word remainder = 0; for(u32bit j = n.sig_words(); j > 0; --j) remainder = bigint_modop(remainder, n.word_at(j-1), mod); if(remainder && n.sign() == BigInt::Negative) return mod - remainder; return remainder; } /************************************************* * Left Shift Operator * *************************************************/ BigInt operator<<(const BigInt& x, u32bit shift) { if(shift == 0) return x; const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS; const u32bit x_sw = x.sig_words(); BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); bigint_shl2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits); return y; } /************************************************* * Right Shift Operator * *************************************************/ BigInt operator>>(const BigInt& x, u32bit shift) { if(shift == 0) return x; if(x.bits() <= shift) return 0; const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS, x_sw = x.sig_words(); BigInt y(x.sign(), x_sw - shift_words); bigint_shr2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits); return y; } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/ml_unix/0000755000175000017500000000000011305557613021651 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/botan/ml_unix/mlock.cpp0000644000175000017500000000442211305557613023464 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Memory Locking Functions Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199309 #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Lock an area of memory into RAM * *************************************************/ void lock_mem(void* ptr, u32bit bytes) { mlock(ptr, bytes); } /************************************************* * Unlock a previously locked region of memory * *************************************************/ void unlock_mem(void* ptr, u32bit bytes) { munlock(ptr, bytes); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mp_comba.cpp0000644000175000017500000003341511305557613022465 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Comba Multiplication and Squaring Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { extern "C" { /************************************************* * Comba 4x4 Multiplication * *************************************************/ void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[0]); z[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[1]); word3_muladd(&w2, &w1, &w0, x[1], y[0]); z[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[2]); word3_muladd(&w2, &w1, &w0, x[1], y[1]); word3_muladd(&w2, &w1, &w0, x[2], y[0]); z[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[3]); word3_muladd(&w2, &w1, &w0, x[1], y[2]); word3_muladd(&w2, &w1, &w0, x[2], y[1]); word3_muladd(&w2, &w1, &w0, x[3], y[0]); z[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[1], y[3]); word3_muladd(&w2, &w1, &w0, x[2], y[2]); word3_muladd(&w2, &w1, &w0, x[3], y[1]); z[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[2], y[3]); word3_muladd(&w2, &w1, &w0, x[3], y[2]); z[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[3], y[3]); z[6] = w0; z[7] = w1; } /************************************************* * Comba 6x6 Multiplication * *************************************************/ void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[0]); z[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[1]); word3_muladd(&w2, &w1, &w0, x[1], y[0]); z[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[2]); word3_muladd(&w2, &w1, &w0, x[1], y[1]); word3_muladd(&w2, &w1, &w0, x[2], y[0]); z[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[3]); word3_muladd(&w2, &w1, &w0, x[1], y[2]); word3_muladd(&w2, &w1, &w0, x[2], y[1]); word3_muladd(&w2, &w1, &w0, x[3], y[0]); z[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[4]); word3_muladd(&w2, &w1, &w0, x[1], y[3]); word3_muladd(&w2, &w1, &w0, x[2], y[2]); word3_muladd(&w2, &w1, &w0, x[3], y[1]); word3_muladd(&w2, &w1, &w0, x[4], y[0]); z[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[5]); word3_muladd(&w2, &w1, &w0, x[1], y[4]); word3_muladd(&w2, &w1, &w0, x[2], y[3]); word3_muladd(&w2, &w1, &w0, x[3], y[2]); word3_muladd(&w2, &w1, &w0, x[4], y[1]); word3_muladd(&w2, &w1, &w0, x[5], y[0]); z[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[1], y[5]); word3_muladd(&w2, &w1, &w0, x[2], y[4]); word3_muladd(&w2, &w1, &w0, x[3], y[3]); word3_muladd(&w2, &w1, &w0, x[4], y[2]); word3_muladd(&w2, &w1, &w0, x[5], y[1]); z[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[2], y[5]); word3_muladd(&w2, &w1, &w0, x[3], y[4]); word3_muladd(&w2, &w1, &w0, x[4], y[3]); word3_muladd(&w2, &w1, &w0, x[5], y[2]); z[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[3], y[5]); word3_muladd(&w2, &w1, &w0, x[4], y[4]); word3_muladd(&w2, &w1, &w0, x[5], y[3]); z[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[4], y[5]); word3_muladd(&w2, &w1, &w0, x[5], y[4]); z[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[5], y[5]); z[10] = w0; z[11] = w1; } /************************************************* * Comba 8x8 Multiplication * *************************************************/ void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[0]); z[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[1]); word3_muladd(&w2, &w1, &w0, x[1], y[0]); z[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[2]); word3_muladd(&w2, &w1, &w0, x[1], y[1]); word3_muladd(&w2, &w1, &w0, x[2], y[0]); z[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[3]); word3_muladd(&w2, &w1, &w0, x[1], y[2]); word3_muladd(&w2, &w1, &w0, x[2], y[1]); word3_muladd(&w2, &w1, &w0, x[3], y[0]); z[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[4]); word3_muladd(&w2, &w1, &w0, x[1], y[3]); word3_muladd(&w2, &w1, &w0, x[2], y[2]); word3_muladd(&w2, &w1, &w0, x[3], y[1]); word3_muladd(&w2, &w1, &w0, x[4], y[0]); z[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[5]); word3_muladd(&w2, &w1, &w0, x[1], y[4]); word3_muladd(&w2, &w1, &w0, x[2], y[3]); word3_muladd(&w2, &w1, &w0, x[3], y[2]); word3_muladd(&w2, &w1, &w0, x[4], y[1]); word3_muladd(&w2, &w1, &w0, x[5], y[0]); z[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[6]); word3_muladd(&w2, &w1, &w0, x[1], y[5]); word3_muladd(&w2, &w1, &w0, x[2], y[4]); word3_muladd(&w2, &w1, &w0, x[3], y[3]); word3_muladd(&w2, &w1, &w0, x[4], y[2]); word3_muladd(&w2, &w1, &w0, x[5], y[1]); word3_muladd(&w2, &w1, &w0, x[6], y[0]); z[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[0], y[7]); word3_muladd(&w2, &w1, &w0, x[1], y[6]); word3_muladd(&w2, &w1, &w0, x[2], y[5]); word3_muladd(&w2, &w1, &w0, x[3], y[4]); word3_muladd(&w2, &w1, &w0, x[4], y[3]); word3_muladd(&w2, &w1, &w0, x[5], y[2]); word3_muladd(&w2, &w1, &w0, x[6], y[1]); word3_muladd(&w2, &w1, &w0, x[7], y[0]); z[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[1], y[7]); word3_muladd(&w2, &w1, &w0, x[2], y[6]); word3_muladd(&w2, &w1, &w0, x[3], y[5]); word3_muladd(&w2, &w1, &w0, x[4], y[4]); word3_muladd(&w2, &w1, &w0, x[5], y[3]); word3_muladd(&w2, &w1, &w0, x[6], y[2]); word3_muladd(&w2, &w1, &w0, x[7], y[1]); z[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[2], y[7]); word3_muladd(&w2, &w1, &w0, x[3], y[6]); word3_muladd(&w2, &w1, &w0, x[4], y[5]); word3_muladd(&w2, &w1, &w0, x[5], y[4]); word3_muladd(&w2, &w1, &w0, x[6], y[3]); word3_muladd(&w2, &w1, &w0, x[7], y[2]); z[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[3], y[7]); word3_muladd(&w2, &w1, &w0, x[4], y[6]); word3_muladd(&w2, &w1, &w0, x[5], y[5]); word3_muladd(&w2, &w1, &w0, x[6], y[4]); word3_muladd(&w2, &w1, &w0, x[7], y[3]); z[10] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[4], y[7]); word3_muladd(&w2, &w1, &w0, x[5], y[6]); word3_muladd(&w2, &w1, &w0, x[6], y[5]); word3_muladd(&w2, &w1, &w0, x[7], y[4]); z[11] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[5], y[7]); word3_muladd(&w2, &w1, &w0, x[6], y[6]); word3_muladd(&w2, &w1, &w0, x[7], y[5]); z[12] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[6], y[7]); word3_muladd(&w2, &w1, &w0, x[7], y[6]); z[13] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[7], y[7]); z[14] = w0; z[15] = w1; } /************************************************* * Comba 4x4 Squaring * *************************************************/ void bigint_comba_sqr4(word z[8], const word x[4]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[0], x[0]); z[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[1]); z[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[2]); word3_muladd(&w2, &w1, &w0, x[1], x[1]); z[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[3]); word3_muladd_2(&w2, &w1, &w0, x[1], x[2]); z[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[1], x[3]); word3_muladd(&w2, &w1, &w0, x[2], x[2]); z[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[2], x[3]); z[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[3], x[3]); z[6] = w0; z[7] = w1; } /************************************************* * Comba 6x6 Squaring * *************************************************/ void bigint_comba_sqr6(word z[12], const word x[6]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[0], x[0]); z[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[1]); z[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[2]); word3_muladd(&w2, &w1, &w0, x[1], x[1]); z[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[3]); word3_muladd_2(&w2, &w1, &w0, x[1], x[2]); z[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[4]); word3_muladd_2(&w2, &w1, &w0, x[1], x[3]); word3_muladd(&w2, &w1, &w0, x[2], x[2]); z[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[5]); word3_muladd_2(&w2, &w1, &w0, x[1], x[4]); word3_muladd_2(&w2, &w1, &w0, x[2], x[3]); z[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[1], x[5]); word3_muladd_2(&w2, &w1, &w0, x[2], x[4]); word3_muladd(&w2, &w1, &w0, x[3], x[3]); z[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[2], x[5]); word3_muladd_2(&w2, &w1, &w0, x[3], x[4]); z[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[3], x[5]); word3_muladd(&w2, &w1, &w0, x[4], x[4]); z[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[4], x[5]); z[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[5], x[5]); z[10] = w0; z[11] = w1; } /************************************************* * Comba 8x8 Squaring * *************************************************/ void bigint_comba_sqr8(word z[16], const word x[8]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[0], x[0]); z[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[1]); z[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[2]); word3_muladd(&w2, &w1, &w0, x[1], x[1]); z[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[3]); word3_muladd_2(&w2, &w1, &w0, x[1], x[2]); z[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[4]); word3_muladd_2(&w2, &w1, &w0, x[1], x[3]); word3_muladd(&w2, &w1, &w0, x[2], x[2]); z[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[5]); word3_muladd_2(&w2, &w1, &w0, x[1], x[4]); word3_muladd_2(&w2, &w1, &w0, x[2], x[3]); z[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[6]); word3_muladd_2(&w2, &w1, &w0, x[1], x[5]); word3_muladd_2(&w2, &w1, &w0, x[2], x[4]); word3_muladd(&w2, &w1, &w0, x[3], x[3]); z[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[0], x[7]); word3_muladd_2(&w2, &w1, &w0, x[1], x[6]); word3_muladd_2(&w2, &w1, &w0, x[2], x[5]); word3_muladd_2(&w2, &w1, &w0, x[3], x[4]); z[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[1], x[7]); word3_muladd_2(&w2, &w1, &w0, x[2], x[6]); word3_muladd_2(&w2, &w1, &w0, x[3], x[5]); word3_muladd(&w2, &w1, &w0, x[4], x[4]); z[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[2], x[7]); word3_muladd_2(&w2, &w1, &w0, x[3], x[6]); word3_muladd_2(&w2, &w1, &w0, x[4], x[5]); z[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[3], x[7]); word3_muladd_2(&w2, &w1, &w0, x[4], x[6]); word3_muladd(&w2, &w1, &w0, x[5], x[5]); z[10] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[4], x[7]); word3_muladd_2(&w2, &w1, &w0, x[5], x[6]); z[11] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[5], x[7]); word3_muladd(&w2, &w1, &w0, x[6], x[6]); z[12] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[6], x[7]); z[13] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[7], x[7]); z[14] = w0; z[15] = w1; } } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/exceptn.cpp0000644000175000017500000000765011305557613022360 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Exceptions Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Constructor for Invalid_Key_Length * *************************************************/ Invalid_Key_Length::Invalid_Key_Length(const std::string& name, u32bit length) { set_msg(name + " cannot accept a key of length " + to_string(length)); } /************************************************* * Constructor for Invalid_Block_Size * *************************************************/ Invalid_Block_Size::Invalid_Block_Size(const std::string& mode, const std::string& pad) { set_msg("Padding method " + pad + " cannot be used with " + mode); } /************************************************* * Constructor for Invalid_IV_Length * *************************************************/ Invalid_IV_Length::Invalid_IV_Length(const std::string& mode, u32bit bad_len) { set_msg("IV length " + to_string(bad_len) + " is invalid for " + mode); } /************************************************* * Constructor for Invalid_Message_Number * *************************************************/ Invalid_Message_Number::Invalid_Message_Number(const std::string& where, u32bit message_no) { set_msg("Pipe::" + where + ": Invalid message number " + to_string(message_no)); } /************************************************* * Constructor for Algorithm_Not_Found * *************************************************/ Algorithm_Not_Found::Algorithm_Not_Found(const std::string& name) { set_msg("Could not find any algorithm named \"" + name + "\""); } /************************************************* * Constructor for Invalid_Algorithm_Name * *************************************************/ Invalid_Algorithm_Name::Invalid_Algorithm_Name(const std::string& name) { set_msg("Invalid algorithm name: " + name); } /************************************************* * Constructor for Config_Error * *************************************************/ Config_Error::Config_Error(const std::string& err, u32bit line) { set_msg("Config error at line " + to_string(line) + ": " + err); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mutex.cpp0000644000175000017500000000777611305557613022065 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Mutex Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_NO_LIBSTATE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif namespace Botan { /************************************************* * Mutex_Holder Constructor * *************************************************/ Mutex_Holder::Mutex_Holder(Mutex* m) : mux(m) { if(!mux) throw Invalid_Argument("Mutex_Holder: Argument was NULL"); mux->lock(); } /************************************************* * Mutex_Holder Destructor * *************************************************/ Mutex_Holder::~Mutex_Holder() { mux->unlock(); } #ifndef BOTAN_NO_LIBSTATE /************************************************* * Named_Mutex_Holder Constructor * *************************************************/ Named_Mutex_Holder::Named_Mutex_Holder(const std::string& name) : mutex_name(name) { global_state().get_named_mutex(mutex_name)->lock(); } /************************************************* * Named_Mutex_Holder Destructor * *************************************************/ Named_Mutex_Holder::~Named_Mutex_Holder() { global_state().get_named_mutex(mutex_name)->unlock(); } #endif /************************************************* * Default Mutex Factory * *************************************************/ #ifdef BOTAN_FIX_GDB namespace { #else Mutex* Default_Mutex_Factory::make() { #endif class Default_Mutex : public Mutex { public: class Mutex_State_Error : public Internal_Error { public: Mutex_State_Error(const std::string& where) : Internal_Error("Default_Mutex::" + where + ": " + "Mutex is already " + where + "ed") {} }; void lock() { if(locked) throw Mutex_State_Error("lock"); locked = true; } void unlock() { if(!locked) throw Mutex_State_Error("unlock"); locked = false; } Default_Mutex() { locked = false; } private: bool locked; }; #ifdef BOTAN_FIX_GDB } // end unnamed namespace Mutex* Default_Mutex_Factory::make() { #endif return new Default_Mutex; } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/charset.cpp0000644000175000017500000002152411305557613022337 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Character Set Handling Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifdef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #else } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { namespace Charset { /************************************************* * Perform character set transcoding * *************************************************/ #ifndef BOTAN_TOOLS_ONLY std::string transcode(const std::string& str, Character_Set to, Character_Set from) { return global_state().transcode(str, to, from); } #endif /************************************************* * Check if a character represents a digit * *************************************************/ bool is_digit(char c) { if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9') return true; return false; } /************************************************* * Check if a character represents whitespace * *************************************************/ bool is_space(char c) { if(c == ' ' || c == '\t' || c == '\n' || c == '\r') return true; return false; } /************************************************* * Convert a character to a digit * *************************************************/ byte char2digit(char c) { switch(c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; } throw Invalid_Argument("char2digit: Input is not a digit character"); } /************************************************* * Convert a digit to a character * *************************************************/ char digit2char(byte b) { switch(b) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; } throw Invalid_Argument("digit2char: Input is not a digit"); } /************************************************* * Case-insensitive character comparison * *************************************************/ bool caseless_cmp(char a, char b) { return (tolower((unsigned char)a) == tolower((unsigned char)b)); } } #ifndef BOTAN_TOOLS_ONLY /************************************************* * Hex Encoder Lookup Tables * *************************************************/ const byte Hex_Encoder::BIN_TO_HEX_UPPER[16] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; const byte Hex_Encoder::BIN_TO_HEX_LOWER[16] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 }; /************************************************* * Base64 Encoder Lookup Table * *************************************************/ const byte Base64_Encoder::BIN_TO_BASE64[64] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F }; /************************************************* * Hex Decoder Lookup Table * *************************************************/ const byte Hex_Decoder::HEX_TO_BIN[256] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; /************************************************* * Base64 Decoder Lookup Table * *************************************************/ const byte Base64_Decoder::BASE64_TO_BIN[256] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; #endif } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/big_base.cpp0000644000175000017500000003075511305557613022447 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * BigInt Base Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Construct a BigInt from a regular number * *************************************************/ BigInt::BigInt(u64bit n) { set_sign(Positive); if(n == 0) return; const u32bit limbs_needed = sizeof(u64bit) / sizeof(word); reg.create(4*limbs_needed); for(u32bit j = 0; j != limbs_needed; ++j) reg[j] = (word)((n >> (j*MP_WORD_BITS)) & MP_WORD_MASK); } /************************************************* * Construct a BigInt of the specified size * *************************************************/ BigInt::BigInt(Sign s, u32bit size) { reg.create(round_up(size, 8)); signedness = s; } /************************************************* * Construct a BigInt from a "raw" BigInt * *************************************************/ BigInt::BigInt(const BigInt& b) { const u32bit b_words = b.sig_words(); if(b_words) { reg.create(round_up(b_words, 8)); reg.copy(b.data(), b_words); set_sign(b.sign()); } else { reg.create(2); set_sign(Positive); } } /************************************************* * Construct a BigInt from a string * *************************************************/ BigInt::BigInt(const std::string& str) { Base base = Decimal; u32bit markers = 0; bool negative = false; if(str.length() > 0 && str[0] == '-') { markers += 1; negative = true; } if(str.length() > markers + 2 && str[markers ] == '0' && str[markers + 1] == 'x') { markers += 2; base = Hexadecimal; } else if(str.length() > markers + 1 && str[markers] == '0') { markers += 1; base = Octal; } *this = decode((const byte*)str.data() + markers, str.length() - markers, base); if(negative) set_sign(Negative); else set_sign(Positive); } /************************************************* * Construct a BigInt from an encoded BigInt * *************************************************/ BigInt::BigInt(const byte input[], u32bit length, Base base) { set_sign(Positive); *this = decode(input, length, base); } /************************************************* * Swap this BigInt with another * *************************************************/ void BigInt::swap(BigInt& other) { std::swap(reg, other.reg); std::swap(signedness, other.signedness); } /************************************************* * Grow the internal storage * *************************************************/ void BigInt::grow_reg(u32bit n) const { reg.grow_to(round_up(size() + n, 8)); } /************************************************* * Grow the internal storage * *************************************************/ void BigInt::grow_to(u32bit n) const { if(n > size()) reg.grow_to(round_up(n, 8)); } /************************************************* * Comparison Function * *************************************************/ s32bit BigInt::cmp(const BigInt& n, bool check_signs) const { if(check_signs) { if(n.is_positive() && this->is_negative()) return -1; if(n.is_negative() && this->is_positive()) return 1; if(n.is_negative() && this->is_negative()) return (-bigint_cmp(data(), sig_words(), n.data(), n.sig_words())); } return bigint_cmp(data(), sig_words(), n.data(), n.sig_words()); } /************************************************* * Convert this number to a u32bit, if possible * *************************************************/ u32bit BigInt::to_u32bit() const { if(is_negative()) throw Encoding_Error("BigInt::to_u32bit: Number is negative"); if(bits() >= 32) throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); u32bit out = 0; for(u32bit j = 0; j != 4; ++j) out = (out << 8) | byte_at(3-j); return out; } /************************************************* * Return byte n of this number * *************************************************/ byte BigInt::byte_at(u32bit n) const { const u32bit WORD_BYTES = sizeof(word); u32bit word_num = n / WORD_BYTES, byte_num = n % WORD_BYTES; if(word_num >= size()) return 0; else return get_byte(WORD_BYTES - byte_num - 1, reg[word_num]); } /************************************************* * Return bit n of this number * *************************************************/ bool BigInt::get_bit(u32bit n) const { return ((word_at(n / MP_WORD_BITS) >> (n % MP_WORD_BITS)) & 1); } /************************************************* * Return bits {offset...offset+length} * *************************************************/ u32bit BigInt::get_substring(u32bit offset, u32bit length) const { if(length > 32) throw Invalid_Argument("BigInt::get_substring: Substring size too big"); u64bit piece = 0; for(u32bit j = 0; j != 8; ++j) piece = (piece << 8) | byte_at((offset / 8) + (7-j)); u64bit mask = (1 << length) - 1; u32bit shift = (offset % 8); return static_cast((piece >> shift) & mask); } /************************************************* * Set bit number n * *************************************************/ void BigInt::set_bit(u32bit n) { const u32bit which = n / MP_WORD_BITS; const word mask = (word)1 << (n % MP_WORD_BITS); if(which >= size()) grow_to(which + 1); reg[which] |= mask; } /************************************************* * Clear bit number n * *************************************************/ void BigInt::clear_bit(u32bit n) { const u32bit which = n / MP_WORD_BITS; const word mask = (word)1 << (n % MP_WORD_BITS); if(which < size()) reg[which] &= ~mask; } /************************************************* * Clear all but the lowest n bits * *************************************************/ void BigInt::mask_bits(u32bit n) { if(n == 0) { clear(); return; } if(n >= bits()) return; const u32bit top_word = n / MP_WORD_BITS; const word mask = ((word)1 << (n % MP_WORD_BITS)) - 1; if(top_word < size()) for(u32bit j = top_word + 1; j != size(); ++j) reg[j] = 0; reg[top_word] &= mask; } /************************************************* * Count the significant words * *************************************************/ u32bit BigInt::sig_words() const { const word* x = data(); u32bit top_set = size(); while(top_set >= 4) { word sum = x[top_set-1] | x[top_set-2] | x[top_set-3] | x[top_set-4]; if(sum) break; else top_set -= 4; } while(top_set && (x[top_set-1] == 0)) top_set--; return top_set; } /************************************************* * Count how many bytes are being used * *************************************************/ u32bit BigInt::bytes() const { return (bits() + 7) / 8; } /************************************************* * Count how many bits are being used * *************************************************/ u32bit BigInt::bits() const { if(sig_words() == 0) return 0; u32bit full_words = sig_words() - 1, top_bits = MP_WORD_BITS; word top_word = word_at(full_words), mask = MP_WORD_TOP_BIT; while(top_bits && ((top_word & mask) == 0)) { mask >>= 1; top_bits--; } return (full_words * MP_WORD_BITS + top_bits); } /************************************************* * Calcluate the size in a certain base * *************************************************/ u32bit BigInt::encoded_size(Base base) const { static const double LOG_2_BASE_10 = 0.30102999566; if(base == Binary) return bytes(); else if(base == Hexadecimal) return 2*bytes(); else if(base == Octal) return ((bits() + 2) / 3); else if(base == Decimal) return (u32bit)((bits() * LOG_2_BASE_10) + 1); else throw Invalid_Argument("Unknown base for BigInt encoding"); } /************************************************* * Return true if this number is zero * *************************************************/ bool BigInt::is_zero() const { for(u32bit j = 0; j != size(); ++j) if(reg[j]) return false; return true; } /************************************************* * Set the sign * *************************************************/ void BigInt::set_sign(Sign s) { if(is_zero()) signedness = Positive; else signedness = s; } /************************************************* * Reverse the value of the sign flag * *************************************************/ void BigInt::flip_sign() { set_sign(reverse_sign()); } /************************************************* * Return the opposite value of the current sign * *************************************************/ BigInt::Sign BigInt::reverse_sign() const { if(sign() == Positive) return Negative; return Positive; } /************************************************* * Return the negation of this number * *************************************************/ BigInt BigInt::operator-() const { BigInt x = (*this); x.flip_sign(); return x; } /************************************************* * Return the absolute value of this number * *************************************************/ BigInt BigInt::abs() const { BigInt x = (*this); x.set_sign(Positive); return x; } /************************************************* * Encode this number into bytes * *************************************************/ void BigInt::binary_encode(byte output[]) const { const u32bit sig_bytes = bytes(); for(u32bit j = 0; j != sig_bytes; ++j) output[sig_bytes-j-1] = byte_at(j); } /************************************************* * Set this number to the value in buf * *************************************************/ void BigInt::binary_decode(const byte buf[], u32bit length) { const u32bit WORD_BYTES = sizeof(word); reg.create(round_up((length / WORD_BYTES) + 1, 8)); for(u32bit j = 0; j != length / WORD_BYTES; ++j) { u32bit top = length - WORD_BYTES*j; for(u32bit k = WORD_BYTES; k > 0; --k) reg[j] = (reg[j] << 8) | buf[top - k]; } for(u32bit j = 0; j != length % WORD_BYTES; ++j) reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[j]; } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mem_pool.cpp0000644000175000017500000002153711305557613022521 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Pooling Allocator Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifdef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #else } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { namespace { /************************************************* * Decide how much memory to allocate at once * *************************************************/ u32bit choose_pref_size(u32bit provided) { if(provided) return provided; #ifdef BOTAN_TOOLS_ONLY u32bit result = (u32bit)global_state().prealloc_size; #else u32bit result = global_config().option_as_u32bit("base/memory_chunk"); #endif if(result) return result; return 16*1024; } } /************************************************* * Memory_Block Constructor * *************************************************/ Pooling_Allocator::Memory_Block::Memory_Block(void* buf) { buffer = static_cast(buf); bitmap = 0; buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE); } /************************************************* * See if ptr is contained by this block * *************************************************/ bool Pooling_Allocator::Memory_Block::contains(void* ptr, u32bit length) const throw() { return ((buffer <= ptr) && (buffer_end >= (byte*)ptr + length * BLOCK_SIZE)); } /************************************************* * Allocate some memory, if possible * *************************************************/ byte* Pooling_Allocator::Memory_Block::alloc(u32bit n) throw() { if(n == 0 || n > BITMAP_SIZE) return 0; if(n == BITMAP_SIZE) { if(bitmap) return 0; else { bitmap = ~bitmap; return buffer; } } bitmap_type mask = ((bitmap_type)1 << n) - 1; u32bit offset = 0; while(bitmap & mask) { mask <<= 1; ++offset; if((bitmap & mask) == 0) break; if(mask >> 63) break; } if(bitmap & mask) return 0; bitmap |= mask; return buffer + offset * BLOCK_SIZE; } /************************************************* * Mark this memory as free, if we own it * *************************************************/ void Pooling_Allocator::Memory_Block::free(void* ptr, u32bit blocks) throw() { clear_mem((byte*)ptr, blocks * BLOCK_SIZE); const u32bit offset = ((byte*)ptr - buffer) / BLOCK_SIZE; if(offset == 0 && blocks == BITMAP_SIZE) bitmap = ~bitmap; else { for(u32bit j = 0; j != blocks; ++j) bitmap &= ~((bitmap_type)1 << (j+offset)); } } /************************************************* * Pooling_Allocator Constructor * *************************************************/ Pooling_Allocator::Pooling_Allocator(u32bit p_size, bool) : PREF_SIZE(choose_pref_size(p_size)) { mutex = global_state().get_mutex(); last_used = blocks.begin(); } /************************************************* * Pooling_Allocator Destructor * *************************************************/ Pooling_Allocator::~Pooling_Allocator() { delete mutex; if(blocks.size()) throw Invalid_State("Pooling_Allocator: Never released memory"); } /************************************************* * Free all remaining memory * *************************************************/ void Pooling_Allocator::destroy() { Mutex_Holder lock(mutex); blocks.clear(); for(u32bit j = 0; j != allocated.size(); ++j) dealloc_block(allocated[j].first, allocated[j].second); allocated.clear(); } /************************************************* * Allocation * *************************************************/ void* Pooling_Allocator::allocate(u32bit n) { const u32bit BITMAP_SIZE = Memory_Block::bitmap_size(); const u32bit BLOCK_SIZE = Memory_Block::block_size(); Mutex_Holder lock(mutex); if(n <= BITMAP_SIZE * BLOCK_SIZE) { const u32bit block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; byte* mem = allocate_blocks(block_no); if(mem) return mem; get_more_core(PREF_SIZE); mem = allocate_blocks(block_no); if(mem) return mem; throw Memory_Exhaustion(); } void* new_buf = alloc_block(n); if(new_buf) return new_buf; throw Memory_Exhaustion(); } /************************************************* * Deallocation * *************************************************/ void Pooling_Allocator::deallocate(void* ptr, u32bit n) { const u32bit BITMAP_SIZE = Memory_Block::bitmap_size(); const u32bit BLOCK_SIZE = Memory_Block::block_size(); if(ptr == 0 || n == 0) return; Mutex_Holder lock(mutex); if(n > BITMAP_SIZE * BLOCK_SIZE) dealloc_block(ptr, n); else { const u32bit block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; std::vector::iterator i = std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); if(i == blocks.end() || !i->contains(ptr, block_no)) throw Invalid_State("Pointer released to the wrong allocator"); i->free(ptr, block_no); } } /************************************************* * Try to get some memory from an existing block * *************************************************/ byte* Pooling_Allocator::allocate_blocks(u32bit n) { if(blocks.empty()) return 0; std::vector::iterator i = last_used; do { byte* mem = i->alloc(n); if(mem) { last_used = i; return mem; } ++i; if(i == blocks.end()) i = blocks.begin(); } while(i != last_used); return 0; } /************************************************* * Allocate more memory for the pool * *************************************************/ void Pooling_Allocator::get_more_core(u32bit in_bytes) { const u32bit BITMAP_SIZE = Memory_Block::bitmap_size(); const u32bit BLOCK_SIZE = Memory_Block::block_size(); const u32bit TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE; const u32bit in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE; const u32bit to_allocate = in_blocks * TOTAL_BLOCK_SIZE; void* ptr = alloc_block(to_allocate); if(ptr == 0) throw Memory_Exhaustion(); allocated.push_back(std::make_pair(ptr, to_allocate)); for(u32bit j = 0; j != in_blocks; ++j) { byte* byte_ptr = static_cast(ptr); blocks.push_back(Memory_Block(byte_ptr + j * TOTAL_BLOCK_SIZE)); } std::sort(blocks.begin(), blocks.end()); last_used = std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); } const u32bit Pooling_Allocator::Memory_Block::BITMAP_SIZE = 8 * sizeof(Pooling_Allocator::Memory_Block::bitmap_type); const u32bit Pooling_Allocator::Memory_Block::BLOCK_SIZE = 64; } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/modules.cpp0000644000175000017500000002035411305557613022356 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Module Factory Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_MUTEX_PTHREAD) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #elif defined(BOTAN_EXT_MUTEX_WIN32) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #elif defined(BOTAN_EXT_MUTEX_QT) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ALLOC_MMAP) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #ifndef BOTAN_TOOLS_ONLY #if defined(BOTAN_EXT_TIMER_HARDWARE) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #elif defined(BOTAN_EXT_TIMER_POSIX) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #elif defined(BOTAN_EXT_TIMER_UNIX) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #elif defined(BOTAN_EXT_TIMER_WIN32) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENGINE_AEP) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENGINE_GNU_MP) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENGINE_OPENSSL) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_AEP) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_EGD) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #if defined(BOTAN_EXT_ENTROPY_SRC_FTW) } // WRAPNS_LINE # include namespace QCA { // WRAPNS_LINE #endif #endif namespace Botan { /************************************************* * Return a mutex factory, if available * *************************************************/ Mutex_Factory* Builtin_Modules::mutex_factory() const { #if defined(BOTAN_EXT_MUTEX_PTHREAD) return new Pthread_Mutex_Factory; #elif defined(BOTAN_EXT_MUTEX_WIN32) return new Win32_Mutex_Factory; #elif defined(BOTAN_EXT_MUTEX_QT) return new Qt_Mutex_Factory; #else return 0; #endif } /************************************************* * Find a high resolution timer, if possible * *************************************************/ #ifndef BOTAN_TOOLS_ONLY Timer* Builtin_Modules::timer() const { #if defined(BOTAN_EXT_TIMER_HARDWARE) return new Hardware_Timer; #elif defined(BOTAN_EXT_TIMER_POSIX) return new POSIX_Timer; #elif defined(BOTAN_EXT_TIMER_UNIX) return new Unix_Timer; #elif defined(BOTAN_EXT_TIMER_WIN32) return new Win32_Timer; #else return new Timer; #endif } #endif /************************************************* * Find any usable allocators * *************************************************/ std::vector Builtin_Modules::allocators() const { std::vector allocators; #if defined(BOTAN_EXT_ALLOC_MMAP) allocators.push_back(new MemoryMapping_Allocator); #endif allocators.push_back(new Locking_Allocator); allocators.push_back(new Malloc_Allocator); return allocators; } /************************************************* * Return the default allocator * *************************************************/ std::string Builtin_Modules::default_allocator() const { if(should_lock) { #if defined(BOTAN_EXT_ALLOC_MMAP) return "mmap"; #else return "locking"; #endif } else return "malloc"; } #ifndef BOTAN_TOOLS_ONLY /************************************************* * Register any usable entropy sources * *************************************************/ std::vector Builtin_Modules::entropy_sources() const { std::vector sources; sources.push_back(new File_EntropySource); #if defined(BOTAN_EXT_ENTROPY_SRC_AEP) sources.push_back(new AEP_EntropySource); #endif #if defined(BOTAN_EXT_ENTROPY_SRC_EGD) sources.push_back(new EGD_EntropySource); #endif #if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) sources.push_back(new Win32_CAPI_EntropySource); #endif #if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) sources.push_back(new Win32_EntropySource); #endif #if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) sources.push_back(new Unix_EntropySource); #endif #if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) sources.push_back(new BeOS_EntropySource); #endif #if defined(BOTAN_EXT_ENTROPY_SRC_FTW) sources.push_back(new FTW_EntropySource); #endif return sources; } /************************************************* * Find any usable engines * *************************************************/ std::vector Builtin_Modules::engines() const { std::vector engines; if(use_engines) { #if defined(BOTAN_EXT_ENGINE_AEP) engines.push_back(new AEP_Engine); #endif #if defined(BOTAN_EXT_ENGINE_GNU_MP) engines.push_back(new GMP_Engine); #endif #if defined(BOTAN_EXT_ENGINE_OPENSSL) engines.push_back(new OpenSSL_Engine); #endif } engines.push_back(new Default_Engine); return engines; } /************************************************* * Find the best transcoder option * *************************************************/ Charset_Transcoder* Builtin_Modules::transcoder() const { return new Default_Charset_Transcoder; } #endif /************************************************* * Builtin_Modules Constructor * *************************************************/ #ifdef BOTAN_TOOLS_ONLY Builtin_Modules::Builtin_Modules() : should_lock(true) { } #else Builtin_Modules::Builtin_Modules(const InitializerOptions& args) : should_lock(args.secure_memory()), use_engines(args.use_engines()) { } #endif } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mp_mulop.cpp0000644000175000017500000000445511305557613022542 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Multiply/Add Algorithm Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { extern "C" { /************************************************* * Multiply/Add Words * *************************************************/ word bigint_mul_add_words(word z[], const word x[], u32bit x_size, word y) { const u32bit blocks = x_size - (x_size % 8); word carry = 0; for(u32bit j = 0; j != blocks; j += 8) carry = word8_madd3(z + j, x + j, y, carry); for(u32bit j = blocks; j != x_size; ++j) z[j] = word_madd3(x[j], y, z[j], carry, &carry); return carry; } } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/license.txt0000644000175000017500000000240711305557613022364 0ustar janjanCopyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. psi-0.14/third-party/qca/qca/src/botantools/botan/defalloc.cpp0000644000175000017500000001011111305557613022445 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Basic Allocators Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { namespace { /************************************************* * Perform Memory Allocation * *************************************************/ void* do_malloc(u32bit n, bool do_lock) { void* ptr = malloc(n); if(!ptr) return 0; if(do_lock) lock_mem(ptr, n); memset(ptr, 0, n); return ptr; } /************************************************* * Perform Memory Deallocation * *************************************************/ void do_free(void* ptr, u32bit n, bool do_lock) { if(!ptr) return; memset(ptr, 0, n); if(do_lock) unlock_mem(ptr, n); free(ptr); } } /************************************************* * Malloc_Allocator's Allocation * *************************************************/ void* Malloc_Allocator::alloc_block(u32bit n) { return do_malloc(n, false); } /************************************************* * Malloc_Allocator's Deallocation * *************************************************/ void Malloc_Allocator::dealloc_block(void* ptr, u32bit n) { do_free(ptr, n, false); } /************************************************* * Locking_Allocator's Allocation * *************************************************/ void* Locking_Allocator::alloc_block(u32bit n) { return do_malloc(n, true); } /************************************************* * Locking_Allocator's Deallocation * *************************************************/ void Locking_Allocator::dealloc_block(void* ptr, u32bit n) { do_free(ptr, n, true); } /************************************************* * Get an allocator * *************************************************/ Allocator* Allocator::get(bool locking) { std::string type = ""; if(!locking) type = "malloc"; Allocator* alloc = global_state().get_allocator(type); if(alloc) return alloc; throw Exception("Couldn't find an allocator to use in get_allocator"); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/libstate.cpp0000644000175000017500000003356611305557613022526 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Library Internal/Global State Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_TOOLS_ONLY } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Botan's global state * *************************************************/ namespace { Library_State* global_lib_state = 0; } /************************************************* * Access the global state object * *************************************************/ Library_State& global_state() { if(!global_lib_state) throw Invalid_State("Library was not initialized correctly"); return (*global_lib_state); } /************************************************* * Set a new global state object * *************************************************/ void set_global_state(Library_State* new_state) { delete swap_global_state(new_state); } /************************************************* * Swap two global state objects * *************************************************/ Library_State* swap_global_state(Library_State* new_state) { Library_State* old_state = global_lib_state; global_lib_state = new_state; return old_state; } /************************************************* * Increment the Engine iterator * *************************************************/ #ifndef BOTAN_TOOLS_ONLY Engine* Library_State::Engine_Iterator::next() { return lib.get_engine_n(n++); } #endif /************************************************* * Get a new mutex object * *************************************************/ Mutex* Library_State::get_mutex() const { return mutex_factory->make(); } /************************************************* * Get a persistent named mutex object * *************************************************/ Mutex* Library_State::get_named_mutex(const std::string& name) { Mutex* mux = search_map(locks, name, 0); if(mux) return mux; return (locks[name] = get_mutex()); } /************************************************* * Get an allocator by its name * *************************************************/ Allocator* Library_State::get_allocator(const std::string& type) const { Named_Mutex_Holder lock("allocator"); if(type != "") return search_map(alloc_factory, type, 0); if(!cached_default_allocator) { #ifdef BOTAN_TOOLS_ONLY std::string chosen = default_allocator_type; #else std::string chosen = config().option("base/default_allocator"); #endif if(chosen == "") chosen = "malloc"; cached_default_allocator = search_map(alloc_factory, chosen, 0); } return cached_default_allocator; } /************************************************* * Create a new name to object mapping * *************************************************/ void Library_State::add_allocator(Allocator* allocator) { Named_Mutex_Holder lock("allocator"); allocator->init(); allocators.push_back(allocator); alloc_factory[allocator->type()] = allocator; } /************************************************* * Set the default allocator type * *************************************************/ #ifdef BOTAN_TOOLS_ONLY void Library_State::set_default_allocator(const std::string& type) #else void Library_State::set_default_allocator(const std::string& type) const #endif { Named_Mutex_Holder lock("allocator"); if(type == "") return; #ifdef BOTAN_TOOLS_ONLY default_allocator_type = type; #else config().set("conf", "base/default_allocator", type); #endif cached_default_allocator = 0; } #ifndef BOTAN_TOOLS_ONLY /************************************************* * Set the high resolution clock implementation * *************************************************/ void Library_State::set_timer(Timer* new_timer) { if(new_timer) { delete timer; timer = new_timer; } } /************************************************* * Read a high resolution clock * *************************************************/ u64bit Library_State::system_clock() const { return (timer) ? timer->clock() : 0; } /************************************************* * Set the global PRNG * *************************************************/ void Library_State::set_prng(RandomNumberGenerator* new_rng) { Named_Mutex_Holder lock("rng"); delete rng; rng = new_rng; } /************************************************* * Get bytes from the global PRNG * *************************************************/ void Library_State::randomize(byte out[], u32bit length) { Named_Mutex_Holder lock("rng"); rng->randomize(out, length); } /************************************************* * Add a new entropy source to use * *************************************************/ void Library_State::add_entropy_source(EntropySource* src, bool last_in_list) { Named_Mutex_Holder lock("rng"); if(last_in_list) entropy_sources.push_back(src); else entropy_sources.insert(entropy_sources.begin(), src); } /************************************************* * Add some bytes of entropy to the global PRNG * *************************************************/ void Library_State::add_entropy(const byte in[], u32bit length) { Named_Mutex_Holder lock("rng"); rng->add_entropy(in, length); } /************************************************* * Add some bytes of entropy to the global PRNG * *************************************************/ void Library_State::add_entropy(EntropySource& source, bool slow_poll) { Named_Mutex_Holder lock("rng"); rng->add_entropy(source, slow_poll); } /************************************************* * Gather entropy for our PRNG object * *************************************************/ u32bit Library_State::seed_prng(bool slow_poll, u32bit bits_to_get) { Named_Mutex_Holder lock("rng"); u32bit bits = 0; for(u32bit j = 0; j != entropy_sources.size(); ++j) { bits += rng->add_entropy(*(entropy_sources[j]), slow_poll); if(bits_to_get && bits >= bits_to_get) return bits; } return bits; } /************************************************* * Get an engine out of the list * *************************************************/ Engine* Library_State::get_engine_n(u32bit n) const { Named_Mutex_Holder lock("engine"); if(n >= engines.size()) return 0; return engines[n]; } /************************************************* * Add a new engine to the list * *************************************************/ void Library_State::add_engine(Engine* engine) { Named_Mutex_Holder lock("engine"); engines.insert(engines.begin(), engine); } /************************************************* * Set the character set transcoder object * *************************************************/ void Library_State::set_transcoder(class Charset_Transcoder* transcoder) { if(this->transcoder) delete this->transcoder; this->transcoder = transcoder; } /************************************************* * Transcode a string from one charset to another * *************************************************/ std::string Library_State::transcode(const std::string str, Character_Set to, Character_Set from) const { if(!transcoder) throw Invalid_State("Library_State::transcode: No transcoder set"); return transcoder->transcode(str, to, from); } /************************************************* * Set the X509 global state class * *************************************************/ void Library_State::set_x509_state(X509_GlobalState* new_x509_state_obj) { delete x509_state_obj; x509_state_obj = new_x509_state_obj; } /************************************************* * Get the X509 global state class * *************************************************/ X509_GlobalState& Library_State::x509_state() { if(!x509_state_obj) x509_state_obj = new X509_GlobalState(); return (*x509_state_obj); } /************************************************* * Set the UI object state * *************************************************/ void Library_State::set_ui(UI* new_ui) { delete ui; ui = new_ui; } /************************************************* * Send a pulse to the UI object * *************************************************/ void Library_State::pulse(Pulse_Type pulse_type) const { if(ui) ui->pulse(pulse_type); } /************************************************* * Set the configuration object * *************************************************/ Config& Library_State::config() const { if(!config_obj) throw Invalid_State("Library_State::config(): No config set"); return (*config_obj); } #endif /************************************************* * Load modules * *************************************************/ void Library_State::load(Modules& modules) { #ifndef BOTAN_TOOLS_ONLY set_timer(modules.timer()); set_transcoder(modules.transcoder()); #endif std::vector mod_allocs = modules.allocators(); for(u32bit j = 0; j != mod_allocs.size(); j++) add_allocator(mod_allocs[j]); set_default_allocator(modules.default_allocator()); #ifndef BOTAN_TOOLS_ONLY std::vector mod_engines = modules.engines(); for(u32bit j = 0; j != mod_engines.size(); ++j) { Named_Mutex_Holder lock("engine"); engines.push_back(mod_engines[j]); } std::vector sources = modules.entropy_sources(); for(u32bit j = 0; j != sources.size(); ++j) add_entropy_source(sources[j]); #endif } /************************************************* * Library_State Constructor * *************************************************/ Library_State::Library_State(Mutex_Factory* mutex_factory) { if(!mutex_factory) throw Exception("Library_State: no mutex found"); this->mutex_factory = mutex_factory; #ifndef BOTAN_TOOLS_ONLY this->timer = new Timer(); this->transcoder = 0; this->config_obj = new Config(); #endif #ifndef BOTAN_TOOLS_ONLY locks["settings"] = get_mutex(); #endif locks["allocator"] = get_mutex(); #ifndef BOTAN_TOOLS_ONLY locks["rng"] = get_mutex(); locks["engine"] = get_mutex(); rng = 0; #endif cached_default_allocator = 0; #ifndef BOTAN_TOOLS_ONLY x509_state_obj = 0; ui = 0; #endif } /************************************************* * Library_State Destructor * *************************************************/ static void delete_lock(std::pair &pair) { delete pair.second; } Library_State::~Library_State() { #ifndef BOTAN_TOOLS_ONLY delete x509_state_obj; delete transcoder; delete rng; delete timer; delete config_obj; delete ui; std::for_each(entropy_sources.begin(), entropy_sources.end(), del_fun()); std::for_each(engines.begin(), engines.end(), del_fun()); #endif cached_default_allocator = 0; for(u32bit j = 0; j != allocators.size(); j++) { allocators[j]->destroy(); delete allocators[j]; } std::for_each(locks.begin(), locks.end(), delete_lock); delete mutex_factory; } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mux_qt/0000755000175000017500000000000011305557613021513 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/botan/mux_qt/mux_qt.cpp0000644000175000017500000000433511305557613023541 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Qt Thread Mutex Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #if QT_VERSION <= 0x040000 && !defined(QT_THREAD_SUPPORT) #error Your version of Qt does not support threads or mutexes #endif namespace Botan { /************************************************* * Qt Mutex Factory * *************************************************/ Mutex* Qt_Mutex_Factory::make() { class Qt_Mutex : public Mutex { public: void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } private: QMutex mutex; }; return new Qt_Mutex(); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/mux_qt/mux_qt.h0000644000175000017500000000367011305557613023207 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Qt Mutex Header File * * (C) 1999-2007 The Botan Project * *************************************************/ #ifndef BOTAN_EXT_MUTEX_QT_H__ #define BOTAN_EXT_MUTEX_QT_H__ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Qt Mutex * *************************************************/ class Qt_Mutex_Factory : public Mutex_Factory { public: Mutex* make(); }; } #endif } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/parsing.cpp0000644000175000017500000001741411305557613022354 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Parser Functions Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Convert a string into an integer * *************************************************/ #ifndef BOTAN_TOOLS_ONLY u32bit to_u32bit(const std::string& number) { u32bit n = 0; for(std::string::const_iterator j = number.begin(); j != number.end(); ++j) { const u32bit OVERFLOW_MARK = 0xFFFFFFFF / 10; byte digit = Charset::char2digit(*j); if((n > OVERFLOW_MARK) || (n == OVERFLOW_MARK && digit > 5)) throw Decoding_Error("to_u32bit: Integer overflow"); n *= 10; n += digit; } return n; } #endif /************************************************* * Convert an integer into a string * *************************************************/ std::string to_string(u64bit n, u32bit min_len) { std::string lenstr; if(n) { while(n > 0) { lenstr = Charset::digit2char(n % 10) + lenstr; n /= 10; } } else lenstr = "0"; while(lenstr.size() < min_len) lenstr = "0" + lenstr; return lenstr; } #ifndef BOTAN_TOOLS_ONLY /************************************************* * Parse a SCAN-style algorithm name * *************************************************/ std::vector parse_algorithm_name(const std::string& namex) { if(namex.find('(') == std::string::npos && namex.find(')') == std::string::npos) return std::vector(1, namex); std::string name = namex, substring; std::vector elems; u32bit level = 0; elems.push_back(name.substr(0, name.find('('))); name = name.substr(name.find('(')); for(std::string::const_iterator j = name.begin(); j != name.end(); ++j) { char c = *j; if(c == '(') ++level; if(c == ')') { if(level == 1 && j == name.end() - 1) { if(elems.size() == 1) elems.push_back(substring.substr(1)); else elems.push_back(substring); return elems; } if(level == 0 || (level == 1 && j != name.end() - 1)) throw Invalid_Algorithm_Name(namex); --level; } if(c == ',' && level == 1) { if(elems.size() == 1) elems.push_back(substring.substr(1)); else elems.push_back(substring); substring.clear(); } else substring += c; } if(substring != "") throw Invalid_Algorithm_Name(namex); return elems; } /************************************************* * Split the string on slashes * *************************************************/ std::vector split_on(const std::string& str, char delim) { std::vector elems; if(str == "") return elems; std::string substr; for(std::string::const_iterator j = str.begin(); j != str.end(); ++j) { if(*j == delim) { if(substr != "") elems.push_back(substr); substr.clear(); } else substr += *j; } if(substr == "") throw Format_Error("Unable to split string: " + str); elems.push_back(substr); return elems; } /************************************************* * Parse an ASN.1 OID string * *************************************************/ std::vector parse_asn1_oid(const std::string& oid) { std::string substring; std::vector oid_elems; for(std::string::const_iterator j = oid.begin(); j != oid.end(); ++j) { char c = *j; if(c == '.') { if(substring == "") throw Invalid_OID(oid); oid_elems.push_back(to_u32bit(substring)); substring.clear(); } else substring += c; } if(substring == "") throw Invalid_OID(oid); oid_elems.push_back(to_u32bit(substring)); if(oid_elems.size() < 2) throw Invalid_OID(oid); return oid_elems; } /************************************************* * X.500 String Comparison * *************************************************/ bool x500_name_cmp(const std::string& name1, const std::string& name2) { std::string::const_iterator p1 = name1.begin(); std::string::const_iterator p2 = name2.begin(); while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; while(p1 != name1.end() && p2 != name2.end()) { if(Charset::is_space(*p1)) { if(!Charset::is_space(*p2)) return false; while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; if(p1 == name1.end() && p2 == name2.end()) return true; } if(!Charset::caseless_cmp(*p1, *p2)) return false; ++p1; ++p2; } while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; if((p1 != name1.end()) || (p2 != name2.end())) return false; return true; } /************************************************* * Parse and compute an arithmetic expression * *************************************************/ u32bit parse_expr(const std::string& expr) { const bool have_add = (expr.find('+') != std::string::npos); const bool have_mul = (expr.find('*') != std::string::npos); if(have_add) { std::vector sub_expr = split_on(expr, '+'); u32bit result = 0; for(u32bit j = 0; j != sub_expr.size(); ++j) result += parse_expr(sub_expr[j]); return result; } else if(have_mul) { std::vector sub_expr = split_on(expr, '*'); u32bit result = 1; for(u32bit j = 0; j != sub_expr.size(); ++j) result *= parse_expr(sub_expr[j]); return result; } else return to_u32bit(expr); } #endif } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/big_code.cpp0000644000175000017500000001423411305557613022441 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * BigInt Encoding/Decoding Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #ifndef BOTAN_MINIMAL_BIGINT } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE #endif namespace Botan { /************************************************* * Encode a BigInt * *************************************************/ void BigInt::encode(byte output[], const BigInt& n, Base base) { if(base == Binary) n.binary_encode(output); #ifndef BOTAN_MINIMAL_BIGINT else if(base == Hexadecimal) { SecureVector binary(n.encoded_size(Binary)); n.binary_encode(binary); for(u32bit j = 0; j != binary.size(); ++j) Hex_Encoder::encode(binary[j], output + 2*j); } #endif else if(base == Octal) { BigInt copy = n; const u32bit output_size = n.encoded_size(Octal); for(u32bit j = 0; j != output_size; ++j) { output[output_size - 1 - j] = Charset::digit2char(copy % 8); copy /= 8; } } else if(base == Decimal) { BigInt copy = n; BigInt remainder; copy.set_sign(Positive); const u32bit output_size = n.encoded_size(Decimal); for(u32bit j = 0; j != output_size; ++j) { divide(copy, 10, copy, remainder); output[output_size - 1 - j] = Charset::digit2char(remainder.word_at(0)); if(copy.is_zero()) { if(j < output_size - 1) { int extra = output_size - 1 - j; memmove(output, output + extra, output_size - extra); memset(output + output_size - extra, 0, extra); } break; } } } else throw Invalid_Argument("Unknown BigInt encoding method"); } /************************************************* * Encode a BigInt * *************************************************/ SecureVector BigInt::encode(const BigInt& n, Base base) { SecureVector output(n.encoded_size(base)); encode(output, n, base); if(base != Binary) for(u32bit j = 0; j != output.size(); ++j) if(output[j] == 0) output[j] = '0'; return output; } /************************************************* * Encode a BigInt, with leading 0s if needed * *************************************************/ SecureVector BigInt::encode_1363(const BigInt& n, u32bit bytes) { const u32bit n_bytes = n.bytes(); if(n_bytes > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); const u32bit leading_0s = bytes - n_bytes; SecureVector output(bytes); encode(output + leading_0s, n, Binary); return output; } /************************************************* * Decode a BigInt * *************************************************/ BigInt BigInt::decode(const MemoryRegion& buf, Base base) { return BigInt::decode(buf, buf.size(), base); } /************************************************* * Decode a BigInt * *************************************************/ BigInt BigInt::decode(const byte buf[], u32bit length, Base base) { BigInt r; if(base == Binary) r.binary_decode(buf, length); #ifndef BOTAN_MINIMAL_BIGINT else if(base == Hexadecimal) { SecureVector hex; for(u32bit j = 0; j != length; ++j) if(Hex_Decoder::is_valid(buf[j])) hex.append(buf[j]); u32bit offset = (hex.size() % 2); SecureVector binary(hex.size() / 2 + offset); if(offset) { byte temp[2] = { '0', hex[0] }; binary[0] = Hex_Decoder::decode(temp); } for(u32bit j = offset; j != binary.size(); ++j) binary[j] = Hex_Decoder::decode(hex+2*j-offset); r.binary_decode(binary, binary.size()); } #endif else if(base == Decimal || base == Octal) { const u32bit RADIX = ((base == Decimal) ? 10 : 8); for(u32bit j = 0; j != length; ++j) { byte x = Charset::char2digit(buf[j]); if(x >= RADIX) { if(RADIX == 10) throw Invalid_Argument("BigInt: Invalid decimal string"); else throw Invalid_Argument("BigInt: Invalid octal string"); } r *= RADIX; r += x; } } else throw Invalid_Argument("Unknown BigInt decoding method"); return r; } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/botan/ml_win32/0000755000175000017500000000000011305557613021630 5ustar janjanpsi-0.14/third-party/qca/qca/src/botantools/botan/ml_win32/mlock.cpp0000644000175000017500000000422411305557613023443 0ustar janjan/* Copyright (C) 1999-2007 The Botan Project. All rights reserved. Redistribution and use in source and binary forms, for any use, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // LICENSEHEADER_END namespace QCA { // WRAPNS_LINE /************************************************* * Memory Locking Functions Source File * * (C) 1999-2007 The Botan Project * *************************************************/ } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE } // WRAPNS_LINE #include namespace QCA { // WRAPNS_LINE namespace Botan { /************************************************* * Lock an area of memory into RAM * *************************************************/ void lock_mem(void* ptr, u32bit bytes) { VirtualLock(ptr, bytes); } /************************************************* * Unlock a previously locked region of memory * *************************************************/ void unlock_mem(void* ptr, u32bit bytes) { VirtualUnlock(ptr, bytes); } } } // WRAPNS_LINE psi-0.14/third-party/qca/qca/src/botantools/addlicenseheaders.sh0000755000175000017500000000036111305557613023061 0ustar janjan#!/bin/sh for f in `find botan -name \*.cpp -o -name \*.h` ; do echo "/*" > file.tmp cat botan/license.txt >> file.tmp echo "*/" >> file.tmp echo "// LICENSEHEADER_END" >> file.tmp cat $f >> file.tmp cp file.tmp $f rm file.tmp done psi-0.14/third-party/qca/qca/src/botantools/README0000644000175000017500000000471211305557613017757 0ustar janjanBotantools 1.6.2 ---------------- Botan is written by Jack Lloyd and available at http://botan.randombit.net/ Description (from the website) : Botan is a library, written in C++. It's main purpose it to provide an easy to use, high level interface to various cryptographic primitives, such as block ciphers, hash functions, and public key algorithms. In addition, the intent is that Botan is as general purpose as possible, and for this reason, it supports many standards and de-facto standards. "Botantools" is a subset of Botan, tailored for use with QCA. It includes only the memory allocation, memory locking, and big integer capabilities. To use it, just include botantools.pri in your qmake profile, and botantools.h in your code. The 'botan' subfolder consists of files just from Botan. Inside are source files (originally from Botan's 'src' folder) as well as some modules (from 'modules'). The further 'botan' subfolder contains headers (from 'include' and modules). Some files had to be modified, and botantools.diff contains the differences. Also, license headers and namespace declarations were added to all source files, but I don't count these as real modifications, and they are not included in the diff. The addlicenseheaders.sh script can be used to apply the license headers. To apply the namespace declarations, build wrapns.c and use the addnamespace.sh script. Files used: '*' indicates modification doc/license.txt include/allocate.h * include/bigint.h include/bit_ops.h * include/charset.h include/defalloc.h include/exceptn.h * include/libstate.h include/mem_ops.h include/mem_pool.h * include/modules.h include/mp_asm.h include/mp_asmi.h include/mp_core.h include/mp_types.h include/mutex.h * include/numthry.h * include/parsing.h include/secmem.h include/stl_util.h * include/types.h * include/util.h modules/alloc_mmap/mmap_mem.h modules/alloc_mmap/mmap_mem.cpp modules/ml_unix/mlock.cpp modules/ml_win32/mlock.cpp modules/mux_qt/mux_qt.h * modules/mux_qt/mux_qt.cpp src/big_base.cpp * src/big_code.cpp * src/big_io.cpp src/big_ops2.cpp src/big_ops3.cpp src/bit_ops.cpp * src/charset.cpp src/defalloc.cpp src/divide.cpp src/exceptn.cpp * src/libstate.cpp * src/mem_pool.cpp * src/modules.cpp * src/mp_asm.cpp src/mp_comba.cpp src/mp_misc.cpp src/mp_mul.cpp src/mp_mulop.cpp src/mp_shift.cpp src/mutex.cpp * src/parsing.cpp * src/util.cpp psi-0.14/third-party/qca/qca/src/botantools/wrapns.c0000644000175000017500000001070111305557613020550 0ustar janjan/* Copyright (C) 2006 Justin Karneges Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include static char *read_file(const char *fname) { FILE *f; char *buf; int size; f = fopen(fname, "r"); if(!f) return 0; fseek(f, 0l, SEEK_END); size = ftell(f); rewind(f); buf = malloc(size + 1); if(!buf) { fclose(f); return 0; } fread(buf, size, 1, f); buf[size] = 0; fclose(f); return buf; } static void write_file(const char *fname, const char *buf) { FILE *f; f = fopen(fname, "w"); fwrite(buf, strlen(buf), 1, f); fclose(f); } static char *insert_string(char *buf, char *str, int at) { int bsize, slen; bsize = strlen(buf) + 1; slen = strlen(str); buf = realloc(buf, bsize + slen); if(!buf) return 0; memmove(buf + at + slen, buf + at, bsize - at); memcpy(buf + at, str, slen); return buf; } static int is_include(const char *buf) { char *p, *sub; int len; if(buf[0] != '#') return 0; p = strchr(buf, '\n'); if(!p) return 0; // take the substring ++buf; len = p - buf; sub = malloc(len + 1); memcpy(sub, buf, len); sub[len] = 0; if(strstr(sub, "include")) { free(sub); return 1; } free(sub); return 0; } static const char *find_include(const char *buf) { const char *p = buf; if(p[0] == '#') { if(is_include(p)) return p; } while(1) { p = strstr(p, "\n#"); if(!p) break; ++p; if(is_include(p)) return p; } return 0; } static const char *find_std(const char *buf) { const char *p; p = strstr(buf, "namespace std"); return p; } static const char *skip_to_next_curly(const char *buf) { int n; for(n = 0; buf[n]; ++n) { if(buf[n] == '{' || buf[n] == '}') return (buf + n); } return 0; } static const char *skip_over_curlies(const char *buf) { const char *p; int opened; p = strchr(buf, '{'); if(!p) return buf; ++p; opened = 1; while(opened) { p = skip_to_next_curly(p); if(!p) return 0; if(*p == '{') ++opened; else if(*p == '}') --opened; ++p; } return p; } void do_it(char *buf, char *ns) { char str[256], str_end[256]; const char *p, *p2; int slen, slen_end; int at; sprintf(str, "namespace %s { // WRAPNS_LINE\n", ns); slen = strlen(str); sprintf(str_end, "} // WRAPNS_LINE\n", ns); slen_end = strlen(str_end); at = 0; while(1) { // make sure there is a line left p = strchr(buf + at, '\n'); if(!p) break; // open the namespace buf = insert_string(buf, str, at); at += slen; // find an #include, "namespace std", or the end int f = 0; p = find_include(buf + at); p2 = find_std(buf + at); if(p && (!p2 || p < p2)) { f = 1; } else if(p2) { f = 2; p = p2; } if(f == 0) { // point to the end at = strlen(buf); } else if(f == 1) { printf("found include\n"); at = p - buf; } else if(f == 2) { printf("found std\n"); at = p - buf; } // close it buf = insert_string(buf, str_end, at); at += slen_end; if(f == 1) { // go to next line p = strchr(buf + at, '\n'); if(!p) break; at = p - buf + 1; } else if(f == 2) { p = skip_over_curlies(buf + at); if(!p) break; at = p - buf; // go to next line p = strchr(buf + at, '\n'); if(!p) break; at = p - buf + 1; } } } int main(int argc, char **argv) { char *buf; if(argc < 3) { printf("usage: wrapns [file] [namespace]\n\n"); return 1; } buf = read_file(argv[1]); do_it(buf, argv[2]); write_file(argv[1], buf); free(buf); return 0; } psi-0.14/third-party/qca/qca/src/botantools/botantools.diff0000644000175000017500000010404011305557613022110 0ustar janjandiff -ur a/include/bigint.h b/include/bigint.h --- a/include/bigint.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/bigint.h 2007-06-26 11:31:40.000000000 -0700 @@ -6,7 +6,13 @@ #ifndef BOTAN_BIGINT_H__ #define BOTAN_BIGINT_H__ -#include +#ifdef BOTAN_MINIMAL_BIGINT +# include +# include +#else +# include +#endif + #include #include @@ -82,7 +88,9 @@ word operator[](u32bit index) const { return reg[index]; } void clear() { reg.clear(); } +#ifndef BOTAN_MINIMAL_BIGINT void randomize(u32bit = 0); +#endif void binary_encode(byte[]) const; void binary_decode(const byte[], u32bit); @@ -102,7 +110,9 @@ BigInt(const std::string&); BigInt(const byte[], u32bit, Base = Binary); BigInt(Sign, u32bit); +#ifndef BOTAN_MINIMAL_BIGINT BigInt(NumberType, u32bit); +#endif private: void grow_to(u32bit) const; SecureVector reg; @@ -140,15 +150,19 @@ /************************************************* * I/O Operators * *************************************************/ +#ifndef BOTAN_MINIMAL_BIGINT std::ostream& operator<<(std::ostream&, const BigInt&); std::istream& operator>>(std::istream&, BigInt&); +#endif } +#ifndef BOTAN_MINIMAL_BIGINT namespace std { inline void swap(Botan::BigInt& a, Botan::BigInt& b) { a.swap(b); } } +#endif #endif diff -ur a/include/charset.h b/include/charset.h --- a/include/charset.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/charset.h 2007-06-26 11:31:40.000000000 -0700 @@ -7,7 +7,9 @@ #define BOTAN_CHARSET_H__ #include +#ifndef BOTAN_TOOLS_ONLY #include +#endif #include namespace Botan { @@ -15,6 +17,7 @@ /************************************************* * Character Set Transcoder Interface * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY class Charset_Transcoder { public: @@ -23,13 +26,16 @@ virtual ~Charset_Transcoder() {} }; +#endif namespace Charset { /************************************************* * Character Set Handling * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY std::string transcode(const std::string&, Character_Set, Character_Set); +#endif bool is_digit(char); bool is_space(char); diff -ur a/include/libstate.h b/include/libstate.h --- a/include/libstate.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/libstate.h 2007-06-26 11:31:40.000000000 -0700 @@ -6,9 +6,13 @@ #ifndef BOTAN_LIB_STATE_H__ #define BOTAN_LIB_STATE_H__ +#ifdef BOTAN_TOOLS_ONLY +#include +#else #include #include #include +#endif #include #include #include @@ -21,6 +25,7 @@ class Library_State { public: +#ifndef BOTAN_TOOLS_ONLY class Engine_Iterator { public: @@ -38,11 +43,18 @@ virtual void pulse(Pulse_Type) {} virtual ~UI() {} }; +#endif + int prealloc_size; Allocator* get_allocator(const std::string& = "") const; void add_allocator(Allocator*); +#ifdef BOTAN_TOOLS_ONLY + void set_default_allocator(const std::string&); +#else void set_default_allocator(const std::string&) const; +#endif +#ifndef BOTAN_TOOLS_ONLY bool rng_is_seeded() const { return rng->is_seeded(); } void randomize(byte[], u32bit); @@ -51,19 +63,23 @@ void add_entropy(const byte[], u32bit); void add_entropy(EntropySource&, bool); u32bit seed_prng(bool, u32bit); +#endif void load(class Modules&); +#ifndef BOTAN_TOOLS_ONLY void set_timer(class Timer*); u64bit system_clock() const; class Config& config() const; void add_engine(class Engine*); +#endif class Mutex* get_mutex() const; class Mutex* get_named_mutex(const std::string&); +#ifndef BOTAN_TOOLS_ONLY void set_x509_state(class X509_GlobalState*); class X509_GlobalState& x509_state(); @@ -73,6 +89,7 @@ void set_transcoder(class Charset_Transcoder*); std::string transcode(const std::string, Character_Set, Character_Set) const; +#endif Library_State(class Mutex_Factory*); ~Library_State(); @@ -80,23 +97,34 @@ Library_State(const Library_State&) {} Library_State& operator=(const Library_State&) { return (*this); } +#ifndef BOTAN_TOOLS_ONLY class Engine* get_engine_n(u32bit) const; +#endif class Mutex_Factory* mutex_factory; +#ifndef BOTAN_TOOLS_ONLY class Timer* timer; class Config* config_obj; class X509_GlobalState* x509_state_obj; +#endif std::map locks; std::map alloc_factory; mutable Allocator* cached_default_allocator; +#ifdef BOTAN_TOOLS_ONLY + std::string default_allocator_type; +#endif +#ifndef BOTAN_TOOLS_ONLY UI* ui; class Charset_Transcoder* transcoder; RandomNumberGenerator* rng; +#endif std::vector allocators; +#ifndef BOTAN_TOOLS_ONLY std::vector entropy_sources; std::vector engines; +#endif }; /************************************************* diff -ur a/include/mem_ops.h b/include/mem_ops.h --- a/include/mem_ops.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/mem_ops.h 2007-06-26 11:31:40.000000000 -0700 @@ -8,6 +8,7 @@ #include #include +#include namespace Botan { @@ -15,16 +16,16 @@ * Memory Manipulation Functions * *************************************************/ template inline void copy_mem(T* out, const T* in, u32bit n) - { std::memmove(out, in, sizeof(T)*n); } + { memmove(out, in, sizeof(T)*n); } template inline void clear_mem(T* ptr, u32bit n) - { std::memset(ptr, 0, sizeof(T)*n); } + { memset(ptr, 0, sizeof(T)*n); } template inline void set_mem(T* ptr, u32bit n, byte val) - { std::memset(ptr, val, sizeof(T)*n); } + { memset(ptr, val, sizeof(T)*n); } template inline bool same_mem(const T* p1, const T* p2, u32bit n) - { return (std::memcmp(p1, p2, sizeof(T)*n) == 0); } + { return (memcmp(p1, p2, sizeof(T)*n) == 0); } } diff -ur a/include/mem_pool.h b/include/mem_pool.h --- a/include/mem_pool.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/mem_pool.h 2007-06-26 11:31:40.000000000 -0700 @@ -46,13 +46,17 @@ byte* alloc(u32bit) throw(); void free(void*, u32bit) throw(); - bool operator<(const void*) const; bool operator<(const Memory_Block& other) const - { return (buffer < other.buffer); } + { + if(buffer < other.buffer && other.buffer < buffer_end) + return false; + return (buffer < other.buffer); + } + private: typedef u64bit bitmap_type; - static const u32bit BITMAP_SIZE = 8 * sizeof(bitmap_type); - static const u32bit BLOCK_SIZE = 64; + static const u32bit BITMAP_SIZE; + static const u32bit BLOCK_SIZE; bitmap_type bitmap; byte* buffer, *buffer_end; Only in b/include: mmap_mem.h diff -ur a/include/modules.h b/include/modules.h --- a/include/modules.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/modules.h 2007-06-26 11:31:40.000000000 -0700 @@ -6,7 +6,9 @@ #ifndef BOTAN_MODULE_FACTORIES_H__ #define BOTAN_MODULE_FACTORIES_H__ +#ifndef BOTAN_TOOLS_ONLY #include +#endif #include #include @@ -19,14 +21,18 @@ { public: virtual class Mutex_Factory* mutex_factory() const = 0; +#ifndef BOTAN_TOOLS_ONLY virtual class Timer* timer() const = 0; virtual class Charset_Transcoder* transcoder() const = 0; +#endif virtual std::string default_allocator() const = 0; virtual std::vector allocators() const = 0; +#ifndef BOTAN_TOOLS_ONLY virtual std::vector entropy_sources() const = 0; virtual std::vector engines() const = 0; +#endif virtual ~Modules() {} }; @@ -38,18 +44,30 @@ { public: class Mutex_Factory* mutex_factory() const; +#ifndef BOTAN_TOOLS_ONLY class Timer* timer() const; class Charset_Transcoder* transcoder() const; +#endif std::string default_allocator() const; std::vector allocators() const; +#ifndef BOTAN_TOOLS_ONLY std::vector entropy_sources() const; std::vector engines() const; +#endif +#ifdef BOTAN_TOOLS_ONLY + Builtin_Modules(); +#else Builtin_Modules(const InitializerOptions&); +#endif private: +#ifdef BOTAN_TOOLS_ONLY + const bool should_lock; +#else const bool should_lock, use_engines; +#endif }; } diff -ur a/include/mutex.h b/include/mutex.h --- a/include/mutex.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/mutex.h 2007-06-26 11:31:40.000000000 -0700 @@ -55,6 +55,7 @@ /************************************************* * Named Mutex Holder * *************************************************/ +#ifndef BOTAN_NO_LIBSTATE class Named_Mutex_Holder { public: @@ -63,6 +64,7 @@ private: const std::string mutex_name; }; +#endif } Only in b/include: mux_qt.h diff -ur a/include/numthry.h b/include/numthry.h --- a/include/numthry.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/numthry.h 2007-06-26 11:31:40.000000000 -0700 @@ -7,11 +7,14 @@ #define BOTAN_NUMBTHRY_H__ #include +#ifndef BOTAN_MINIMAL_BIGINT #include #include +#endif namespace Botan { +#ifndef BOTAN_MINIMAL_BIGINT /************************************************* * Fused Arithmetic Operations * *************************************************/ @@ -22,9 +25,11 @@ * Number Theory Functions * *************************************************/ inline BigInt abs(const BigInt& n) { return n.abs(); } +#endif void divide(const BigInt&, const BigInt&, BigInt&, BigInt&); +#ifndef BOTAN_MINIMAL_BIGINT BigInt gcd(const BigInt&, const BigInt&); BigInt lcm(const BigInt&, const BigInt&); @@ -85,6 +90,7 @@ Fixed_Exponent_Power_Mod pow_mod; Modular_Reducer reducer; }; +#endif } diff -ur a/include/parsing.h b/include/parsing.h --- a/include/parsing.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/parsing.h 2007-06-26 11:31:40.000000000 -0700 @@ -15,17 +15,21 @@ /************************************************* * String Parsing Functions * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY std::vector parse_algorithm_name(const std::string&); std::vector split_on(const std::string&, char); std::vector parse_asn1_oid(const std::string&); bool x500_name_cmp(const std::string&, const std::string&); u32bit parse_expr(const std::string&); +#endif /************************************************* * String/Integer Conversions * *************************************************/ std::string to_string(u64bit, u32bit = 0); +#ifndef BOTAN_TOOLS_ONLY u32bit to_u32bit(const std::string&); +#endif } diff -ur a/include/types.h b/include/types.h --- a/include/types.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/types.h 2007-06-26 11:31:40.000000000 -0700 @@ -6,10 +6,24 @@ #ifndef BOTAN_TYPES_H__ #define BOTAN_TYPES_H__ +#ifdef BOTAN_TYPES_QT +#include +#else #include +#endif namespace Botan { +#ifdef BOTAN_TYPES_QT + +typedef quint8 byte; +typedef quint16 u16bit; +typedef quint32 u32bit; +typedef qint32 s32bit; +typedef quint64 u64bit; + +#else + typedef unsigned char byte; typedef unsigned short u16bit; typedef unsigned int u32bit; @@ -26,6 +40,8 @@ typedef unsigned long long u64bit; #endif +#endif // BOTAN_TYPES_QT + } namespace Botan_types { diff -ur a/include/util.h b/include/util.h --- a/include/util.h 2007-03-24 11:51:37.000000000 -0700 +++ b/include/util.h 2007-06-26 11:31:40.000000000 -0700 @@ -13,8 +13,10 @@ /************************************************* * Timer Access Functions * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY u64bit system_time(); u64bit system_clock(); +#endif /************************************************* * Memory Locking Functions * @@ -27,13 +29,17 @@ *************************************************/ u32bit round_up(u32bit, u32bit); u32bit round_down(u32bit, u32bit); +#ifndef BOTAN_TOOLS_ONLY u64bit combine_timers(u32bit, u32bit, u32bit); +#endif /************************************************* * Work Factor Estimates * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY u32bit entropy_estimate(const byte[], u32bit); u32bit dl_work_factor(u32bit); +#endif } diff -ur a/modules/alloc_mmap/mmap_mem.cpp b/modules/alloc_mmap/mmap_mem.cpp --- a/modules/alloc_mmap/mmap_mem.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/modules/alloc_mmap/mmap_mem.cpp 2007-08-20 07:51:08.000000000 -0700 @@ -102,6 +102,11 @@ void MemoryMapping_Allocator::dealloc_block(void* ptr, u32bit n) { if(ptr == 0) return; +#ifdef MLOCK_NOT_VOID_PTR +# define MLOCK_TYPE_CAST (char *) +#else +# define MLOCK_TYPE_CAST +#endif const u32bit OVERWRITE_PASSES = 12; const byte PATTERNS[] = { 0x00, 0xFF, 0xAA, 0x55, 0x73, 0x8C, 0x5F, 0xA0, @@ -110,14 +115,14 @@ for(u32bit j = 0; j != OVERWRITE_PASSES; j++) { std::memset(ptr, PATTERNS[j % sizeof(PATTERNS)], n); - if(msync(ptr, n, MS_SYNC)) + if(msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) throw MemoryMapping_Failed("Sync operation failed"); } std::memset(ptr, 0, n); - if(msync(ptr, n, MS_SYNC)) + if(msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) throw MemoryMapping_Failed("Sync operation failed"); - if(munmap(ptr, n)) + if(munmap(MLOCK_TYPE_CAST ptr, n)) throw MemoryMapping_Failed("Could not unmap file"); } diff -ur a/modules/mux_qt/mux_qt.cpp b/modules/mux_qt/mux_qt.cpp --- a/modules/mux_qt/mux_qt.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/modules/mux_qt/mux_qt.cpp 2007-06-26 11:32:30.000000000 -0700 @@ -6,7 +6,7 @@ #include #include -#if !defined(QT_THREAD_SUPPORT) +#if QT_VERSION <= 0x040000 && !defined(QT_THREAD_SUPPORT) #error Your version of Qt does not support threads or mutexes #endif diff -ur a/src/big_code.cpp b/src/big_code.cpp --- a/src/big_code.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/big_code.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -6,7 +6,9 @@ #include #include #include +#ifndef BOTAN_MINIMAL_BIGINT #include +#endif namespace Botan { @@ -17,6 +19,7 @@ { if(base == Binary) n.binary_encode(output); +#ifndef BOTAN_MINIMAL_BIGINT else if(base == Hexadecimal) { SecureVector binary(n.encoded_size(Binary)); @@ -24,6 +27,7 @@ for(u32bit j = 0; j != binary.size(); ++j) Hex_Encoder::encode(binary[j], output + 2*j); } +#endif else if(base == Octal) { BigInt copy = n; @@ -46,7 +50,15 @@ output[output_size - 1 - j] = Charset::digit2char(remainder.word_at(0)); if(copy.is_zero()) + { + if(j < output_size - 1) + { + int extra = output_size - 1 - j; + memmove(output, output + extra, output_size - extra); + memset(output + output_size - extra, 0, extra); + } break; + } } } else @@ -99,6 +111,7 @@ BigInt r; if(base == Binary) r.binary_decode(buf, length); +#ifndef BOTAN_MINIMAL_BIGINT else if(base == Hexadecimal) { SecureVector hex; @@ -119,6 +132,7 @@ binary[j] = Hex_Decoder::decode(hex+2*j-offset); r.binary_decode(binary, binary.size()); } +#endif else if(base == Decimal || base == Octal) { const u32bit RADIX = ((base == Decimal) ? 10 : 8); diff -ur a/src/big_io.cpp b/src/big_io.cpp --- a/src/big_io.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/big_io.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -8,6 +8,8 @@ namespace Botan { +#ifndef BOTAN_MINIMAL_BIGINT + /************************************************* * Write the BigInt into a stream * *************************************************/ @@ -49,4 +51,6 @@ return stream; } +#endif + } diff -ur a/src/big_ops2.cpp b/src/big_ops2.cpp --- a/src/big_ops2.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/big_ops2.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -19,7 +19,11 @@ { const u32bit x_sw = sig_words(), y_sw = y.sig_words(); +#ifdef BOTAN_TYPES_QT + const u32bit reg_size = qMax(x_sw, y_sw) + 1; +#else const u32bit reg_size = std::max(x_sw, y_sw) + 1; +#endif grow_to(reg_size); if((sign() == y.sign())) @@ -56,7 +60,11 @@ s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); +#ifdef BOTAN_TYPES_QT + const u32bit reg_size = qMax(x_sw, y_sw) + 1; +#else const u32bit reg_size = std::max(x_sw, y_sw) + 1; +#endif grow_to(reg_size); if(relative_size < 0) diff -ur a/src/big_ops3.cpp b/src/big_ops3.cpp --- a/src/big_ops3.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/big_ops3.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -18,7 +18,11 @@ { const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); +#ifdef BOTAN_TYPES_QT + BigInt z(x.sign(), qMax(x_sw, y_sw) + 1); +#else BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); +#endif if((x.sign() == y.sign())) bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); @@ -49,7 +53,11 @@ s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); +#ifdef BOTAN_TYPES_QT + BigInt z(BigInt::Positive, qMax(x_sw, y_sw) + 1); +#else BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); +#endif if(relative_size < 0) { diff -ur a/src/charset.cpp b/src/charset.cpp --- a/src/charset.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/charset.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -4,10 +4,15 @@ *************************************************/ #include +#ifdef BOTAN_TOOLS_ONLY +#include +#else #include #include +#endif #include #include +#include namespace Botan { @@ -16,11 +21,13 @@ /************************************************* * Perform character set transcoding * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY std::string transcode(const std::string& str, Character_Set to, Character_Set from) { return global_state().transcode(str, to, from); } +#endif /************************************************* * Check if a character represents a digit * @@ -92,11 +99,13 @@ *************************************************/ bool caseless_cmp(char a, char b) { - return (std::tolower((unsigned char)a) == std::tolower((unsigned char)b)); + return (tolower((unsigned char)a) == tolower((unsigned char)b)); } } +#ifndef BOTAN_TOOLS_ONLY + /************************************************* * Hex Encoder Lookup Tables * *************************************************/ @@ -168,4 +177,6 @@ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; +#endif + } diff -ur a/src/defalloc.cpp b/src/defalloc.cpp --- a/src/defalloc.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/defalloc.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -8,6 +8,8 @@ #include #include #include +#include +#include namespace Botan { @@ -18,7 +20,7 @@ *************************************************/ void* do_malloc(u32bit n, bool do_lock) { - void* ptr = std::malloc(n); + void* ptr = malloc(n); if(!ptr) return 0; @@ -26,7 +28,7 @@ if(do_lock) lock_mem(ptr, n); - std::memset(ptr, 0, n); + memset(ptr, 0, n); return ptr; } @@ -38,11 +40,11 @@ if(!ptr) return; - std::memset(ptr, 0, n); + memset(ptr, 0, n); if(do_lock) unlock_mem(ptr, n); - std::free(ptr); + free(ptr); } } diff -ur a/src/libstate.cpp b/src/libstate.cpp --- a/src/libstate.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/libstate.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -4,14 +4,20 @@ *************************************************/ #include +#ifndef BOTAN_TOOLS_ONLY #include +#endif #include +#ifndef BOTAN_TOOLS_ONLY #include #include +#endif #include #include +#ifndef BOTAN_TOOLS_ONLY #include #include +#endif #include namespace Botan { @@ -56,10 +62,12 @@ /************************************************* * Increment the Engine iterator * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY Engine* Library_State::Engine_Iterator::next() { return lib.get_engine_n(n++); } +#endif /************************************************* * Get a new mutex object * @@ -92,8 +100,11 @@ if(!cached_default_allocator) { +#ifdef BOTAN_TOOLS_ONLY + std::string chosen = default_allocator_type; +#else std::string chosen = config().option("base/default_allocator"); - +#endif if(chosen == "") chosen = "malloc"; @@ -120,17 +131,26 @@ /************************************************* * Set the default allocator type * *************************************************/ +#ifdef BOTAN_TOOLS_ONLY +void Library_State::set_default_allocator(const std::string& type) +#else void Library_State::set_default_allocator(const std::string& type) const +#endif { Named_Mutex_Holder lock("allocator"); if(type == "") return; +#ifdef BOTAN_TOOLS_ONLY + default_allocator_type = type; +#else config().set("conf", "base/default_allocator", type); +#endif cached_default_allocator = 0; } +#ifndef BOTAN_TOOLS_ONLY /************************************************* * Set the high resolution clock implementation * *************************************************/ @@ -317,13 +337,17 @@ return (*config_obj); } +#endif + /************************************************* * Load modules * *************************************************/ void Library_State::load(Modules& modules) { +#ifndef BOTAN_TOOLS_ONLY set_timer(modules.timer()); set_transcoder(modules.transcoder()); +#endif std::vector mod_allocs = modules.allocators(); for(u32bit j = 0; j != mod_allocs.size(); j++) @@ -331,6 +355,7 @@ set_default_allocator(modules.default_allocator()); +#ifndef BOTAN_TOOLS_ONLY std::vector mod_engines = modules.engines(); for(u32bit j = 0; j != mod_engines.size(); ++j) { @@ -341,6 +366,7 @@ std::vector sources = modules.entropy_sources(); for(u32bit j = 0; j != sources.size(); ++j) add_entropy_source(sources[j]); +#endif } /************************************************* @@ -352,25 +378,39 @@ throw Exception("Library_State: no mutex found"); this->mutex_factory = mutex_factory; +#ifndef BOTAN_TOOLS_ONLY this->timer = new Timer(); this->transcoder = 0; this->config_obj = new Config(); +#endif +#ifndef BOTAN_TOOLS_ONLY locks["settings"] = get_mutex(); +#endif locks["allocator"] = get_mutex(); +#ifndef BOTAN_TOOLS_ONLY locks["rng"] = get_mutex(); locks["engine"] = get_mutex(); rng = 0; +#endif cached_default_allocator = 0; +#ifndef BOTAN_TOOLS_ONLY x509_state_obj = 0; ui = 0; +#endif } /************************************************* * Library_State Destructor * *************************************************/ +static void delete_lock(std::pair &pair) + { + delete pair.second; + } + Library_State::~Library_State() { +#ifndef BOTAN_TOOLS_ONLY delete x509_state_obj; delete transcoder; delete rng; @@ -381,6 +421,7 @@ std::for_each(entropy_sources.begin(), entropy_sources.end(), del_fun()); std::for_each(engines.begin(), engines.end(), del_fun()); +#endif cached_default_allocator = 0; @@ -390,8 +431,7 @@ delete allocators[j]; } - std::for_each(locks.begin(), locks.end(), - delete2nd::value_type>); + std::for_each(locks.begin(), locks.end(), delete_lock); delete mutex_factory; } diff -ur a/src/mem_pool.cpp b/src/mem_pool.cpp --- a/src/mem_pool.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/mem_pool.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -5,8 +5,12 @@ #include #include +#ifdef BOTAN_TOOLS_ONLY +#include +#else #include #include +#endif #include #include @@ -22,7 +26,11 @@ if(provided) return provided; +#ifdef BOTAN_TOOLS_ONLY + u32bit result = (u32bit)global_state().prealloc_size; +#else u32bit result = global_config().option_as_u32bit("base/memory_chunk"); +#endif if(result) return result; @@ -42,16 +50,6 @@ } /************************************************* -* Compare a Memory_Block with a void pointer * -*************************************************/ -inline bool Pooling_Allocator::Memory_Block::operator<(const void* other) const - { - if(buffer <= other && other < buffer_end) - return false; - return (buffer < other); - } - -/************************************************* * See if ptr is contained by this block * *************************************************/ bool Pooling_Allocator::Memory_Block::contains(void* ptr, @@ -207,7 +205,7 @@ const u32bit block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; std::vector::iterator i = - std::lower_bound(blocks.begin(), blocks.end(), ptr); + std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); if(i == blocks.end() || !i->contains(ptr, block_no)) throw Invalid_State("Pointer released to the wrong allocator"); @@ -270,7 +268,10 @@ } std::sort(blocks.begin(), blocks.end()); - last_used = std::lower_bound(blocks.begin(), blocks.end(), ptr); + last_used = std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); } +const u32bit Pooling_Allocator::Memory_Block::BITMAP_SIZE = 8 * sizeof(Pooling_Allocator::Memory_Block::bitmap_type); +const u32bit Pooling_Allocator::Memory_Block::BLOCK_SIZE = 64; + } diff -ur a/src/modules.cpp b/src/modules.cpp --- a/src/modules.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/modules.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -5,71 +5,77 @@ #include #include +#ifndef BOTAN_TOOLS_ONLY #include #include #include #include +#endif #if defined(BOTAN_EXT_MUTEX_PTHREAD) - #include +# include #elif defined(BOTAN_EXT_MUTEX_WIN32) - #include +# include #elif defined(BOTAN_EXT_MUTEX_QT) - #include +# include #endif #if defined(BOTAN_EXT_ALLOC_MMAP) - #include +# include #endif +#ifndef BOTAN_TOOLS_ONLY + #if defined(BOTAN_EXT_TIMER_HARDWARE) - #include +# include #elif defined(BOTAN_EXT_TIMER_POSIX) - #include +# include #elif defined(BOTAN_EXT_TIMER_UNIX) - #include +# include #elif defined(BOTAN_EXT_TIMER_WIN32) - #include +# include #endif #if defined(BOTAN_EXT_ENGINE_AEP) - #include +# include #endif #if defined(BOTAN_EXT_ENGINE_GNU_MP) - #include +# include #endif #if defined(BOTAN_EXT_ENGINE_OPENSSL) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_AEP) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_EGD) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) - #include +# include #endif #if defined(BOTAN_EXT_ENTROPY_SRC_FTW) - #include +# include +#endif + #endif namespace Botan { @@ -93,6 +99,7 @@ /************************************************* * Find a high resolution timer, if possible * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY Timer* Builtin_Modules::timer() const { #if defined(BOTAN_EXT_TIMER_HARDWARE) @@ -107,6 +114,7 @@ return new Timer; #endif } +#endif /************************************************* * Find any usable allocators * @@ -142,6 +150,8 @@ return "malloc"; } +#ifndef BOTAN_TOOLS_ONLY + /************************************************* * Register any usable entropy sources * *************************************************/ @@ -217,13 +227,22 @@ return new Default_Charset_Transcoder; } +#endif + /************************************************* * Builtin_Modules Constructor * *************************************************/ +#ifdef BOTAN_TOOLS_ONLY +Builtin_Modules::Builtin_Modules() : + should_lock(true) + { + } +#else Builtin_Modules::Builtin_Modules(const InitializerOptions& args) : should_lock(args.secure_memory()), use_engines(args.use_engines()) { } +#endif } diff -ur a/src/mp_asm.cpp b/src/mp_asm.cpp --- a/src/mp_asm.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/mp_asm.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -174,6 +174,7 @@ /************************************************* * Montgomery Reduction Algorithm * *************************************************/ +#ifndef BOTAN_MINIMAL_BIGINT void bigint_monty_redc(word z[], u32bit z_size, const word x[], u32bit x_size, word u) { @@ -199,6 +200,7 @@ if(bigint_cmp(z + x_size, x_size + 1, x, x_size) >= 0) bigint_sub2(z + x_size, x_size + 1, x, x_size); } +#endif } diff -ur a/src/mutex.cpp b/src/mutex.cpp --- a/src/mutex.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/mutex.cpp 2007-08-20 07:53:57.000000000 -0700 @@ -3,8 +3,11 @@ * (C) 1999-2007 The Botan Project * *************************************************/ +#include #include +#ifndef BOTAN_NO_LIBSTATE #include +#endif namespace Botan { @@ -26,6 +29,7 @@ mux->unlock(); } +#ifndef BOTAN_NO_LIBSTATE /************************************************* * Named_Mutex_Holder Constructor * *************************************************/ @@ -42,12 +46,17 @@ { global_state().get_named_mutex(mutex_name)->unlock(); } +#endif /************************************************* * Default Mutex Factory * *************************************************/ +#ifdef BOTAN_FIX_GDB +namespace { +#else Mutex* Default_Mutex_Factory::make() { +#endif class Default_Mutex : public Mutex { public: @@ -78,6 +87,12 @@ bool locked; }; +#ifdef BOTAN_FIX_GDB + } // end unnamed namespace +Mutex* Default_Mutex_Factory::make() + { +#endif + return new Default_Mutex; } diff -ur a/src/parsing.cpp b/src/parsing.cpp --- a/src/parsing.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/parsing.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -12,6 +12,7 @@ /************************************************* * Convert a string into an integer * *************************************************/ +#ifndef BOTAN_TOOLS_ONLY u32bit to_u32bit(const std::string& number) { u32bit n = 0; @@ -29,7 +30,7 @@ } return n; } - +#endif /************************************************* * Convert an integer into a string * @@ -54,6 +55,7 @@ return lenstr; } +#ifndef BOTAN_TOOLS_ONLY /************************************************* * Parse a SCAN-style algorithm name * *************************************************/ @@ -237,5 +239,6 @@ else return to_u32bit(expr); } +#endif } diff -ur a/src/util.cpp b/src/util.cpp --- a/src/util.cpp 2007-03-24 11:51:37.000000000 -0700 +++ b/src/util.cpp 2007-06-26 11:31:30.000000000 -0700 @@ -4,7 +4,9 @@ *************************************************/ #include +#ifndef BOTAN_TOOLS_ONLY #include +#endif #include #include @@ -28,6 +30,7 @@ return (n - (n % align_to)); } +#ifndef BOTAN_TOOLS_ONLY /************************************************* * Return the work required for solving DL * *************************************************/ @@ -77,5 +80,6 @@ return (estimate / 2); } +#endif } psi-0.14/third-party/qca/qca/src/botantools/botantools.h0000644000175000017500000000200211305557613021422 0ustar janjan/* * Copyright (C) 2004-2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #ifndef BOTANTOOLS_H #define BOTANTOOLS_H #include #include #include #include #include #include #endif psi-0.14/third-party/qca/qca/src/botantools/removeadded.sh0000755000175000017500000000025111305557613021707 0ustar janjan#!/bin/sh for f in `find botan -name \*.cpp -o -name \*.h` ; do sed -e '1,/LICENSEHEADER_END/d' $f | grep -v WRAPNS_LINE > file.tmp cp file.tmp $f rm file.tmp done psi-0.14/third-party/qca/qca/src/botantools/.krazy0000644000175000017500000000002111305557613020225 0ustar janjanIGNORESUBS botan psi-0.14/third-party/qca/qca/src/botantools/addnamespace.sh0000755000175000017500000000013011305557613022031 0ustar janjan#!/bin/sh for f in `find botan -name \*.cpp -o -name \*.h` ; do ./wrapns $f QCA done psi-0.14/third-party/qca/qca/src/botantools/botantools.pri0000644000175000017500000000217511305557613022000 0ustar janjanBOTAN_BASE = $$PWD/botan DEFINES += \ BOTAN_TYPES_QT \ BOTAN_TOOLS_ONLY \ BOTAN_FIX_GDB \ BOTAN_MINIMAL_BIGINT DEFINES += BOTAN_MP_WORD_BITS=32 DEFINES += BOTAN_KARAT_MUL_THRESHOLD=12 DEFINES += BOTAN_KARAT_SQR_THRESHOLD=12 DEFINES += BOTAN_EXT_MUTEX_QT unix:DEFINES += BOTAN_EXT_ALLOC_MMAP INCLUDEPATH += $$BOTAN_BASE SOURCES += \ $$BOTAN_BASE/util.cpp \ $$BOTAN_BASE/charset.cpp \ $$BOTAN_BASE/parsing.cpp \ $$BOTAN_BASE/exceptn.cpp \ $$BOTAN_BASE/mutex.cpp \ $$BOTAN_BASE/mux_qt/mux_qt.cpp \ $$BOTAN_BASE/defalloc.cpp \ $$BOTAN_BASE/mem_pool.cpp \ $$BOTAN_BASE/libstate.cpp \ $$BOTAN_BASE/modules.cpp \ $$BOTAN_BASE/mp_comba.cpp \ $$BOTAN_BASE/mp_mul.cpp \ $$BOTAN_BASE/mp_mulop.cpp \ $$BOTAN_BASE/mp_shift.cpp \ $$BOTAN_BASE/mp_asm.cpp \ $$BOTAN_BASE/mp_misc.cpp \ $$BOTAN_BASE/divide.cpp \ $$BOTAN_BASE/bit_ops.cpp \ $$BOTAN_BASE/big_base.cpp \ $$BOTAN_BASE/big_code.cpp \ $$BOTAN_BASE/big_io.cpp \ $$BOTAN_BASE/big_ops2.cpp \ $$BOTAN_BASE/big_ops3.cpp unix:{ SOURCES += \ $$BOTAN_BASE/ml_unix/mlock.cpp \ $$BOTAN_BASE/alloc_mmap/mmap_mem.cpp } windows:{ SOURCES += \ $$BOTAN_BASE/ml_win32/mlock.cpp } psi-0.14/third-party/qca/qca/src/support/0000755000175000017500000000000011305557613016423 5ustar janjanpsi-0.14/third-party/qca/qca/src/support/logger.cpp0000644000175000017500000000561111305557613020411 0ustar janjan/* * Copyright (C) 2007 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_support.h" namespace QCA { AbstractLogDevice::AbstractLogDevice(const QString &name, QObject *parent) : QObject( parent ), m_name( name ) { } AbstractLogDevice::~AbstractLogDevice() {} QString AbstractLogDevice::name() const { return m_name; } void AbstractLogDevice::logTextMessage( const QString &message, Logger::Severity severity ) { Q_UNUSED( message ); Q_UNUSED( severity ); } void AbstractLogDevice::logBinaryMessage( const QByteArray &blob, Logger::Severity severity ) { Q_UNUSED( blob ); Q_UNUSED( severity ); } Logger::Logger() { // d pointer? m_logLevel = Logger::Notice; } Logger::~Logger() { // delete d; } QStringList Logger::currentLogDevices() const { return m_loggerNames; } void Logger::registerLogDevice(AbstractLogDevice* logger) { m_loggers.append( logger ); m_loggerNames.append( logger->name() ); } void Logger::unregisterLogDevice(const QString &loggerName) { for ( int i = 0; i < m_loggers.size(); ++i ) { if ( m_loggers[i]->name() == loggerName ) { m_loggers.removeAt( i ); --i; // we backstep, to make sure we check the new entry in this position. } } for ( int i = 0; i < m_loggerNames.size(); ++i ) { if ( m_loggerNames[i] == loggerName ) { m_loggerNames.removeAt( i ); --i; // we backstep, to make sure we check the new entry in this position. } } } void Logger::setLevel (Severity level) { m_logLevel = level; } void Logger::logTextMessage(const QString &message, Severity severity ) { if (severity <= level ()) { for ( int i = 0; i < m_loggers.size(); ++i ) { m_loggers[i]->logTextMessage( message, severity ); } } } void Logger::logBinaryMessage(const QByteArray &blob, Severity severity ) { if (severity <= level ()) { for ( int i = 0; i < m_loggers.size(); ++i ) { m_loggers[i]->logBinaryMessage( blob, severity ); } } } } psi-0.14/third-party/qca/qca/src/support/qpipe.cpp0000644000175000017500000011612211305557613020250 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ // Note: if we ever enable the threaded backend, we need to protect: // QPipeDevice read and bytesAvailable // QPipeEnd finalize // Note: we never use the return value for QPipeWriter::stop, but I don't // think this matters much #include "qpipe.h" #include #include // sorry, i've added this dependency for now, but it's easy enough to take // with you if you want qpipe independent of qca #include "qca_safeobj.h" #ifdef Q_OS_WIN # include # include # include # include # include # include #else # include #endif #ifdef Q_OS_UNIX # include # include # include # include # include # ifdef HAVE_SYS_FILIO_H # include # endif #endif #define USE_POLL #define CONSOLE_CHAREXPAND 5 #define PIPEWRITER_POLL 1000 #define PIPEREADER_POLL 100 #define PIPEWRITER_BLOCK 8192 #define PIPEEND_BLOCK 8192 #define PIPEEND_READBUF 16384 #define PIPEEND_READBUF_SEC 1024 namespace QCA { #ifdef Q_OS_UNIX // adapted from qt Q_GLOBAL_STATIC(QMutex, ign_mutex) static bool ign_sigpipe = false; static void ignore_sigpipe() { // Set to ignore SIGPIPE once only. //#if QT_VERSION < 0x040400 QMutexLocker locker(ign_mutex()); if(!ign_sigpipe) { ign_sigpipe = true; //#else // static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); // if(atom.testAndSetRelaxed(0, 1)) // { //#endif struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &noaction, 0); } } #endif #ifdef Q_OS_WIN static int pipe_dword_cap_to_int(DWORD dw) { if(sizeof(int) <= sizeof(DWORD)) return (int)((dw > INT_MAX) ? INT_MAX : dw); else return (int)dw; } static bool pipe_dword_overflows_int(DWORD dw) { if(sizeof(int) <= sizeof(DWORD)) return (dw > INT_MAX) ? true : false; else return false; } #endif #ifdef Q_OS_UNIX static int pipe_size_t_cap_to_int(size_t size) { if(sizeof(int) <= sizeof(size_t)) return (int)((size > INT_MAX) ? INT_MAX : size); else // maybe silly.. can int ever be larger than size_t? return (int)size; } #endif static bool pipe_set_blocking(Q_PIPE_ID pipe, bool b) { #ifdef Q_OS_WIN DWORD flags = 0; if(!b) flags |= PIPE_NOWAIT; if(!SetNamedPipeHandleState(pipe, &flags, NULL, NULL)) return false; return true; #endif #ifdef Q_OS_UNIX int flags = fcntl(pipe, F_GETFL); if(!b) flags |= O_NONBLOCK; else flags &= ~O_NONBLOCK; if(fcntl(pipe, F_SETFL, flags) == -1) return false; return true; #endif } // on windows, the pipe is closed and the new pipe is returned in newPipe static bool pipe_set_inheritable(Q_PIPE_ID pipe, bool b, Q_PIPE_ID *newPipe = 0) { #ifdef Q_OS_WIN // windows is required to accept a new pipe id if(!newPipe) return false; HANDLE h; if(!DuplicateHandle(GetCurrentProcess(), pipe, GetCurrentProcess(), &h, 0, b, DUPLICATE_SAME_ACCESS)) return false; *newPipe = h; return true; #endif #ifdef Q_OS_UNIX if(newPipe) *newPipe = pipe; int flags = fcntl(pipe, F_GETFD); if(!b) flags |= FD_CLOEXEC; else flags &= ~FD_CLOEXEC; if(fcntl(pipe, F_SETFD, flags) == -1) return false; return true; #endif } // returns number of bytes available static int pipe_read_avail(Q_PIPE_ID pipe) { int bytesAvail = 0; #ifdef Q_OS_WIN DWORD i = 0; if(PeekNamedPipe(pipe, 0, 0, 0, &i, 0)) bytesAvail = pipe_dword_cap_to_int(i); #endif #ifdef Q_OS_UNIX size_t nbytes = 0; if(ioctl(pipe, FIONREAD, (char *)&nbytes) >= 0) bytesAvail = pipe_size_t_cap_to_int(nbytes); #endif return bytesAvail; } // returns number of bytes actually read, no more than 'max'. // -1 on error. 0 means no data, NOT EOF. // note: even though this function looks like it can return data and EOF // at the same time, it never actually does. static int pipe_read(Q_PIPE_ID pipe, char *data, int max, bool *eof) { int bytesRead = 0; if(eof) *eof = false; if(max < 1) return 0; #ifdef Q_OS_WIN DWORD maxread = max; DWORD r = 0; if(!ReadFile(pipe, data, maxread, &r, 0)) { DWORD err = GetLastError(); if(err == ERROR_HANDLE_EOF) { if(eof) *eof = true; } else if(err == ERROR_NO_DATA) { r = 0; } else return -1; } bytesRead = (int)r; // safe to cast, since 'max' is signed #endif #ifdef Q_OS_UNIX int r = 0; int ret = read(pipe, data, max); if(ret == -1) { if(errno != EAGAIN) return -1; } else if(ret == 0) { if(eof) *eof = true; } else r = ret; bytesRead = r; #endif return bytesRead; } // returns number of bytes actually written. // for blocking pipes, this should always be 'size'. // -1 on error. static int pipe_write(Q_PIPE_ID pipe, const char *data, int size) { #ifdef Q_OS_WIN DWORD written; if(!WriteFile(pipe, data, size, &written, 0)) return -1; return (int)written; // safe to cast, since 'size' is signed #endif #ifdef Q_OS_UNIX ignore_sigpipe(); int r = 0; int ret = write(pipe, data, size); if(ret == -1) { if(errno != EAGAIN) return -1; } else r = ret; return r; #endif } // Windows Console functions #ifdef Q_OS_WIN static bool pipe_is_a_console(Q_PIPE_ID pipe) { DWORD mode; if(GetConsoleMode(pipe, &mode)) return true; return false; } // returns the number of keypress events in the console input queue, // or -1 if there is an error (don't forget this!!) static int pipe_read_avail_console(Q_PIPE_ID pipe) { DWORD count, i; INPUT_RECORD *rec; int n, icount, total; // how many events are there? if(!GetNumberOfConsoleInputEvents(pipe, &count)) return -1; // peek them all rec = (INPUT_RECORD *)malloc(count * sizeof(INPUT_RECORD)); BOOL ret; QT_WA( ret = PeekConsoleInputW(pipe, rec, count, &i); , ret = PeekConsoleInputA(pipe, rec, count, &i); ) if(!ret) { free(rec); return -1; } icount = pipe_dword_cap_to_int(i); // process only the amount returned // see which ones are normal keypress events total = 0; for(n = 0; n < icount; ++n) { if(rec[n].EventType == KEY_EVENT) { KEY_EVENT_RECORD *ke = &rec[n].Event.KeyEvent; if(ke->bKeyDown && ke->uChar.AsciiChar != 0) total += ke->wRepeatCount; } } free(rec); return total; } // pass dec to keep a long-running decoder, else 0 static int pipe_read_console(Q_PIPE_ID pipe, ushort *data, int max, bool *eof, QTextDecoder *dec = 0) { int n, size, count; bool own_decoder; if(eof) *eof = false; if(max < 1) return 0; count = pipe_read_avail_console(pipe); if(count == -1) return -1; if(count == 0) return 0; if(dec) { own_decoder = false; } else { QT_WA( dec = 0; , dec = QTextCodec::codecForLocale()->makeDecoder(); ) own_decoder = true; } size = 0; for(n = 0; n < count && size < max; ++n) { bool use_uni = true; quint16 uni = 0; quint8 ansi = 0; BOOL ret; DWORD i; QT_WA( ret = ReadConsoleW(pipe, &uni, 1, &i, NULL); , ret = ReadConsoleA(pipe, &ansi, 1, &i, NULL); use_uni = false; ) if(!ret) { // if the first read is an error, then report error if(n == 0) { delete dec; return -1; } // if we have some data, don't count this as an error. // we'll probably get it again next time around... else break; } QString substr; if(use_uni) substr = QChar(uni); else substr = dec->toUnicode((const char *)&ansi, 1); for(int k = 0; k < substr.length() && size < max; ++k) { QChar c = substr[k]; if(c == QChar(0x1A)) // EOF? { if(eof) *eof = true; break; } data[size++] = substr[k].unicode(); } } if(own_decoder) delete dec; return size; } static int pipe_write_console(Q_PIPE_ID pipe, const ushort *data, int size) { DWORD i; BOOL ret; QT_WA( ret = WriteConsoleW(pipe, data, size, &i, NULL); , // Note: we lose security by converting to QString here, but // who really cares if we're writing to a *display* ? :) QByteArray out = QString::fromUtf16(data, size).toLocal8Bit(); ret = WriteConsoleA(pipe, out.data(), out.size(), &i, NULL); if(ret) { // convert number of bytes to number of unicode chars i = (DWORD)QString::fromLocal8Bit(out.mid(0, i)).length(); if(pipe_dword_overflows_int(i)) return -1; } ) if(!ret) return -1; return (int)i; // safe to cast since 'size' is signed } #endif #ifdef Q_OS_WIN // Here is the multi-backend stuff for windows. QPipeWriter and QPipeReader // define a common interface, and then subclasses (like QPipeWriterThread) // are used by QPipeDevice. The base classes inherit from QThread, even // if threads aren't used, so that I can define signals without dealing // with multiple QObject inheritance in the thread subclasses (it is also // possible that I'm missing something obvious and don't need to do this). // Note: // QPipeWriterThread and QPipeReaderThread require the pipes to be in // blocking mode. QPipeWriterPoll and QPipeReaderPoll require the pipes // to be in non-blocking mode. //---------------------------------------------------------------------------- // QPipeWriter //---------------------------------------------------------------------------- class QPipeWriter : public QThread { Q_OBJECT public: QPipeWriter(QObject *parent = 0) : QThread(parent) { } virtual ~QPipeWriter() { } // start virtual void start() = 0; // stop, and return number of bytes written so far virtual int stop() = 0; // data pointer needs to remain until canWrite is emitted virtual int write(const char *data, int size) = 0; signals: // result values: // = 0 : success // = -1 : error void canWrite(int result, int bytesWritten); protected: virtual void run() { // implement a default to satisfy the polling subclass } }; //---------------------------------------------------------------------------- // QPipeReader //---------------------------------------------------------------------------- class QPipeReader : public QThread { Q_OBJECT public: QPipeReader(QObject *parent = 0) : QThread(parent) { } virtual ~QPipeReader() { } // start virtual void start() = 0; // to be called after every read virtual void resume() = 0; signals: // result values: // >= 0 : readAhead // = -1 : atEnd // = -2 : atError // = -3 : data available, but no readAhead void canRead(int result); protected: virtual void run() { // implement a default to satisfy the polling subclass } }; //---------------------------------------------------------------------------- // QPipeWriterThread //---------------------------------------------------------------------------- class QPipeWriterThread : public QPipeWriter { Q_OBJECT public: Q_PIPE_ID pipe; QMutex m; QWaitCondition w; bool do_quit; const char *data; int size; QPipeWriterThread(Q_PIPE_ID id, QObject *parent = 0) : QPipeWriter(parent) { do_quit = false; data = 0; connect(this, SIGNAL(canWrite_p(int, int)), SIGNAL(canWrite(int, int))); DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS); } virtual ~QPipeWriterThread() { stop(); CloseHandle(pipe); } virtual void start() { pipe_set_blocking(pipe, true); QThread::start(); } virtual int stop() { if(isRunning()) { m.lock(); do_quit = true; w.wakeOne(); m.unlock(); if(!wait(100)) terminate(); do_quit = false; data = 0; } return size; } virtual int write(const char *_data, int _size) { if(!isRunning()) return -1; QMutexLocker locker(&m); if(data) return 0; data = _data; size = _size; w.wakeOne(); return _size; } protected: virtual void run() { while(1) { m.lock(); while(!data && !do_quit) w.wait(&m); if(do_quit) { m.unlock(); break; } const char *p = data; int len = size; m.unlock(); int ret = internalWrite(p, len); m.lock(); data = 0; size = ret; m.unlock(); emit canWrite_p(ret < len ? -1 : 0, ret); } } private: // attempts to write len bytes. value returned is number of bytes written. // any return value less than len means a write error was encountered int internalWrite(const char *p, int len) { int total = 0; while(total < len) { m.lock(); if(do_quit) { m.unlock(); return 0; } m.unlock(); int ret = pipe_write(pipe, p + total, qMin(PIPEWRITER_BLOCK, len - total)); if(ret == -1) { // from qt, don't know why if(GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER { // give the os a rest msleep(100); continue; } // on any other error, end thread return total; } total += ret; } return total; } signals: void canWrite_p(int result, int bytesWritten); }; //---------------------------------------------------------------------------- // QPipeWriterPoll //---------------------------------------------------------------------------- class QPipeWriterPoll : public QPipeWriter { Q_OBJECT public: Q_PIPE_ID pipe; const char *data; int size; SafeTimer timer; int total; QPipeWriterPoll(Q_PIPE_ID id, QObject *parent = 0) : QPipeWriter(parent), timer(this) { pipe = id; data = 0; connect(&timer, SIGNAL(timeout()), SLOT(tryNextWrite())); } virtual ~QPipeWriterPoll() { } virtual void start() { pipe_set_blocking(pipe, false); } // return number of bytes written virtual int stop() { timer.stop(); data = 0; return total; } // data pointer needs to remain until canWrite is emitted virtual int write(const char *_data, int _size) { total = 0; data = _data; size = _size; timer.start(0); // write at next event loop return _size; } private slots: void tryNextWrite() { int written = pipe_write(pipe, data + total, size - total); bool error = false; if(written == -1) { error = true; written = 0; // no bytes written on error // from qt, they don't count it as fatal if(GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER error = false; } total += written; if(error || total == size) { timer.stop(); data = 0; emit canWrite(error ? -1 : 0, total); return; } timer.setInterval(PIPEWRITER_POLL); } }; //---------------------------------------------------------------------------- // QPipeReaderThread //---------------------------------------------------------------------------- class QPipeReaderThread : public QPipeReader { Q_OBJECT public: Q_PIPE_ID pipe; QMutex m; QWaitCondition w; bool do_quit, active; QPipeReaderThread(Q_PIPE_ID id, QObject *parent = 0) : QPipeReader(parent) { do_quit = false; active = true; connect(this, SIGNAL(canRead_p(int)), SIGNAL(canRead(int))); DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS); } virtual ~QPipeReaderThread() { if(isRunning()) { m.lock(); do_quit = true; w.wakeOne(); m.unlock(); if(!wait(100)) terminate(); } CloseHandle(pipe); } virtual void start() { pipe_set_blocking(pipe, true); QThread::start(); } virtual void resume() { QMutexLocker locker(&m); pipe_set_blocking(pipe, true); active = true; w.wakeOne(); } protected: virtual void run() { while(1) { m.lock(); while(!active && !do_quit) w.wait(&m); if(do_quit) { m.unlock(); break; } m.unlock(); while(1) { unsigned char c; bool done; int ret = pipe_read(pipe, (char *)&c, 1, &done); if(done || ret != 0) // eof, error, or data? { int result; if(done) // we got EOF? result = -1; else if(ret == -1) // we got an error? result = -2; else if(ret >= 1) // we got some data?? queue it result = c; else // will never happen result = -2; m.lock(); active = false; pipe_set_blocking(pipe, false); m.unlock(); emit canRead_p(result); break; } } } } signals: void canRead_p(int result); }; //---------------------------------------------------------------------------- // QPipeReaderPoll //---------------------------------------------------------------------------- class QPipeReaderPoll : public QPipeReader { Q_OBJECT public: Q_PIPE_ID pipe; SafeTimer timer; bool consoleMode; QPipeReaderPoll(Q_PIPE_ID id, QObject *parent = 0) : QPipeReader(parent), timer(this) { pipe = id; connect(&timer, SIGNAL(timeout()), SLOT(tryRead())); } virtual ~QPipeReaderPoll() { } virtual void start() { pipe_set_blocking(pipe, false); consoleMode = pipe_is_a_console(pipe); resume(); } virtual void resume() { timer.start(0); } private slots: void tryRead() { if(consoleMode) tryReadConsole(); else tryReadPipe(); } private: void tryReadPipe() { // is there data available for reading? if so, signal. int bytes = pipe_read_avail(pipe); if(bytes > 0) { timer.stop(); emit canRead(-3); // no readAhead return; } // no data available? probe for EOF/error unsigned char c; bool done; int ret = pipe_read(pipe, (char *)&c, 1, &done); if(done || ret != 0) // eof, error, or data? { int result; if(done) // we got EOF? result = -1; else if(ret == -1) // we got an error? result = -2; else if(ret >= 1) // we got some data?? queue it result = c; else // will never happen result = -2; timer.stop(); emit canRead(result); return; } timer.setInterval(PIPEREADER_POLL); } void tryReadConsole() { // is there data available for reading? if so, signal. int count = pipe_read_avail_console(pipe); if(count > 0) { timer.stop(); emit canRead(-3); // no readAhead return; } timer.setInterval(PIPEREADER_POLL); } }; // end of windows pipe writer/reader implementations #endif //---------------------------------------------------------------------------- // QPipeDevice //---------------------------------------------------------------------------- class QPipeDevice::Private : public QObject { Q_OBJECT public: QPipeDevice *q; Q_PIPE_ID pipe; QPipeDevice::Type type; bool enabled; bool blockReadNotify; bool canWrite; int writeResult; int lastTaken, lastWritten; #ifdef Q_OS_WIN bool atEnd, atError, forceNotify; int readAhead; SafeTimer *readTimer; QTextDecoder *dec; bool consoleMode; QPipeWriter *pipeWriter; QPipeReader *pipeReader; #endif #ifdef Q_OS_UNIX SafeSocketNotifier *sn_read, *sn_write; #endif Private(QPipeDevice *_q) : QObject(_q), q(_q), pipe(INVALID_Q_PIPE_ID) { #ifdef Q_OS_WIN readTimer = 0; pipeWriter = 0; pipeReader = 0; dec = 0; #endif #ifdef Q_OS_UNIX sn_read = 0; sn_write = 0; #endif } ~Private() { reset(); } void reset() { #ifdef Q_OS_WIN atEnd = false; atError = false; forceNotify = false; readAhead = -1; delete readTimer; readTimer = 0; delete pipeWriter; pipeWriter = 0; delete pipeReader; pipeReader = 0; delete dec; dec = 0; consoleMode = false; #endif #ifdef Q_OS_UNIX delete sn_read; sn_read = 0; delete sn_write; sn_write = 0; #endif if(pipe != INVALID_Q_PIPE_ID) { #ifdef Q_OS_WIN CloseHandle(pipe); #endif #ifdef Q_OS_UNIX ::close(pipe); #endif pipe = INVALID_Q_PIPE_ID; } enabled = false; blockReadNotify = false; canWrite = true; writeResult = -1; } void setup(Q_PIPE_ID id, QPipeDevice::Type _type) { pipe = id; type = _type; } void enable() { if(enabled) return; enabled = true; if(type == QPipeDevice::Read) { #ifdef Q_OS_WIN // for windows, the blocking mode is chosen by the QPipeReader // console might need a decoder if(consoleMode) { QT_WA( dec = 0; , dec = QTextCodec::codecForLocale()->makeDecoder(); ) } // pipe reader #ifdef USE_POLL pipeReader = new QPipeReaderPoll(pipe, this); #else // console always polls, no matter what if(consoleMode) pipeReader = new QPipeReaderPoll(pipe, this); else pipeReader = new QPipeReaderThread(pipe, this); #endif connect(pipeReader, SIGNAL(canRead(int)), this, SLOT(pr_canRead(int))); pipeReader->start(); // polling timer readTimer = new SafeTimer(this); connect(readTimer, SIGNAL(timeout()), SLOT(t_timeout())); // updated: now that we have pipeReader, this no longer // polls for data. it only does delayed singleshot // notifications. readTimer->setSingleShot(true); #endif #ifdef Q_OS_UNIX pipe_set_blocking(pipe, false); // socket notifier sn_read = new SafeSocketNotifier(pipe, QSocketNotifier::Read, this); connect(sn_read, SIGNAL(activated(int)), SLOT(sn_read_activated(int))); #endif } else { // for windows, the blocking mode is chosen by the QPipeWriter #ifdef Q_OS_UNIX pipe_set_blocking(pipe, false); // socket notifier sn_write = new SafeSocketNotifier(pipe, QSocketNotifier::Write, this); connect(sn_write, SIGNAL(activated(int)), SLOT(sn_write_activated(int))); sn_write->setEnabled(false); #endif } } public slots: void t_timeout() { #ifdef Q_OS_WIN if(blockReadNotify) return; // were we forced to notify? this can happen if we want to // spread out results across two reads. whatever caused // the forceNotify already knows what to do, so all we do // is signal. if(forceNotify) { forceNotify = false; blockReadNotify = true; emit q->notify(); return; } #endif } void pw_canWrite(int result, int bytesWritten) { #ifdef Q_OS_WIN if(result == 0) { writeResult = 0; lastWritten = lastTaken; // success means all bytes } else { writeResult = -1; lastWritten = bytesWritten; } canWrite = true; emit q->notify(); #else Q_UNUSED(result); Q_UNUSED(bytesWritten); #endif } void pr_canRead(int result) { #ifdef Q_OS_WIN blockReadNotify = true; if(result == -1) atEnd = true; else if(result == -2) atError = true; else if(result != -3) readAhead = result; emit q->notify(); #else Q_UNUSED(result); #endif } void sn_read_activated(int) { #ifdef Q_OS_UNIX if(blockReadNotify) return; blockReadNotify = true; emit q->notify(); #endif } void sn_write_activated(int) { #ifdef Q_OS_UNIX writeResult = 0; lastWritten = lastTaken; canWrite = true; sn_write->setEnabled(false); emit q->notify(); #endif } }; QPipeDevice::QPipeDevice(QObject *parent) :QObject(parent) { d = new Private(this); } QPipeDevice::~QPipeDevice() { delete d; } QPipeDevice::Type QPipeDevice::type() const { return d->type; } bool QPipeDevice::isValid() const { return (d->pipe != INVALID_Q_PIPE_ID); } Q_PIPE_ID QPipeDevice::id() const { return d->pipe; } int QPipeDevice::idAsInt() const { #ifdef Q_OS_WIN DWORD dw; memcpy(&dw, &d->pipe, sizeof(DWORD)); return (int)dw; // FIXME? assumes handle value fits in signed int #endif #ifdef Q_OS_UNIX return d->pipe; #endif } void QPipeDevice::take(Q_PIPE_ID id, Type t) { close(); d->setup(id, t); } void QPipeDevice::enable() { #ifdef Q_OS_WIN d->consoleMode = pipe_is_a_console(d->pipe); #endif d->enable(); } void QPipeDevice::close() { d->reset(); } void QPipeDevice::release() { d->pipe = INVALID_Q_PIPE_ID; d->reset(); } bool QPipeDevice::setInheritable(bool enabled) { #ifdef Q_OS_WIN Q_PIPE_ID newPipe; if(!pipe_set_inheritable(d->pipe, enabled, &newPipe)) return false; d->pipe = newPipe; #ifdef USE_POLL if(d->pipeReader) static_cast(d->pipeReader)->pipe = d->pipe; if(d->pipeWriter) static_cast(d->pipeWriter)->pipe = d->pipe; #endif return true; #endif #ifdef Q_OS_UNIX return pipe_set_inheritable(d->pipe, enabled, 0); #endif } int QPipeDevice::bytesAvailable() const { int n; #ifdef Q_OS_WIN if(d->consoleMode) n = pipe_read_avail_console(d->pipe); else n = pipe_read_avail(d->pipe); if(d->readAhead != -1) ++n; #else n = pipe_read_avail(d->pipe); #endif return n; } int QPipeDevice::read(char *data, int maxsize) { if(d->type != QPipeDevice::Read) return -1; // must read at least 1 byte if(maxsize < 1) return -1; #ifdef Q_OS_WIN // for windows console: // the number of bytes in utf8 can exceed the number of actual // characters it represents. to be safe, we'll assume that // utf8 could outnumber characters X:1. this does mean that // the maxsize parameter needs to be at least X to do // anything. (X = CONSOLE_CHAREXPAND) if(d->consoleMode && maxsize < CONSOLE_CHAREXPAND) return -1; // for resuming the pipeReader bool wasBlocked = d->blockReadNotify; #endif d->blockReadNotify = false; #ifdef Q_OS_WIN // predetermined results if(d->atEnd) { close(); return 0; } if(d->atError) { close(); return -1; } int offset = 0; int size = maxsize; // prepend readAhead if we have it if(d->readAhead != -1) { unsigned char c = (unsigned char)d->readAhead; d->readAhead = -1; memcpy(&data[0], &c, 1); ++offset; --size; // readAhead was enough data for the caller? if(size == 0) { if(wasBlocked) d->pipeReader->resume(); return offset; } } // read from the pipe now bool done; int ret; if(d->consoleMode) { // read a fraction of the number of characters as requested, // to guarantee the result fits int num = size / CONSOLE_CHAREXPAND; #ifdef QPIPE_SECURE SecureArray destbuf(num * sizeof(ushort), 0); #else QByteArray destbuf(num * sizeof(ushort), 0); #endif ushort *dest = (ushort *)destbuf.data(); ret = pipe_read_console(d->pipe, dest, num, &done, d->dec); if(ret != -1) { // for security, encode one character at a time without // performing a QString conversion of the whole thing QTextCodec *codec = QTextCodec::codecForMib(106); QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader); int at = 0; for(int n = 0; n < ret; ++n) { QChar c(dest[n]); QByteArray out = codec->fromUnicode(&c, 1, &cstate); memcpy(data + offset + at, out.data(), out.size()); at += out.size(); } ret = at; // change ret to actual bytes } } else ret = pipe_read(d->pipe, data + offset, size, &done); if(done || ret == -1) // eof or error { // did we already have some data? if so, defer the eof/error if(offset) { d->forceNotify = true; if(done) d->atEnd = true; else d->atError = true; // readTimer is a singleshot, so we have to start it // for forceNotify to work d->readTimer->start(); } // otherwise, bail else { close(); if(done) return 0; else return -1; } } else offset += ret; // pipe still active? resume the pipeReader if(wasBlocked && !d->atEnd && !d->atError) d->pipeReader->resume(); // no data means error if(offset == 0) return -1; return offset; #endif #ifdef Q_OS_UNIX bool done; int r = pipe_read(d->pipe, data, maxsize, &done); if(done) { close(); return 0; } if(r == -1) { close(); return -1; } // no data means error if(r == 0) return -1; return r; #endif } int QPipeDevice::write(const char *data, int size) { if(d->type != QPipeDevice::Write) return -1; // allowed to write? if(!d->canWrite) return -1; // if size is zero, don't bother if(size == 0) return 0; int r; #ifdef Q_OS_WIN if(!d->pipeWriter) { #ifdef USE_POLL d->pipeWriter = new QPipeWriterPoll(d->pipe, d); #else // console always polls, no matter what if(d->consoleMode) d->pipeWriter = new QPipeReaderPoll(d->pipe, d); else d->pipeWriter = new QPipeWriterThread(d->pipe, d); #endif connect(d->pipeWriter, SIGNAL(canWrite(int, int)), d, SLOT(pw_canWrite(int, int))); d->pipeWriter->start(); } if(d->consoleMode) { // Note: we convert to QString here, but it should not be a // security issue (see pipe_write_console comment above) // for console, just write direct. we won't use pipewriter QString out = QString::fromUtf8(QByteArray(data, size)); r = pipe_write_console(d->pipe, out.utf16(), out.length()); if(r == -1) return -1; // convert characters to bytes r = out.mid(0, r).toUtf8().size(); // simulate. we invoke the signal of pipewriter rather than our // own slot, so that the invoke can be cancelled. d->canWrite = false; QMetaObject::invokeMethod(d->pipeWriter, "canWrite", Qt::QueuedConnection, Q_ARG(int, 0), Q_ARG(int, r)); } else { d->canWrite = false; r = d->pipeWriter->write(data, size); } d->lastTaken = r; if(r == -1) { close(); return -1; } #endif #ifdef Q_OS_UNIX r = pipe_write(d->pipe, data, size); d->lastTaken = r; if(r == -1) { close(); return -1; } d->canWrite = false; d->sn_write->setEnabled(true); #endif return r; } int QPipeDevice::writeResult(int *written) const { if(written) *written = d->lastWritten; return d->writeResult; } //---------------------------------------------------------------------------- // QPipeEnd //---------------------------------------------------------------------------- enum ResetMode { ResetSession = 0, ResetSessionAndData = 1, ResetAll = 2 }; class QPipeEnd::Private : public QObject { Q_OBJECT public: QPipeEnd *q; QPipeDevice pipe; QPipeDevice::Type type; QByteArray buf; QByteArray curWrite; #ifdef Q_OS_WIN bool consoleMode; #endif #ifdef QPIPE_SECURE bool secure; SecureArray sec_buf; SecureArray sec_curWrite; #endif SafeTimer readTrigger, writeTrigger, closeTrigger, writeErrorTrigger; bool canRead, activeWrite; int lastWrite; bool closeLater; bool closing; Private(QPipeEnd *_q) : QObject(_q), q(_q), pipe(this), readTrigger(this), writeTrigger(this), closeTrigger(this), writeErrorTrigger(this) { readTrigger.setSingleShot(true); writeTrigger.setSingleShot(true); closeTrigger.setSingleShot(true); writeErrorTrigger.setSingleShot(true); connect(&pipe, SIGNAL(notify()), SLOT(pipe_notify())); connect(&readTrigger, SIGNAL(timeout()), SLOT(doRead())); connect(&writeTrigger, SIGNAL(timeout()), SLOT(doWrite())); connect(&closeTrigger, SIGNAL(timeout()), SLOT(doClose())); connect(&writeErrorTrigger, SIGNAL(timeout()), SLOT(doWriteError())); reset(ResetSessionAndData); } void reset(ResetMode mode) { pipe.close(); readTrigger.stop(); writeTrigger.stop(); closeTrigger.stop(); writeErrorTrigger.stop(); canRead = false; activeWrite = false; lastWrite = 0; closeLater = false; closing = false; curWrite.clear(); #ifdef QPIPE_SECURE secure = false; sec_curWrite.clear(); #endif if(mode >= ResetSessionAndData) { buf.clear(); #ifdef QPIPE_SECURE sec_buf.clear(); #endif } } void setup(Q_PIPE_ID id, QPipeDevice::Type _type) { type = _type; #ifdef Q_OS_WIN consoleMode = pipe_is_a_console(id); #endif pipe.take(id, type); } int pendingSize() const { #ifdef QPIPE_SECURE if(secure) return sec_buf.size(); else #endif return buf.size(); } int pendingFreeSize() const { #ifdef QPIPE_SECURE if(secure) return qMax(PIPEEND_READBUF_SEC - sec_buf.size(), 0); else #endif return qMax(PIPEEND_READBUF - buf.size(), 0); } void appendArray(QByteArray *a, const QByteArray &b) { (*a) += b; } #ifdef QPIPE_SECURE void appendArray(SecureArray *a, const SecureArray &b) { a->append(b); } #endif void takeArray(QByteArray *a, int len) { char *p = a->data(); int newsize = a->size() - len; memmove(p, p + len, newsize); a->resize(newsize); } #ifdef QPIPE_SECURE void takeArray(SecureArray *a, int len) { char *p = a->data(); int newsize = a->size() - len; memmove(p, p + len, newsize); a->resize(newsize); } #endif void setupNextRead() { if(pipe.isValid() && canRead) { canRead = false; readTrigger.start(0); } } void setupNextWrite() { if(!activeWrite) { activeWrite = true; writeTrigger.start(0); } } QByteArray read(QByteArray *buf, int bytes) { QByteArray a; if(bytes == -1 || bytes > buf->size()) { a = *buf; } else { a.resize(bytes); memcpy(a.data(), buf->data(), a.size()); } takeArray(buf, a.size()); setupNextRead(); return a; } void write(QByteArray *buf, const QByteArray &a) { appendArray(buf, a); setupNextWrite(); } #ifdef QPIPE_SECURE SecureArray readSecure(SecureArray *buf, int bytes) { SecureArray a; if(bytes == -1 || bytes > buf->size()) { a = *buf; } else { a.resize(bytes); memcpy(a.data(), buf->data(), a.size()); } takeArray(buf, a.size()); setupNextRead(); return a; } void writeSecure(SecureArray *buf, const SecureArray &a) { appendArray(buf, a); setupNextWrite(); } #endif public slots: void pipe_notify() { if(pipe.type() == QPipeDevice::Read) { doRead(); } else { int x; int writeResult = pipe.writeResult(&x); if(writeResult == -1) lastWrite = x; // if error, we may have written less bytes // remove what we just wrote bool moreData = false; #ifdef QPIPE_SECURE if(secure) { takeArray(&sec_buf, lastWrite); moreData = !sec_buf.isEmpty(); } else #endif { takeArray(&buf, lastWrite); moreData = !buf.isEmpty(); } #ifdef QPIPE_SECURE sec_curWrite.clear(); #endif curWrite.clear(); x = lastWrite; lastWrite = 0; if(writeResult == 0) { // more to write? do it if(moreData) { writeTrigger.start(0); } // done with all writing else { activeWrite = false; if(closeLater) { closeLater = false; closeTrigger.start(0); } } } else writeErrorTrigger.start(); if(x > 0) emit q->bytesWritten(x); } } void doRead() { doReadActual(true); } void doReadActual(bool sigs) { int left = pendingFreeSize(); if(left == 0) { canRead = true; return; } int max; #ifdef Q_OS_WIN if(consoleMode) { // need a minimum amount for console if(left < CONSOLE_CHAREXPAND) { canRead = true; return; } // don't use pipe.bytesAvailable() for console mode, // as it is somewhat bogus. fortunately, there is // no problem with overreading from the console. max = qMin(left, 32); } else #endif { max = qMin(left, pipe.bytesAvailable()); } int ret; #ifdef QPIPE_SECURE if(secure) { SecureArray a(max); ret = pipe.read(a.data(), a.size()); if(ret >= 1) { a.resize(ret); sec_buf.append(a); } } else #endif { QByteArray a(max, 0); ret = pipe.read(a.data(), a.size()); if(ret >= 1) { a.resize(ret); buf += a; } } if(ret < 1) { reset(ResetSession); if(sigs) { if(ret == 0) emit q->error(QPipeEnd::ErrorEOF); else emit q->error(QPipeEnd::ErrorBroken); } return; } if(sigs) emit q->readyRead(); } void doWrite() { int ret; #ifdef QPIPE_SECURE if(secure) { sec_curWrite.resize(qMin(PIPEEND_BLOCK, sec_buf.size())); memcpy(sec_curWrite.data(), sec_buf.data(), sec_curWrite.size()); ret = pipe.write(sec_curWrite.data(), sec_curWrite.size()); } else #endif { curWrite.resize(qMin(PIPEEND_BLOCK, buf.size())); memcpy(curWrite.data(), buf.data(), curWrite.size()); ret = pipe.write(curWrite.data(), curWrite.size()); } if(ret == -1) { reset(ResetSession); emit q->error(QPipeEnd::ErrorBroken); return; } lastWrite = ret; } void doClose() { reset(ResetSession); emit q->closed(); } void doWriteError() { reset(ResetSession); emit q->error(QPipeEnd::ErrorBroken); } }; QPipeEnd::QPipeEnd(QObject *parent) :QObject(parent) { d = new Private(this); } QPipeEnd::~QPipeEnd() { delete d; } void QPipeEnd::reset() { d->reset(ResetAll); } QPipeDevice::Type QPipeEnd::type() const { return d->pipe.type(); } bool QPipeEnd::isValid() const { return d->pipe.isValid(); } Q_PIPE_ID QPipeEnd::id() const { return d->pipe.id(); } int QPipeEnd::idAsInt() const { return d->pipe.idAsInt(); } void QPipeEnd::take(Q_PIPE_ID id, QPipeDevice::Type t) { reset(); d->setup(id, t); } #ifdef QPIPE_SECURE void QPipeEnd::setSecurityEnabled(bool secure) { // no change if(d->secure == secure) return; if(secure) { d->sec_buf = d->buf; d->buf.clear(); } else { d->buf = d->sec_buf.toByteArray(); d->sec_buf.clear(); } d->secure = secure; } #endif void QPipeEnd::enable() { d->pipe.enable(); } void QPipeEnd::close() { if(!isValid() || d->closing) return; d->closing = true; if(d->activeWrite) d->closeLater = true; else d->closeTrigger.start(0); } void QPipeEnd::release() { if(!isValid()) return; d->pipe.release(); d->reset(ResetSession); } bool QPipeEnd::setInheritable(bool enabled) { return d->pipe.setInheritable(enabled); } void QPipeEnd::finalize() { if(!isValid()) return; if(d->pipe.bytesAvailable()) d->doReadActual(false); d->reset(ResetSession); } void QPipeEnd::finalizeAndRelease() { if(!isValid()) return; if(d->pipe.bytesAvailable()) d->doReadActual(false); d->pipe.release(); d->reset(ResetSession); } int QPipeEnd::bytesAvailable() const { return d->pendingSize(); } int QPipeEnd::bytesToWrite() const { return d->pendingSize(); } QByteArray QPipeEnd::read(int bytes) { return d->read(&d->buf, bytes); } void QPipeEnd::write(const QByteArray &buf) { if(!isValid() || d->closing) return; if(buf.isEmpty()) return; #ifdef QPIPE_SECURE if(d->secure) // call writeSecure() instead return; #endif d->write(&d->buf, buf); } #ifdef QPIPE_SECURE SecureArray QPipeEnd::readSecure(int bytes) { return d->readSecure(&d->sec_buf, bytes); } void QPipeEnd::writeSecure(const SecureArray &buf) { if(!isValid() || d->closing) return; if(buf.isEmpty()) return; if(!d->secure) // call write() instead return; d->writeSecure(&d->sec_buf, buf); } #endif QByteArray QPipeEnd::takeBytesToWrite() { // only call this on inactive sessions if(isValid()) return QByteArray(); QByteArray a = d->buf; d->buf.clear(); return a; } #ifdef QPIPE_SECURE SecureArray QPipeEnd::takeBytesToWriteSecure() { // only call this on inactive sessions if(isValid()) return SecureArray(); SecureArray a = d->sec_buf; d->sec_buf.clear(); return a; } #endif //---------------------------------------------------------------------------- // QPipe //---------------------------------------------------------------------------- QPipe::QPipe(QObject *parent) :i(parent), o(parent) { } QPipe::~QPipe() { } void QPipe::reset() { i.reset(); o.reset(); } #ifdef QPIPE_SECURE bool QPipe::create(bool secure) #else bool QPipe::create() #endif { reset(); #ifdef Q_OS_WIN SECURITY_ATTRIBUTES secAttr; memset(&secAttr, 0, sizeof secAttr); secAttr.nLength = sizeof secAttr; secAttr.bInheritHandle = false; HANDLE r, w; if(!CreatePipe(&r, &w, &secAttr, 0)) return false; i.take(r, QPipeDevice::Read); o.take(w, QPipeDevice::Write); #endif #ifdef Q_OS_UNIX int p[2]; if(pipe(p) == -1) return false; if(!pipe_set_inheritable(p[0], false, 0) || !pipe_set_inheritable(p[1], false, 0)) { close(p[0]); close(p[1]); return false; } i.take(p[0], QPipeDevice::Read); o.take(p[1], QPipeDevice::Write); #endif #ifdef QPIPE_SECURE i.setSecurityEnabled(secure); o.setSecurityEnabled(secure); #endif return true; } } #include "qpipe.moc" psi-0.14/third-party/qca/qca/src/support/dirwatch.cpp0000644000175000017500000001333011305557613020734 0ustar janjan/* * Copyright (C) 2003-2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_support.h" #include #include #include #include #include #include "qca_safeobj.h" namespace QCA { // this gets us DOR-SS and SR, provided we delete the object between uses. // we assume QFileSystemWatcher complies to DS,NE. class QFileSystemWatcherRelay : public QObject { Q_OBJECT public: QFileSystemWatcher *watcher; QFileSystemWatcherRelay(QFileSystemWatcher *_watcher, QObject *parent = 0) :QObject(parent), watcher(_watcher) { connect(watcher, SIGNAL(directoryChanged(const QString &)), SIGNAL(directoryChanged(const QString &)), Qt::QueuedConnection); connect(watcher, SIGNAL(fileChanged(const QString &)), SIGNAL(fileChanged(const QString &)), Qt::QueuedConnection); } signals: void directoryChanged(const QString &path); void fileChanged(const QString &path); }; //---------------------------------------------------------------------------- // DirWatch //---------------------------------------------------------------------------- class DirWatch::Private : public QObject { Q_OBJECT public: DirWatch *q; QFileSystemWatcher *watcher; QFileSystemWatcherRelay *watcher_relay; QString dirName; Private(DirWatch *_q) : QObject(_q), q(_q), watcher(0), watcher_relay(0) { } private slots: void watcher_changed(const QString &path) { Q_UNUSED(path); emit q->changed(); } }; DirWatch::DirWatch(const QString &dir, QObject *parent) :QObject(parent) { d = new Private(this); setDirName(dir); } DirWatch::~DirWatch() { delete d; } QString DirWatch::dirName() const { return d->dirName; } void DirWatch::setDirName(const QString &dir) { if(d->watcher) { delete d->watcher; delete d->watcher_relay; d->watcher = 0; d->watcher_relay = 0; } d->dirName = dir; if(!d->dirName.isEmpty() && QFileInfo(d->dirName).isDir()) { d->watcher = new QFileSystemWatcher(this); d->watcher_relay = new QFileSystemWatcherRelay(d->watcher, this); connect(d->watcher_relay, SIGNAL(directoryChanged(const QString &)), d, SLOT(watcher_changed(const QString &))); d->watcher->addPath(d->dirName); } } //---------------------------------------------------------------------------- // FileWatch //---------------------------------------------------------------------------- class FileWatch::Private : public QObject { Q_OBJECT public: FileWatch *q; QFileSystemWatcher *watcher; QFileSystemWatcherRelay *watcher_relay; QString fileName; // file (optionally w/ path) as provided by user QString filePath; // absolute path of file, calculated by us bool fileExisted; Private(FileWatch *_q) : QObject(_q), q(_q), watcher(0), watcher_relay(0) { } void start(const QString &_fileName) { fileName = _fileName; watcher = new QFileSystemWatcher(this); watcher_relay = new QFileSystemWatcherRelay(watcher, this); connect(watcher_relay, SIGNAL(directoryChanged(const QString &)), SLOT(dir_changed(const QString &))); connect(watcher_relay, SIGNAL(fileChanged(const QString &)), SLOT(file_changed(const QString &))); QFileInfo fi(fileName); fi.makeAbsolute(); filePath = fi.filePath(); QDir dir = fi.dir(); // we watch both the directory and the file itself. the // reason we watch the directory is so we can detect when // the file is deleted/created // we don't bother checking for dir existence before adding, // since there isn't an atomic way to do both at once. if // it turns out that the dir doesn't exist, then the // monitoring will just silently not work at all. watcher->addPath(dir.path()); // similarly, we don't check for existence of the file. if // the add works, then it works. however, unlike the dir, // if the file add fails then the overall monitoring could // still potentially work... watcher->addPath(filePath); // save whether or not the file exists fileExisted = fi.exists(); // TODO: address race conditions and think about error // reporting instead of silently failing. probably this // will require a Qt API update. } void stop() { if(watcher) { delete watcher; delete watcher_relay; watcher = 0; watcher_relay = 0; } fileName.clear(); filePath.clear(); } private slots: void dir_changed(const QString &path) { Q_UNUSED(path); QFileInfo fi(filePath); bool exists = fi.exists(); if(exists && !fileExisted) { // this means the file was created. put a // watch on it. fileExisted = true; watcher->addPath(filePath); emit q->changed(); } } void file_changed(const QString &path) { Q_UNUSED(path); QFileInfo fi(filePath); if(!fi.exists()) fileExisted = false; emit q->changed(); } }; FileWatch::FileWatch(const QString &file, QObject *parent) :QObject(parent) { d = new Private(this); d->start(file); } FileWatch::~FileWatch() { delete d; } QString FileWatch::fileName() const { return d->fileName; } void FileWatch::setFileName(const QString &file) { d->stop(); d->start(file); } } #include "dirwatch.moc" psi-0.14/third-party/qca/qca/src/support/syncthread.cpp0000644000175000017500000001232011305557613021271 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_support.h" #include #include #include #include namespace QCA { QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList argTypes) { for(int n = 0; n < obj->methodCount(); ++n) { QMetaMethod m = obj->method(n); QByteArray sig = m.signature(); int offset = sig.indexOf('('); if(offset == -1) continue; QByteArray name = sig.mid(0, offset); if(name != method) continue; if(m.parameterTypes() != argTypes) continue; return m.typeName(); } return QByteArray(); } bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type) { // QMetaObject::invokeMethod() has a 10 argument maximum if(args.count() > 10) return false; QList argTypes; for(int n = 0; n < args.count(); ++n) argTypes += args[n].typeName(); // get return type int metatype = 0; QByteArray retTypeName = methodReturnType(obj->metaObject(), method, argTypes); if(!retTypeName.isEmpty()) { metatype = QMetaType::type(retTypeName.data()); if(metatype == 0) // lookup failed return false; } QGenericArgument arg[10]; for(int n = 0; n < args.count(); ++n) arg[n] = QGenericArgument(args[n].typeName(), args[n].constData()); QGenericReturnArgument retarg; QVariant retval; if(metatype != 0) { retval = QVariant(metatype, (const void *)0); retarg = QGenericReturnArgument(retval.typeName(), retval.data()); } if(!QMetaObject::invokeMethod(obj, method.data(), type, retarg, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9])) return false; if(retval.isValid() && ret) *ret = retval; return true; } //---------------------------------------------------------------------------- // SyncThread //---------------------------------------------------------------------------- class SyncThreadAgent; class SyncThread::Private : public QObject { Q_OBJECT public: SyncThread *q; QMutex m; QWaitCondition w; QEventLoop *loop; SyncThreadAgent *agent; bool last_success; QVariant last_ret; Private(SyncThread *_q) : QObject(_q), q(_q) { loop = 0; agent = 0; } private slots: void agent_started(); void agent_call_ret(bool success, const QVariant &ret); }; class SyncThreadAgent : public QObject { Q_OBJECT public: SyncThreadAgent(QObject *parent = 0) : QObject(parent) { QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection); } signals: void started(); void call_ret(bool success, const QVariant &ret); public slots: void call_do(QObject *obj, const QByteArray &method, const QVariantList &args) { QVariant ret; bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection); emit call_ret(ok, ret); } }; SyncThread::SyncThread(QObject *parent) :QThread(parent) { d = new Private(this); qRegisterMetaType("QVariant"); qRegisterMetaType("QVariantList"); } SyncThread::~SyncThread() { stop(); delete d; } void SyncThread::start() { QMutexLocker locker(&d->m); Q_ASSERT(!d->loop); QThread::start(); d->w.wait(&d->m); } void SyncThread::stop() { QMutexLocker locker(&d->m); if(!d->loop) return; QMetaObject::invokeMethod(d->loop, "quit"); d->w.wait(&d->m); wait(); } QVariant SyncThread::call(QObject *obj, const QByteArray &method, const QVariantList &args, bool *ok) { QMutexLocker locker(&d->m); bool ret; ret = QMetaObject::invokeMethod(d->agent, "call_do", Qt::QueuedConnection, Q_ARG(QObject*, obj), Q_ARG(QByteArray, method), Q_ARG(QVariantList, args)); Q_ASSERT(ret); d->w.wait(&d->m); if(ok) *ok = d->last_success; QVariant v = d->last_ret; d->last_ret = QVariant(); return v; } void SyncThread::run() { d->m.lock(); d->loop = new QEventLoop; d->agent = new SyncThreadAgent; connect(d->agent, SIGNAL(started()), d, SLOT(agent_started()), Qt::DirectConnection); connect(d->agent, SIGNAL(call_ret(bool, const QVariant &)), d, SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection); d->loop->exec(); d->m.lock(); atEnd(); delete d->agent; delete d->loop; d->agent = 0; d->loop = 0; d->w.wakeOne(); d->m.unlock(); } void SyncThread::Private::agent_started() { q->atStart(); w.wakeOne(); m.unlock(); } void SyncThread::Private::agent_call_ret(bool success, const QVariant &ret) { QMutexLocker locker(&m); last_success = success; last_ret = ret; w.wakeOne(); } } #include "syncthread.moc" psi-0.14/third-party/qca/qca/src/support/synchronizer.cpp0000644000175000017500000002301611305557613021666 0ustar janjan/* * Copyright (C) 2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_support.h" #include #include #include #include #include #include #include //#define TIMERFIXER_DEBUG namespace QCA { //---------------------------------------------------------------------------- // TimerFixer //---------------------------------------------------------------------------- class TimerFixer : public QObject { Q_OBJECT public: struct TimerInfo { int id; int interval; QTime time; bool fixInterval; TimerInfo() : fixInterval(false) {} }; TimerFixer *fixerParent; QList fixerChildren; QObject *target; QAbstractEventDispatcher *ed; QList timers; static bool haveFixer(QObject *obj) { return (qFindChild(obj) ? true: false); } TimerFixer(QObject *_target, TimerFixer *_fp = 0) : QObject(_target) { ed = 0; target = _target; fixerParent = _fp; if(fixerParent) fixerParent->fixerChildren.append(this); #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] pairing with %p (%s)\n", this, target, target->metaObject()->className()); #endif edlink(); target->installEventFilter(this); QObjectList list = target->children(); for(int n = 0; n < list.count(); ++n) hook(list[n]); } ~TimerFixer() { if(fixerParent) fixerParent->fixerChildren.removeAll(this); QList list = fixerChildren; for(int n = 0; n < list.count(); ++n) delete list[n]; list.clear(); updateTimerList(); // do this just to trip debug output target->removeEventFilter(this); edunlink(); #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] unpaired with %p (%s)\n", this, target, target->metaObject()->className()); #endif } virtual bool event(QEvent *e) { switch(e->type()) { case QEvent::ThreadChange: // this happens second //printf("TimerFixer[%p] self changing threads\n", this); edunlink(); QMetaObject::invokeMethod(this, "fixTimers", Qt::QueuedConnection); break; default: break; } return QObject::event(e); } virtual bool eventFilter(QObject *, QEvent *e) { switch(e->type()) { case QEvent::ChildAdded: hook(((QChildEvent *)e)->child()); break; case QEvent::ChildRemoved: unhook(((QChildEvent *)e)->child()); break; case QEvent::Timer: handleTimerEvent(((QTimerEvent *)e)->timerId()); break; case QEvent::ThreadChange: // this happens first #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] target changing threads\n", this); #endif break; default: break; } return false; } private slots: void edlink() { ed = QAbstractEventDispatcher::instance(); //printf("TimerFixer[%p] linking to dispatcher %p\n", this, ed); connect(ed, SIGNAL(aboutToBlock()), SLOT(ed_aboutToBlock())); } void edunlink() { //printf("TimerFixer[%p] unlinking from dispatcher %p\n", this, ed); if(ed) { disconnect(ed, SIGNAL(aboutToBlock()), this, SLOT(ed_aboutToBlock())); ed = 0; } } void ed_aboutToBlock() { //printf("TimerFixer[%p] aboutToBlock\n", this); updateTimerList(); } void fixTimers() { edlink(); updateTimerList(); for(int n = 0; n < timers.count(); ++n) { TimerInfo &info = timers[n]; QThread *objectThread = target->thread(); QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance(objectThread); int timeLeft = qMax(info.interval - info.time.elapsed(), 0); info.fixInterval = true; ed->unregisterTimer(info.id); ed->registerTimer(info.id, timeLeft, target); #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] adjusting [%d] to %d\n", this, info.id, timeLeft); #endif } } private: void hook(QObject *obj) { // don't watch a fixer or any object that already has one if(obj == this || qobject_cast(obj) || haveFixer(obj)) return; new TimerFixer(obj, this); } void unhook(QObject *obj) { TimerFixer *t = 0; for(int n = 0; n < fixerChildren.count(); ++n) { if(fixerChildren[n]->target == obj) t = fixerChildren[n]; } delete t; } void handleTimerEvent(int id) { bool found = false; int n; for(n = 0; n < timers.count(); ++n) { if(timers[n].id == id) { found = true; break; } } if(!found) { //printf("*** unrecognized timer [%d] activated ***\n", id); return; } TimerInfo &info = timers[n]; #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] timer [%d] activated!\n", this, info.id); #endif if(info.fixInterval) { #ifdef TIMERFIXER_DEBUG printf("restoring correct interval (%d)\n", info.interval); #endif info.fixInterval = false; ed->unregisterTimer(info.id); ed->registerTimer(info.id, info.interval, target); } info.time.start(); } void updateTimerList() { QList edtimers; if(ed) edtimers = ed->registeredTimers(target); // removed? for(int n = 0; n < timers.count(); ++n) { bool found = false; int id = timers[n].id; for(int i = 0; i < edtimers.count(); ++i) { if(edtimers[i].first == id) { found = true; break; } } if(!found) { timers.removeAt(n); --n; #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] timer [%d] removed\n", this, id); #endif } } // added? for(int n = 0; n < edtimers.count(); ++n) { int id = edtimers[n].first; bool found = false; for(int i = 0; i < timers.count(); ++i) { if(timers[i].id == id) { found = true; break; } } if(!found) { TimerInfo info; info.id = id; info.interval = edtimers[n].second; info.time.start(); timers += info; #ifdef TIMERFIXER_DEBUG printf("TimerFixer[%p] timer [%d] added (interval=%d)\n", this, info.id, info.interval); #endif } } } }; //---------------------------------------------------------------------------- // Synchronizer //---------------------------------------------------------------------------- class SynchronizerAgent : public QObject { Q_OBJECT public: SynchronizerAgent(QObject *parent = 0) : QObject(parent) { QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection); } signals: void started(); }; class Synchronizer::Private : public QThread { Q_OBJECT public: Synchronizer *q; bool active; bool do_quit; bool cond_met; QObject *obj; QEventLoop *loop; SynchronizerAgent *agent; TimerFixer *fixer; QMutex m; QWaitCondition w; QThread *orig_thread; Private(QObject *_obj, Synchronizer *_q) : QThread(_q), q(_q) { active = false; obj = _obj; loop = 0; fixer = new TimerFixer(obj); } ~Private() { stop(); delete fixer; } void start() { if(active) return; m.lock(); active = true; do_quit = false; QThread::start(); w.wait(&m); m.unlock(); } void stop() { if(!active) return; m.lock(); do_quit = true; w.wakeOne(); m.unlock(); wait(); active = false; } bool waitForCondition(int msecs) { unsigned long time = ULONG_MAX; if(msecs != -1) time = msecs; // move object to the worker thread cond_met = false; orig_thread = QThread::currentThread(); q->setParent(0); // don't follow the object QObject *orig_parent = obj->parent(); obj->setParent(0); // unparent the target or the move will fail obj->moveToThread(this); // tell the worker thread to start, wait for completion m.lock(); w.wakeOne(); if(!w.wait(&m, time)) { if(loop) { // if we timed out, tell the worker to quit QMetaObject::invokeMethod(loop, "quit"); w.wait(&m); } } // at this point the worker is done. cleanup and return m.unlock(); // restore parents obj->setParent(orig_parent); q->setParent(obj); return cond_met; } void conditionMet() { if(!loop) return; loop->quit(); cond_met = true; } protected: virtual void run() { m.lock(); QEventLoop eventLoop; while(1) { // thread now sleeps, waiting for work w.wakeOne(); w.wait(&m); if(do_quit) { m.unlock(); break; } loop = &eventLoop; agent = new SynchronizerAgent; connect(agent, SIGNAL(started()), SLOT(agent_started()), Qt::DirectConnection); // run the event loop eventLoop.exec(); delete agent; agent = 0; // eventloop done, flush pending events QCoreApplication::instance()->sendPostedEvents(); QCoreApplication::instance()->sendPostedEvents(0, QEvent::DeferredDelete); // and move the object back obj->moveToThread(orig_thread); m.lock(); loop = 0; w.wakeOne(); } } private slots: void agent_started() { m.unlock(); } }; Synchronizer::Synchronizer(QObject *parent) :QObject(parent) { d = new Private(parent, this); } Synchronizer::~Synchronizer() { delete d; } bool Synchronizer::waitForCondition(int msecs) { d->start(); return d->waitForCondition(msecs); } void Synchronizer::conditionMet() { d->conditionMet(); } } #include "synchronizer.moc" psi-0.14/third-party/qca/qca/src/support/console.cpp0000644000175000017500000004467711305557613020613 0ustar janjan/* * Copyright (C) 2006,2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qca_support.h" #include "qpipe.h" #include "qca_safeobj.h" #include #include #include #ifdef Q_OS_WIN # include #else # include # include # include # include #endif #include #define CONSOLEPROMPT_INPUT_MAX 56 Q_DECLARE_METATYPE(QCA::SecureArray) namespace QCA { //---------------------------------------------------------------------------- // ConsoleWorker //---------------------------------------------------------------------------- class ConsoleWorker : public QObject { Q_OBJECT private: QPipeEnd in, out; bool started; QByteArray in_left, out_left; public: ConsoleWorker(QObject *parent = 0) : QObject(parent), in(this), out(this) { started = false; } ~ConsoleWorker() { stop(); } void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id) { Q_ASSERT(!started); if(in_id != INVALID_Q_PIPE_ID) { in.take(in_id, QPipeDevice::Read); connect(&in, SIGNAL(readyRead()), SLOT(in_readyRead())); connect(&in, SIGNAL(closed()), SLOT(in_closed())); connect(&in, SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(in_error(QCA::QPipeEnd::Error))); in.enable(); } if(out_id != INVALID_Q_PIPE_ID) { out.take(out_id, QPipeDevice::Write); connect(&out, SIGNAL(bytesWritten(int)), SLOT(out_bytesWritten(int))); connect(&out, SIGNAL(closed()), SLOT(out_closed())); out.enable(); } started = true; } void stop() { if(!started) return; if(in.isValid()) in.finalizeAndRelease(); if(out.isValid()) out.release(); in_left = in.read(); out_left = out.takeBytesToWrite(); started = false; } public slots: bool isValid() const { return in.isValid(); } void setSecurityEnabled(bool enabled) { if(in.isValid()) in.setSecurityEnabled(enabled); if(out.isValid()) out.setSecurityEnabled(enabled); } QByteArray read(int bytes = -1) { return in.read(bytes); } void write(const QByteArray &a) { out.write(a); } QCA::SecureArray readSecure(int bytes = -1) { return in.readSecure(bytes); } void writeSecure(const QCA::SecureArray &a) { out.writeSecure(a); } void closeOutput() { out.close(); } int bytesAvailable() const { return in.bytesAvailable(); } int bytesToWrite() const { return in.bytesToWrite(); } public: QByteArray takeBytesToRead() { QByteArray a = in_left; in_left.clear(); return a; } QByteArray takeBytesToWrite() { QByteArray a = out_left; out_left.clear(); return a; } signals: void readyRead(); void bytesWritten(int bytes); void inputClosed(); void outputClosed(); private slots: void in_readyRead() { emit readyRead(); } void out_bytesWritten(int bytes) { emit bytesWritten(bytes); } void in_closed() { emit inputClosed(); } void in_error(QCA::QPipeEnd::Error) { emit inputClosed(); } void out_closed() { emit outputClosed(); } }; //---------------------------------------------------------------------------- // ConsoleThread //---------------------------------------------------------------------------- class ConsoleThread : public SyncThread { Q_OBJECT public: ConsoleWorker *worker; Q_PIPE_ID _in_id, _out_id; QByteArray in_left, out_left; QMutex call_mutex; ConsoleThread(QObject *parent = 0) : SyncThread(parent) { qRegisterMetaType("QCA::SecureArray"); } ~ConsoleThread() { stop(); } void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id) { _in_id = in_id; _out_id = out_id; SyncThread::start(); } void stop() { SyncThread::stop(); } QVariant mycall(QObject *obj, const char *method, const QVariantList &args = QVariantList()) { QVariant ret; bool ok; call_mutex.lock(); ret = call(obj, method, args, &ok); call_mutex.unlock(); Q_ASSERT(ok); if(!ok) { fprintf(stderr, "QCA: ConsoleWorker call [%s] failed.\n", method); abort(); return QVariant(); } return ret; } bool isValid() { return mycall(worker, "isValid").toBool(); } void setSecurityEnabled(bool enabled) { mycall(worker, "setSecurityEnabled", QVariantList() << enabled); } QByteArray read(int bytes = -1) { return mycall(worker, "read", QVariantList() << bytes).toByteArray(); } void write(const QByteArray &a) { mycall(worker, "write", QVariantList() << a); } SecureArray readSecure(int bytes = -1) { return qVariantValue(mycall(worker, "readSecure", QVariantList() << bytes)); } void writeSecure(const SecureArray &a) { mycall(worker, "writeSecure", QVariantList() << qVariantFromValue(a)); } void closeOutput() { mycall(worker, "closeOutput"); } int bytesAvailable() { return mycall(worker, "bytesAvailable").toInt(); } int bytesToWrite() { return mycall(worker, "bytesToWrite").toInt(); } QByteArray takeBytesToRead() { QByteArray a = in_left; in_left.clear(); return a; } QByteArray takeBytesToWrite() { QByteArray a = out_left; out_left.clear(); return a; } signals: void readyRead(); void bytesWritten(int); void inputClosed(); void outputClosed(); protected: virtual void atStart() { worker = new ConsoleWorker; // use direct connections here, so that the emits come from // the other thread. we can also connect to our own // signals to avoid having to make slots just to emit. connect(worker, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::DirectConnection); connect(worker, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)), Qt::DirectConnection); connect(worker, SIGNAL(inputClosed()), SIGNAL(inputClosed()), Qt::DirectConnection); connect(worker, SIGNAL(outputClosed()), SIGNAL(outputClosed()), Qt::DirectConnection); worker->start(_in_id, _out_id); } virtual void atEnd() { in_left = worker->takeBytesToRead(); out_left = worker->takeBytesToWrite(); delete worker; } }; //---------------------------------------------------------------------------- // Console //---------------------------------------------------------------------------- class ConsolePrivate : public QObject { Q_OBJECT public: Console *q; bool started; Console::Type type; Console::ChannelMode cmode; Console::TerminalMode mode; ConsoleThread *thread; ConsoleReference *ref; Q_PIPE_ID in_id; #ifdef Q_OS_WIN DWORD old_mode; #else struct termios old_term_attr; #endif ConsolePrivate(Console *_q) : QObject(_q), q(_q) { started = false; mode = Console::Default; thread = new ConsoleThread(this); ref = 0; } ~ConsolePrivate() { delete thread; setInteractive(Console::Default); } void setInteractive(Console::TerminalMode m) { // no change if(m == mode) return; if(m == Console::Interactive) { #ifdef Q_OS_WIN GetConsoleMode(in_id, &old_mode); SetConsoleMode(in_id, old_mode & (~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT)); #else int fd = in_id; struct termios attr; tcgetattr(fd, &attr); old_term_attr = attr; attr.c_lflag &= ~(ECHO); // turn off the echo flag attr.c_lflag &= ~(ICANON); // no wait for a newline attr.c_cc[VMIN] = 1; // read at least 1 char attr.c_cc[VTIME] = 0; // set wait time to zero // set the new attributes tcsetattr(fd, TCSAFLUSH, &attr); #endif } else { #ifdef Q_OS_WIN SetConsoleMode(in_id, old_mode); #else int fd = in_id; tcsetattr(fd, TCSANOW, &old_term_attr); #endif } mode = m; } }; static Console *g_tty_console = 0, *g_stdio_console = 0; Console::Console(Type type, ChannelMode cmode, TerminalMode tmode, QObject *parent) :QObject(parent) { if(type == Tty) { Q_ASSERT(g_tty_console == 0); g_tty_console = this; } else { Q_ASSERT(g_stdio_console == 0); g_stdio_console = this; } d = new ConsolePrivate(this); d->type = type; d->cmode = cmode; Q_PIPE_ID in = INVALID_Q_PIPE_ID; Q_PIPE_ID out = INVALID_Q_PIPE_ID; #ifdef Q_OS_WIN if(type == Tty) { in = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, false, OPEN_EXISTING, 0, NULL); } else { in = GetStdHandle(STD_INPUT_HANDLE); } #else if(type == Tty) { in = open("/dev/tty", O_RDONLY); } else { in = 0; // stdin } #endif if(cmode == ReadWrite) { #ifdef Q_OS_WIN if(type == Tty) { out = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, false, OPEN_EXISTING, 0, NULL); } else { out = GetStdHandle(STD_OUTPUT_HANDLE); } #else if(type == Tty) { out = open("/dev/tty", O_WRONLY); } else { out = 1; // stdout } #endif } d->in_id = in; d->setInteractive(tmode); d->thread->start(in, out); } Console::~Console() { release(); Console::Type type = d->type; delete d; if(type == Tty) g_tty_console = 0; else g_stdio_console = 0; } Console::Type Console::type() const { return d->type; } Console::ChannelMode Console::channelMode() const { return d->cmode; } Console::TerminalMode Console::terminalMode() const { return d->mode; } bool Console::isStdinRedirected() { #ifdef Q_OS_WIN HANDLE h = GetStdHandle(STD_INPUT_HANDLE); DWORD mode; if(GetConsoleMode(h, &mode)) return false; return true; #else return (isatty(0) ? false : true); // 0 == stdin #endif } bool Console::isStdoutRedirected() { #ifdef Q_OS_WIN HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode; if(GetConsoleMode(h, &mode)) return false; return true; #else return (isatty(1) ? false : true); // 1 == stdout #endif } Console *Console::ttyInstance() { return g_tty_console; } Console *Console::stdioInstance() { return g_stdio_console; } void Console::release() { d->thread->stop(); } QByteArray Console::bytesLeftToRead() { return d->thread->takeBytesToRead(); } QByteArray Console::bytesLeftToWrite() { return d->thread->takeBytesToWrite(); } //---------------------------------------------------------------------------- // ConsoleReference //---------------------------------------------------------------------------- class ConsoleReferencePrivate : public QObject { Q_OBJECT public: ConsoleReference *q; Console *console; ConsoleThread *thread; ConsoleReference::SecurityMode smode; SafeTimer lateTrigger; bool late_read, late_close; ConsoleReferencePrivate(ConsoleReference *_q) : QObject(_q), q(_q), lateTrigger(this) { console = 0; thread = 0; connect(&lateTrigger, SIGNAL(timeout()), SLOT(doLate())); lateTrigger.setSingleShot(true); } private slots: void doLate() { QPointer self = this; if(late_read) emit q->readyRead(); if(!self) return; if(late_close) emit q->inputClosed(); } }; ConsoleReference::ConsoleReference(QObject *parent) :QObject(parent) { d = new ConsoleReferencePrivate(this); } ConsoleReference::~ConsoleReference() { stop(); delete d; } bool ConsoleReference::start(Console *console, SecurityMode mode) { // make sure this reference isn't using a console already Q_ASSERT(!d->console); // one console reference at a time Q_ASSERT(console->d->ref == 0); // let's take it d->console = console; d->thread = d->console->d->thread; d->console->d->ref = this; bool valid = d->thread->isValid(); int avail = d->thread->bytesAvailable(); // pipe already closed and no data? consider this an error if(!valid && avail == 0) { d->console->d->ref = 0; d->thread = 0; d->console = 0; return false; } // enable security? it will last for this active session only d->smode = mode; if(mode == SecurityEnabled) d->thread->setSecurityEnabled(true); connect(d->thread, SIGNAL(readyRead()), SIGNAL(readyRead())); connect(d->thread, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int))); connect(d->thread, SIGNAL(inputClosed()), SIGNAL(inputClosed())); connect(d->thread, SIGNAL(outputClosed()), SIGNAL(outputClosed())); d->late_read = false; d->late_close = false; if(avail > 0) d->late_read = true; if(!valid) d->late_close = true; if(d->late_read || d->late_close) d->lateTrigger.start(); return true; } void ConsoleReference::stop() { if(!d->console) return; d->lateTrigger.stop(); disconnect(d->thread, 0, this, 0); // automatically disable security when we go inactive d->thread->setSecurityEnabled(false); d->console->d->ref = 0; d->thread = 0; d->console = 0; } Console *ConsoleReference::console() const { return d->console; } ConsoleReference::SecurityMode ConsoleReference::securityMode() const { return d->smode; } QByteArray ConsoleReference::read(int bytes) { return d->thread->read(bytes); } void ConsoleReference::write(const QByteArray &a) { d->thread->write(a); } SecureArray ConsoleReference::readSecure(int bytes) { return d->thread->readSecure(bytes); } void ConsoleReference::writeSecure(const SecureArray &a) { d->thread->writeSecure(a); } void ConsoleReference::closeOutput() { d->thread->closeOutput(); } int ConsoleReference::bytesAvailable() const { return d->thread->bytesAvailable(); } int ConsoleReference::bytesToWrite() const { return d->thread->bytesToWrite(); } //---------------------------------------------------------------------------- // ConsolePrompt //---------------------------------------------------------------------------- class ConsolePrompt::Private : public QObject { Q_OBJECT public: ConsolePrompt *q; Synchronizer sync; Console *con; bool own_con; ConsoleReference console; QString promptStr; SecureArray result; bool waiting; int at; bool done; bool charMode; QTextCodec *codec; QTextCodec::ConverterState *encstate, *decstate; Private(ConsolePrompt *_q) : QObject(_q), q(_q), sync(_q), console(this) { connect(&console, SIGNAL(readyRead()), SLOT(con_readyRead())); connect(&console, SIGNAL(inputClosed()), SLOT(con_inputClosed())); con = 0; own_con = false; waiting = false; #ifdef Q_OS_WIN codec = QTextCodec::codecForMib(106); // UTF-8 #else codec = QTextCodec::codecForLocale(); #endif encstate = 0; decstate = 0; } ~Private() { reset(); } void reset() { delete encstate; encstate = 0; delete decstate; decstate = 0; console.stop(); if(own_con) { delete con; con = 0; own_con = false; } } bool start(bool _charMode) { own_con = false; con = Console::ttyInstance(); if(!con) { con = new Console(Console::Tty, Console::ReadWrite, Console::Interactive); own_con = true; } result.clear(); at = 0; done = false; charMode = _charMode; encstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader); decstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader); if(!console.start(con, ConsoleReference::SecurityEnabled)) { reset(); fprintf(stderr, "Console input not available or closed\n"); return false; } if(!charMode) writeString(promptStr + ": "); return true; } void writeString(const QString &str) { console.writeSecure(codec->fromUnicode(str.unicode(), str.length(), encstate)); } // process each char. internally store the result as utf16, which // is easier to edit (e.g. backspace) bool processChar(QChar c) { if(charMode) { appendChar(c); done = true; return false; } if(c == '\r' || c == '\n') { writeString("\n"); done = true; return false; } if(c == '\b' || c == 0x7f) { if(at > 0) { --at; writeString("\b \b"); result.resize(at * sizeof(ushort)); } return true; } else if(c < 0x20) return true; if(at >= CONSOLEPROMPT_INPUT_MAX) return true; appendChar(c); writeString("*"); return true; } void appendChar(QChar c) { if((at + 1) * (int)sizeof(ushort) > result.size()) result.resize((at + 1) * sizeof(ushort)); ushort *p = (ushort *)result.data(); p[at++] = c.unicode(); } void convertToUtf8() { // convert result from utf16 to utf8, securely QTextCodec *codec = QTextCodec::codecForMib(106); QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader); SecureArray out; ushort *ustr = (ushort *)result.data(); int len = result.size() / sizeof(ushort); for(int n = 0; n < len; ++n) { QChar c(ustr[n]); out += codec->fromUnicode(&c, 1, &cstate); } result = out; } private slots: void con_readyRead() { while(console.bytesAvailable() > 0) { SecureArray buf = console.readSecure(1); if(buf.isEmpty()) break; // convert to unicode and process QString str = codec->toUnicode(buf.data(), 1, decstate); bool quit = false; for(int n = 0; n < str.length(); ++n) { if(!processChar(str[n])) { quit = true; break; } } if(quit) break; } if(done) { convertToUtf8(); reset(); if(waiting) sync.conditionMet(); else emit q->finished(); } } void con_inputClosed() { fprintf(stderr, "Console input closed\n"); if(!done) { done = true; result.clear(); reset(); if(waiting) sync.conditionMet(); else emit q->finished(); } } }; ConsolePrompt::ConsolePrompt(QObject *parent) :QObject(parent) { d = new Private(this); } ConsolePrompt::~ConsolePrompt() { delete d; } void ConsolePrompt::getHidden(const QString &promptStr) { d->reset(); d->promptStr = promptStr; if(!d->start(false)) { QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); return; } } void ConsolePrompt::getChar() { d->reset(); if(!d->start(true)) { QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); return; } } void ConsolePrompt::waitForFinished() { // reparent the Console under us (for Synchronizer) QObject *orig_parent = d->con->parent(); d->con->setParent(this); // block while prompting d->waiting = true; d->sync.waitForCondition(); d->waiting = false; // restore parent (if con still exists) if(d->con) d->con->setParent(orig_parent); } SecureArray ConsolePrompt::result() const { return d->result; } QChar ConsolePrompt::resultChar() const { QString str = QString::fromUtf8(d->result.toByteArray()); // this will never happen if getChar completes if(str.isEmpty()) return QChar(); return str[0]; } } #include "console.moc" psi-0.14/third-party/qca/qca/include/0000755000175000017500000000000011305557613015543 5ustar janjanpsi-0.14/third-party/qca/qca/include/QtCrypto/0000755000175000017500000000000011305557613017330 5ustar janjanpsi-0.14/third-party/qca/qca/include/QtCrypto/QtCrypto0000644000175000017500000000002111305557613021031 0ustar janjan#include "qca.h" psi-0.14/third-party/qca/qca/include/QtCrypto/qca_basic.h0000644000175000017500000007415211305557613021417 0ustar janjan/* * qca_basic.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004-2007 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_basic.h Header file for classes for cryptographic primitives (basic operations). \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_BASIC_H #define QCA_BASIC_H #include "qca_core.h" namespace QCA { /** \defgroup UserAPI QCA user API This is the main set of QCA classes, intended for use in standard applications. */ /** \class Random qca_basic.h QtCrypto Source of random numbers. QCA provides a built in source of random numbers, which can be accessed through this class. You can also use an alternative random number source, by implementing another provider. The normal use of this class is expected to be through the static members - randomChar(), randomInt() and randomArray(). \ingroup UserAPI */ class QCA_EXPORT Random : public Algorithm { public: /** Standard Constructor \param provider the name of the provider library for the random number generation */ Random(const QString &provider = QString()); /** Copy constructor \param from the %Random object to copy from */ Random(const Random &from); ~Random(); /** Assignment operator \param from the %Random object to copy state from */ Random & operator=(const Random &from); /** Provide a random byte. This method isn't normally required - you should use the static randomChar() method instead. \sa randomChar */ uchar nextByte(); /** Provide a specified number of random bytes. This method isn't normally required - you should use the static randomArray() method instead. \param size the number of bytes to provide \sa randomArray */ SecureArray nextBytes(int size); /** Provide a random character (byte) This is the normal way of obtaining a single random char (ie. 8 bit byte), as shown below: \code myRandomChar = QCA::Random::randomChar(); \endcode If you need a number of bytes, perhaps randomArray() may be of use. */ static uchar randomChar(); /** Provide a random integer. This is the normal way of obtaining a single random integer, as shown below: \code myRandomInt = QCA::Random::randomInt(); \endcode */ static int randomInt(); /** Provide a specified number of random bytes. \code // build a 30 byte secure array. SecureArray arry = QCA::Random::randomArray(30); \endcode \param size the number of bytes to provide */ static SecureArray randomArray(int size); private: class Private; Private *d; }; /** \class Hash qca_basic.h QtCrypto General class for hashing algorithms. Hash is the class for the various hashing algorithms within %QCA. SHA256, SHA1 or RIPEMD160 are recommended for new applications, although MD2, MD4, MD5 or SHA0 may be applicable (for interoperability reasons) for some applications. To perform a hash, you create a Hash object, call update() with the data that needs to be hashed, and then call final(), which returns a QByteArray of the hash result. An example (using the SHA1 hash, with 1000 updates of a 1000 byte string) is shown below: \code if(!QCA::isSupported("sha1")) printf("SHA1 not supported!\n"); else { QByteArray fillerString; fillerString.fill('a', 1000); QCA::Hash shaHash("sha1"); for (int i=0; i<1000; i++) shaHash.update(fillerString); QByteArray hashResult = shaHash.final(); if ( "34aa973cd4c4daa4f61eeb2bdbad27316534016f" == QCA::arrayToHex(hashResult) ) { printf("big SHA1 is OK\n"); } else { printf("big SHA1 failed\n"); } } \endcode If you only have a simple hash requirement - a single string that is fully available in memory at one time - then you may be better off with one of the convenience methods. So, for example, instead of creating a QCA::Hash object, then doing a single update() and the final() call; you could simply call QCA::Hash("algoName").hash() with the data that you would otherwise have provided to the update() call. For more information on hashing algorithms, see \ref hashing. \ingroup UserAPI */ class QCA_EXPORT Hash : public Algorithm, public BufferedComputation { public: /** Constructor \param type label for the type of hash to be created (for example, "sha1" or "md2") \param provider the name of the provider plugin for the subclass (eg "qca-ossl") */ explicit Hash(const QString &type, const QString &provider = QString()); /** Copy constructor \param from the Hash object to copy from */ Hash(const Hash &from); ~Hash(); /** Assignment operator \param from the Hash object to copy state from */ Hash & operator=(const Hash &from); /** Returns a list of all of the hash types available \param provider the name of the provider to get a list from, if one provider is required. If not specified, available hash types from all providers will be returned. */ static QStringList supportedTypes(const QString &provider = QString()); /** Return the hash type */ QString type() const; /** Reset a hash, dumping all previous parts of the message. This method clears (or resets) the hash algorithm, effectively undoing any previous update() calls. You should use this call if you are re-using a Hash sub-class object to calculate additional hashes. */ virtual void clear(); /** Update a hash, adding more of the message contents to the digest. The whole message needs to be added using this method before you call final(). If you find yourself only calling update() once, you may be better off using a convenience method such as hash() or hashToString() instead. \param a the byte array to add to the hash */ virtual void update(const MemoryRegion &a); /** \overload \param a the QByteArray to add to the hash */ void update(const QByteArray &a); /** \overload This method is provided to assist with code that already exists, and is being ported to %QCA. You are better off passing a SecureArray (as shown above) if you are writing new code. \param data pointer to a char array \param len the length of the array. If not specified (or specified as a negative number), the length will be determined with strlen(), which may not be what you want if the array contains a null (0x00) character. */ void update(const char *data, int len = -1); /** \overload This allows you to read from a file or other I/O device. Note that the device must be already open for reading \param file an I/O device If you are trying to calculate the hash of a whole file (and it isn't already open), you might want to use code like this: \code QFile f( "file.dat" ); if ( f1.open( IO_ReadOnly ) ) { QCA::Hash hashObj("sha1"); hashObj.update( &f1 ); QString output = hashObj.final() ) ), } \endcode */ void update(QIODevice *file); /** Finalises input and returns the hash result After calling update() with the required data, the hash results are finalised and produced. Note that it is not possible to add further data (with update()) after calling final(), because of the way the hashing works - null bytes are inserted to pad the results up to a fixed size. If you want to reuse the Hash object, you should call clear() and start to update() again. */ virtual MemoryRegion final(); /** %Hash a byte array, returning it as another byte array This is a convenience method that returns the hash of a SecureArray. \code SecureArray sampleArray(3); sampleArray.fill('a'); SecureArray outputArray = QCA::Hash("md2")::hash(sampleArray); \endcode \param array the QByteArray to hash If you need more flexibility (e.g. you are constructing a large byte array object just to pass it to hash(), then consider creating an Hash object, and then calling update() and final(). */ MemoryRegion hash(const MemoryRegion &array); /** %Hash a byte array, returning it as a printable string This is a convenience method that returns the hash of a QSeecureArray as a hexadecimal representation encoded in a QString. \param array the QByteArray to hash If you need more flexibility, you can create a Hash object, call Hash::update() as required, then call Hash::final(), before using the static arrayToHex() method. */ QString hashToString(const MemoryRegion &array); private: class Private; Private *d; }; /** \page hashing Hashing Algorithms There are a range of hashing algorithms available in %QCA. Hashing algorithms are used with the Hash and MessageAuthenticationCode classes. The MD2 algorithm takes an arbitrary data stream, known as the message and outputs a condensed 128 bit (16 byte) representation of that data stream, known as the message digest. This algorithm is considered slightly more secure than MD5, but is more expensive to compute. Unless backward compatibility or interoperability are considerations, you are better off using the SHA1 or RIPEMD160 hashing algorithms. For more information on %MD2, see B. Kalinski RFC1319 "The %MD2 Message-Digest Algorithm". The label for MD2 is "md2". The MD4 algorithm takes an arbitrary data stream, known as the message and outputs a condensed 128 bit (16 byte) representation of that data stream, known as the message digest. MD4 is not considered to be secure, based on known attacks. It should only be used for applications where collision attacks are not a consideration (for example, as used in the rsync algorithm for fingerprinting blocks of data). If a secure hash is required, you are better off using the SHA1 or RIPEMD160 hashing algorithms. MD2 and MD5 are both stronger 128 bit hashes. For more information on MD4, see R. Rivest RFC1320 "The %MD4 Message-Digest Algorithm". The label for MD4 is "md4". The MD5 takes an arbitrary data stream, known as the message and outputs a condensed 128 bit (16 byte) representation of that data stream, known as the message digest. MD5 is not considered to be secure, based on known attacks. It should only be used for applications where collision attacks are not a consideration. If a secure hash is required, you are better off using the SHA1 or RIPEMD160 hashing algorithms. For more information on MD5, see R. Rivest RFC1321 "The %MD5 Message-Digest Algorithm". The label for MD5 is "md5". The RIPEMD160 algorithm takes an arbitrary data stream, known as the message (up to \f$2^{64}\f$ bits in length) and outputs a condensed 160 bit (20 byte) representation of that data stream, known as the message digest. The RIPEMD160 algorithm is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. The label for RIPEMD160 is "ripemd160". The SHA-0 algorithm is a 160 bit hashing function, no longer recommended for new applications because of known (partial) attacks against it. The label for SHA-0 is "sha0". The SHA-1 algorithm takes an arbitrary data stream, known as the message (up to \f$2^{64}\f$ bits in length) and outputs a condensed 160 bit (20 byte) representation of that data stream, known as the message digest. SHA-1 is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. For more information on the SHA-1 algorithm,, see Federal Information Processing Standard Publication 180-2 "Specifications for the Secure %Hash Standard", available from http://csrc.nist.gov/publications/. The label for SHA-1 is "sha1". The SHA-224 algorithm takes an arbitrary data stream, known as the message (up to \f$2^{64}\f$ bits in length) and outputs a condensed 224 bit (28 byte) representation of that data stream, known as the message digest. SHA-224 is a "cut down" version of SHA-256, and you may be better off using SHA-256 in new designs. The SHA-224 algorithm is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. For more information on SHA-224, see Federal Information Processing Standard Publication 180-2 "Specifications for the Secure %Hash Standard", with change notice 1, available from http://csrc.nist.gov/publications/. The label for SHA-224 is "sha224". The SHA-256 algorithm takes an arbitrary data stream, known as the message (up to \f$2^{64}\f$ bits in length) and outputs a condensed 256 bit (32 byte) representation of that data stream, known as the message digest. The SHA-256 algorithm is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. For more information on SHA-256, see Federal Information Processing Standard Publication 180-2 "Specifications for the Secure %Hash Standard", available from http://csrc.nist.gov/publications/. The label for SHA-256 is "sha256". The SHA-384 algorithm takes an arbitrary data stream, known as the message (up to \f$2^{128}\f$ bits in length) and outputs a condensed 384 bit (48 byte) representation of that data stream, known as the message digest. The SHA-384 algorithm is a "cut down" version of SHA-512, and you may be better off using SHA-512 in new designs. The SHA-384 algorithm is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. For more information on SHA-384, see Federal Information Processing Standard Publication 180-2 "Specifications for the Secure %Hash Standard", available from http://csrc.nist.gov/publications/. The label for SHA-384 is "sha384". The SHA-512 algorithm takes an arbitrary data stream, known as the message (up to \f$2^{128}\f$ bits in length) and outputs a condensed 512 bit (64 byte) representation of that data stream, known as the message digest. The SHA-512 algorithm is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. For more information on SHA-512, see Federal Information Processing Standard Publication 180-2 "Specifications for the Secure %Hash Standard", available from http://csrc.nist.gov/publications/. The label for SHA-512 is "sha512". The Whirlpool algorithm takes an arbitrary data stream, known as the message (up to \f$2^{256}\f$ bits in length) and outputs a condensed 512 bit (64 byte) representation of that data stream, known as the message digest. The Whirlpool algorithm is considered secure in that it is considered computationally infeasible to find the message that produced the message digest. For more information on Whirlpool, see http://paginas.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html or ISO/IEC 10118-3:2004. The label for Whirlpool is "whirlpool". */ /** \page paddingDescription Padding For those Cipher sub-classes that are block based, there are modes that require a full block on encryption and decryption - %Cipher Block Chaining mode and Electronic Code Book modes are good examples. Since real world messages are not always a convenient multiple of a block size, we have to adding padding. There are a number of padding modes that %QCA supports, including not doing any padding at all. If you are not going to use padding, then you can pass QCA::Cipher::NoPadding as the pad argument to the Cipher sub-class, however it is then your responsibility to pass in appropriate data for the mode that you are using. The most common padding scheme is known as PKCS#7 (also PKCS#1), and it specifies that the pad bytes are all equal to the length of the padding ( for example, if you need three pad bytes to complete the block, then the padding is 0x03 0x03 0x03 ). On encryption, for algorithm / mode combinations that require padding, you will get a block of ciphertext when the input plain text block is complete. When you call final(), you will get out the ciphertext that corresponds to the last part of the plain text, plus any padding. If you had provided plaintext that matched up with a block size, then the cipher text block is generated from pure padding - you always get at least some padding, to ensure that the padding can be safely removed on decryption. On decryption, for algorithm / mode combinations that use padding, you will get back a block of plaintext when the input ciphertext block is complete. When you call final(), you will get a block that has been stripped of ciphertext. */ /** \class Cipher qca_basic.h QtCrypto General class for cipher (encryption / decryption) algorithms. Cipher is the class for the various algorithms that perform low level encryption and decryption within %QCA. AES128, AES192 and AES256 are recommended for new applications. Standard names for ciphers are: - Blowfish - "blowfish" - TripleDES - "tripledes" - DES - "des" - AES128 - "aes128" - AES192 - "aes192" - AES256 - "aes256" - CAST5 (CAST-128) - "cast5" When checking for the availability of a particular kind of cipher operation (e.g. AES128 in CBC mode with PKCS7 padding), you append the mode and padding type (in that example "aes128-cbc-pkcs7"). CFB and OFB modes don't use padding, so they are always just the cipher name followed by the mode (e.g. "blowfish-cfb" or "aes192-ofb"). If you are not using padding with CBC mode (i.e. you are ensuring block size operations yourself), just use the cipher name followed by "-cbc" (e.g. "blowfish-cbc" or "aes256-cbc"). \ingroup UserAPI */ class QCA_EXPORT Cipher : public Algorithm, public Filter { public: /** Mode settings for cipher algorithms. \note ECB is almost never what you want, unless you are trying to implement a %Cipher variation that is not supported by %QCA. */ enum Mode { CBC, ///< operate in %Cipher Block Chaining mode CFB, ///< operate in %Cipher FeedBack mode ECB, ///< operate in Electronic Code Book mode OFB ///< operate in Output FeedBack Mode }; /** Padding variations for cipher algorithms. See the \ref paddingDescription description for more details on padding schemes. */ enum Padding { DefaultPadding, ///< Default for cipher-mode NoPadding, ///< Do not use padding PKCS7 ///< Pad using the scheme in PKCS#7 }; /** Standard constructor \param type the name of the cipher specialisation to use (e.g. "aes128") \param mode the operating Mode to use (e.g. QCA::Cipher::CBC) \param pad the type of Padding to use \param dir the Direction that this Cipher should use (Encode for encryption, Decode for decryption) \param key the SymmetricKey array that is the key \param iv the InitializationVector to use (not used for ECB mode) \param provider the name of the Provider to use \note Padding only applies to CBC and ECB modes. CFB and OFB ciphertext is always the length of the plaintext. */ Cipher(const QString &type, Mode mode, Padding pad = DefaultPadding, Direction dir = Encode, const SymmetricKey &key = SymmetricKey(), const InitializationVector &iv = InitializationVector(), const QString &provider = QString()); /** Standard copy constructor \param from the Cipher to copy state from */ Cipher(const Cipher &from); ~Cipher(); /** Assignment operator \param from the Cipher to copy state from */ Cipher & operator=(const Cipher &from); /** Returns a list of all of the cipher types available \param provider the name of the provider to get a list from, if one provider is required. If not specified, available cipher types from all providers will be returned. */ static QStringList supportedTypes(const QString &provider = QString()); /** Return the cipher type */ QString type() const; /** Return the cipher mode */ Mode mode() const; /** Return the cipher padding type */ Padding padding() const; /** Return the cipher direction */ Direction direction() const; /** Return acceptable key lengths */ KeyLength keyLength() const; /** Test if a key length is valid for the cipher algorithm \param n the key length in bytes \return true if the key would be valid for the current algorithm */ bool validKeyLength(int n) const; /** return the block size for the cipher object */ int blockSize() const; /** reset the cipher object, to allow re-use */ virtual void clear(); /** pass in a byte array of data, which will be encrypted or decrypted (according to the Direction that was set in the constructor or in setup() ) and returned. \param a the array of data to encrypt / decrypt */ virtual MemoryRegion update(const MemoryRegion &a); /** complete the block of data, padding as required, and returning the completed block */ virtual MemoryRegion final(); /** Test if an update() or final() call succeeded. \return true if the previous call succeeded */ virtual bool ok() const; /** Reset / reconfigure the Cipher You can use this to re-use an existing Cipher, rather than creating a new object with a slightly different configuration. \param dir the Direction that this Cipher should use (Encode for encryption, Decode for decryption) \param key the SymmetricKey array that is the key \param iv the InitializationVector to use (not used for ECB Mode) \note You should not leave iv empty for any Mode except ECB. */ void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv = InitializationVector()); /** Construct a Cipher type string \param cipherType the name of the algorithm (eg AES128, DES) \param modeType the mode to operate the cipher in (eg QCA::CBC, QCA::CFB) \param paddingType the padding required (eg QCA::NoPadding, QCA::PCKS7) */ static QString withAlgorithms(const QString &cipherType, Mode modeType, Padding paddingType); private: class Private; Private *d; }; /** \class MessageAuthenticationCode qca_basic.h QtCrypto General class for message authentication code (MAC) algorithms. MessageAuthenticationCode is a class for accessing the various message authentication code algorithms within %QCA. HMAC using SHA1 ("hmac(sha1)") or HMAC using SHA256 ("hmac(sha256)") is recommended for new applications. Note that if your application is potentially susceptable to "replay attacks" where the message is sent more than once, you should include a counter in the message that is covered by the MAC, and check that the counter is always incremented every time you receive a message and MAC. For more information on HMAC, see H. Krawczyk et al. RFC2104 "HMAC: Keyed-Hashing for Message Authentication" \ingroup UserAPI */ class QCA_EXPORT MessageAuthenticationCode : public Algorithm, public BufferedComputation { public: /** Standard constructor \param type the name of the MAC (and algorithm, if applicable) to use \param key the shared key \param provider the provider to use, if a particular provider is required */ MessageAuthenticationCode(const QString &type, const SymmetricKey &key, const QString &provider = QString()); /** Standard copy constructor Copies the state (including key) from one MessageAuthenticationCode to another \param from the MessageAuthenticationCode to copy state from */ MessageAuthenticationCode(const MessageAuthenticationCode &from); ~MessageAuthenticationCode(); /** Assignment operator. Copies the state (including key) from one MessageAuthenticationCode to another \param from the MessageAuthenticationCode to assign from. */ MessageAuthenticationCode & operator=(const MessageAuthenticationCode &from); /** Returns a list of all of the message authentication code types available \param provider the name of the provider to get a list from, if one provider is required. If not specified, available message authentication codes types from all providers will be returned. */ static QStringList supportedTypes(const QString &provider = QString()); /** Return the MAC type */ QString type() const; /** Return acceptable key lengths */ KeyLength keyLength() const; /** Test if a key length is valid for the MAC algorithm \param n the key length in bytes \return true if the key would be valid for the current algorithm */ bool validKeyLength(int n) const; /** Reset a MessageAuthenticationCode, dumping all previous parts of the message. This method clears (or resets) the algorithm, effectively undoing any previous update() calls. You should use this call if you are re-using a %MessageAuthenticationCode sub-class object to calculate additional MACs. Note that if the key doesn't need to be changed, you don't need to call setup() again, since the key can just be reused. */ virtual void clear(); /** Update the MAC, adding more of the message contents to the digest. The whole message needs to be added using this method before you call final(). \param array the message contents */ virtual void update(const MemoryRegion &array); /** Finalises input and returns the MAC result After calling update() with the required data, the hash results are finalised and produced. Note that it is not possible to add further data (with update()) after calling final(). If you want to reuse the %MessageAuthenticationCode object, you should call clear() and start to update() again. */ virtual MemoryRegion final(); /** Initialise the MAC algorithm \param key the key to use for the algorithm */ void setup(const SymmetricKey &key); private: class Private; Private *d; }; /** \class KeyDerivationFunction qca_basic.h QtCrypto General superclass for key derivation algorithms. %KeyDerivationFunction is a superclass for the various key derivation function algorithms within %QCA. You should not need to use it directly unless you are adding another key derivation capability to %QCA - you should be using a sub-class. PBKDF2 using SHA1 is recommended for new applications. \ingroup UserAPI */ class QCA_EXPORT KeyDerivationFunction : public Algorithm { public: /** Standard copy constructor \param from the KeyDerivationFunction to copy from */ KeyDerivationFunction(const KeyDerivationFunction &from); ~KeyDerivationFunction(); /** Assignment operator Copies the state (including key) from one KeyDerivationFunction to another \param from the KeyDerivationFunction to assign from */ KeyDerivationFunction & operator=(const KeyDerivationFunction &from); /** Generate the key from a specified secret and salt value \note key length is ignored for some functions \param secret the secret (password or passphrase) \param salt the salt to use \param keyLength the length of key to return \param iterationCount the number of iterations to perform \return the derived key */ SymmetricKey makeKey(const SecureArray &secret, const InitializationVector &salt, unsigned int keyLength, unsigned int iterationCount); /** Construct the name of the algorithm You can use this to build a standard name string. You probably only need this method if you are creating a new subclass. \param kdfType the type of key derivation function \param algType the name of the algorithm to use with the key derivation function \return the name of the KDF/algorithm pair */ static QString withAlgorithm(const QString &kdfType, const QString &algType); protected: /** Special constructor for subclass initialisation \param type the algorithm to create \param provider the name of the provider to create the key derivation function in. */ KeyDerivationFunction(const QString &type, const QString &provider); private: class Private; Private *d; }; /** \class PBKDF1 qca_basic.h QtCrypto Password based key derivation function version 1 This class implements Password Based Key Derivation Function version 1, as specified in RFC2898, and also in PKCS#5. \ingroup UserAPI */ class QCA_EXPORT PBKDF1 : public KeyDerivationFunction { public: /** Standard constructor \param algorithm the name of the hashing algorithm to use \param provider the name of the provider to use, if available */ explicit PBKDF1(const QString &algorithm = "sha1", const QString &provider = QString()) : KeyDerivationFunction(withAlgorithm("pbkdf1", algorithm), provider) {} }; /** \class PBKDF2 qca_basic.h QtCrypto Password based key derivation function version 2 This class implements Password Based Key Derivation Function version 2, as specified in RFC2898, and also in PKCS#5. \ingroup UserAPI */ class QCA_EXPORT PBKDF2 : public KeyDerivationFunction { public: /** Standard constructor \param algorithm the name of the hashing algorithm to use \param provider the name of the provider to use, if available */ explicit PBKDF2(const QString &algorithm = "sha1", const QString &provider = QString()) : KeyDerivationFunction(withAlgorithm("pbkdf2", algorithm), provider) {} }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca.h0000644000175000017500000000260111305557613020244 0ustar janjan/* * qca.h - Qt Cryptographic Architecture * Copyright (C) 2003-2005 Justin Karneges * Copyright (C) 2004-2006 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca.h Summary header file for %QCA. \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_H #define QCA_H #include "qca_core.h" #include "qca_textfilter.h" #include "qca_basic.h" #include "qca_publickey.h" #include "qca_cert.h" #include "qca_keystore.h" #include "qca_securelayer.h" #include "qca_securemessage.h" #include "qcaprovider.h" #include "qpipe.h" #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_publickey.h0000644000175000017500000011351511305557613022322 0ustar janjan/* * qca_publickey.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_publickey.h Header file for PublicKey and PrivateKey related classes \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_PUBLICKEY_H #define QCA_PUBLICKEY_H #include #include "qca_core.h" namespace QCA { class PublicKey; class PrivateKey; class KeyGenerator; class RSAPublicKey; class RSAPrivateKey; class DSAPublicKey; class DSAPrivateKey; class DHPublicKey; class DHPrivateKey; /** Encryption algorithms */ enum EncryptionAlgorithm { EME_PKCS1v15, ///< Block type 2 (PKCS#1, Version 1.5) EME_PKCS1_OAEP ///< Optimal asymmetric encryption padding (PKCS#1, Version 2.0) }; /** Signature algorithm variants */ enum SignatureAlgorithm { SignatureUnknown, ///< Unknown signing algorithm EMSA1_SHA1, ///< SHA1, with EMSA1 (IEEE1363-2000) encoding (this is the usual DSA algorithm - FIPS186) EMSA3_SHA1, ///< SHA1, with EMSA3 (ie PKCS#1 Version 1.5) encoding EMSA3_MD5, ///< MD5, with EMSA3 (ie PKCS#1 Version 1.5) encoding (this is the usual RSA algorithm) EMSA3_MD2, ///< MD2, with EMSA3 (ie PKCS#1 Version 1.5) encoding EMSA3_RIPEMD160, ///< RIPEMD160, with EMSA3 (ie PKCS#1 Version 1.5) encoding EMSA3_Raw ///< EMSA3 without computing a message digest or a DigestInfo encoding (identical to PKCS#11's CKM_RSA_PKCS mechanism) }; /** Signature formats (DSA only) */ enum SignatureFormat { DefaultFormat, ///< For DSA, this is the same as IEEE_1363 IEEE_1363, ///< 40-byte format from IEEE 1363 (Botan/.NET) DERSequence ///< Signature wrapped in DER formatting (OpenSSL/Java) }; /** Password-based encryption */ enum PBEAlgorithm { PBEDefault, ///< Use modern default (same as PBES2_TripleDES_SHA1) PBES2_DES_SHA1, ///< PKCS#5 v2.0 DES/CBC,SHA1 PBES2_TripleDES_SHA1, ///< PKCS#5 v2.0 TripleDES/CBC,SHA1 PBES2_AES128_SHA1, ///< PKCS#5 v2.0 AES-128/CBC,SHA1 PBES2_AES192_SHA1, ///< PKCS#5 v2.0 AES-192/CBC,SHA1 PBES2_AES256_SHA1 ///< PKCS#5 v2.0 AES-256/CBC,SHA1 }; /** Return value from a format conversion Note that if you are checking for any result other than ConvertGood, then you may be introducing a provider specific dependency. */ enum ConvertResult { ConvertGood, ///< Conversion succeeded, results should be valid ErrorDecode, ///< General failure in the decode stage ErrorPassphrase, ///< Failure because of incorrect passphrase ErrorFile ///< Failure because of incorrect file }; /** Well known discrete logarithm group sets These sets are derived from three main sources: Java Cryptographic Extensions, RFC2412 and RFC3526. */ enum DLGroupSet { DSA_512, ///< 512 bit group, for compatibility with JCE DSA_768, ///< 768 bit group, for compatibility with JCE DSA_1024, ///< 1024 bit group, for compatibility with JCE IETF_768, ///< Group 1 from RFC 2412, Section E.1 IETF_1024, ///< Group 2 from RFC 2412, Section E.2 IETF_1536, ///< 1536-bit MODP Group ("group 5") from RFC3526 Section 2. IETF_2048, ///< 2048-bit MODP Group ("group 14") from RFC3526 Section 3. IETF_3072, ///< 3072-bit MODP Group ("group 15") from RFC3526 Section 4. IETF_4096, ///< 4096-bit MODP Group ("group 16") from RFC3526 Section 5. IETF_6144, ///< 6144-bit MODP Group ("group 17") from RFC3526 Section 6. IETF_8192 ///< 8192-bit MODP Group ("group 18") from RFC3526 Section 7. }; /** Encode a hash result in EMSA3 (PKCS#1) format This is a convenience function for providers that only have access to raw RSA signing (mainly smartcard providers). This is a built-in function of QCA and does not utilize a provider. SHA1, MD5, MD2, and RIPEMD160 are supported. \param hashName the hash type used to create the digest \param digest the digest to encode in EMSA3 format \param size the desired size of the encoding output (-1 for automatic size) */ QCA_EXPORT QByteArray emsa3Encode(const QString &hashName, const QByteArray &digest, int size = -1); /** \class DLGroup qca_publickey.h QtCrypto A discrete logarithm group \ingroup UserAPI */ class QCA_EXPORT DLGroup { public: DLGroup(); /** Construct a discrete logarithm group from raw parameters \param p the P parameter \param q the Q parameter \param g the G parameter */ DLGroup(const BigInteger &p, const BigInteger &q, const BigInteger &g); /** Construct a discrete logarithm group from raw parameters \param p the P parameter \param g the G parameter */ DLGroup(const BigInteger &p, const BigInteger &g); /** Standard copy constructor \param from the group to copy from */ DLGroup(const DLGroup &from); ~DLGroup(); /** Standard assignment operator \param from the DLGroup to copy from */ DLGroup & operator=(const DLGroup &from); /** Provide a list of the supported group sets \param provider the provider to report which group sets are available. If not specified, all providers will be checked */ static QList supportedGroupSets(const QString &provider = QString()); /** Test if the group is empty */ bool isNull() const; /** Provide the p component of the group */ BigInteger p() const; /** Provide the q component of the group */ BigInteger q() const; /** Provide the g component of the group */ BigInteger g() const; private: class Private; Private *d; }; /** \class PKey qca_publickey.h QtCrypto General superclass for public (PublicKey) and private (PrivateKey) keys used with asymmetric encryption techniques. \ingroup UserAPI */ class QCA_EXPORT PKey : public Algorithm { public: /** Types of public key cryptography keys supported by QCA */ enum Type { RSA, ///< RSA key DSA, ///< DSA key DH ///< Diffie Hellman key }; /** Standard constructor */ PKey(); /** Standard copy constructor \param from the key to copy from */ PKey(const PKey &from); ~PKey(); /** Standard assignment operator \param from the PKey to copy from */ PKey & operator=(const PKey &from); /** Test what types of keys are supported. Normally you would just test if the capability is present, however for PKey, you also need to test which types of keys are available. So if you want to figure out if RSA keys are supported, you need to do something like: \code if(!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::RSA)) { // then there is no RSA key support } else { // there is RSA key support } \endcode To make things a bit more complex, supportedTypes() only checks for basic functionality. If you want to check that you can do operations with PEM or DER (eg toPEM(), fromPEM(), and the equivalent DER and PEMfile operations, plus anything else that uses them, including the constructor form that takes a fileName), then you need to check for supportedIOTypes() instead. \param provider the name of the provider to use, if a particular provider is required. \sa supportedIOTypes() */ static QList supportedTypes(const QString &provider = QString()); /** Test what types of keys are supported for IO operations If you are using PKey DER or PEM operations, then you need to check for appropriate support using this method. For example, if you want to check if you can export or import an RSA key, then you need to do something like: \code if(!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) { // then there is no RSA key IO support } else { // there is RSA key IO support } \endcode Note that if you only want to check for basic functionality (ie not PEM or DER import/export), then you can use supportedTypes(). There is no need to use both - if the key type is supported for IO, then is also supported for basic operations. \param provider the name of the provider to use, if a particular provider is required. \sa supportedTypes() */ static QList supportedIOTypes(const QString &provider = QString()); /** Test if the key is null (empty) \return true if the key is null */ bool isNull() const; /** Report the Type of key (eg RSA, DSA or Diffie Hellman) \sa isRSA, isDSA and isDH for boolean tests. */ Type type() const; /** Report the number of bits in the key */ int bitSize() const; /** Test if the key is an RSA key */ bool isRSA() const; /** Test if the key is a DSA key */ bool isDSA() const; /** Test if the key is a Diffie Hellman key */ bool isDH() const; /** Test if the key is a public key */ bool isPublic() const; /** Test if the key is a private key */ bool isPrivate() const; /** Test if the key data can be exported. If the key resides on a smart card or other such device, this will likely return false. */ bool canExport() const; /** Test if the key can be used for key agreement */ bool canKeyAgree() const; /** Interpret this key as a PublicKey \sa toRSAPublicKey(), toDSAPublicKey() and toDHPublicKey() for protected forms of this call. */ PublicKey toPublicKey() const; /** Interpret this key as a PrivateKey */ PrivateKey toPrivateKey() const; /** test if two keys are equal \param a the key to compare with this key */ bool operator==(const PKey &a) const; /** test if two keys are not equal \param a the key to compare with this key */ bool operator!=(const PKey &a) const; protected: /** Create a key of the specified type \param type the name of the type of key to create \param provider the name of the provider to create the key in */ PKey(const QString &type, const QString &provider); /** Set the key \param k the key to assign from */ void set(const PKey &k); /** Interpret this key as an RSAPublicKey \note This function is essentially a convenience cast - if the key was created as a DSA key, this function cannot turn it into an RSA key. \sa toPublicKey() for the public version of this method */ RSAPublicKey toRSAPublicKey() const; /** Interpret this key as an RSAPrivateKey \note This function is essentially a convenience cast - if the key was created as a DSA key, this function cannot turn it into a RSA key. \sa toPrivateKey() for the public version of this method */ RSAPrivateKey toRSAPrivateKey() const; /** Interpret this key as an DSAPublicKey \note This function is essentially a convenience cast - if the key was created as an RSA key, this function cannot turn it into a DSA key. \sa toPublicKey() for the public version of this method */ DSAPublicKey toDSAPublicKey() const; /** Interpret this key as a DSAPrivateKey \note This function is essentially a convenience cast - if the key was created as an RSA key, this function cannot turn it into a DSA key. \sa toPrivateKey() for the public version of this method */ DSAPrivateKey toDSAPrivateKey() const; /** Interpret this key as an DHPublicKey \note This function is essentially a convenience cast - if the key was created as a DSA key, this function cannot turn it into a DH key. \sa toPublicKey() for the public version of this method */ DHPublicKey toDHPublicKey() const; /** Interpret this key as a DHPrivateKey \note This function is essentially a convenience cast - if the key was created as a DSA key, this function cannot turn it into a DH key. \sa toPrivateKey() for the public version of this method */ DHPrivateKey toDHPrivateKey() const; private: void assignToPublic(PKey *dest) const; void assignToPrivate(PKey *dest) const; class Private; Private *d; }; /** \class PublicKey qca_publickey.h QtCrypto Generic public key \ingroup UserAPI */ class QCA_EXPORT PublicKey : public PKey { public: /** Create an empty (null) public key */ PublicKey(); /** Create a public key based on a specified private key \param k the private key to extract the public key parts from */ PublicKey(const PrivateKey &k); /** Import a public key from a PEM representation in a file \param fileName the name of the file containing the public key \sa fromPEMFile for an alternative method */ PublicKey(const QString &fileName); /** Copy constructor \param from the PublicKey to copy from */ PublicKey(const PublicKey &from); ~PublicKey(); /** Assignment operator \param from the PublicKey to copy from */ PublicKey & operator=(const PublicKey &from); /** Convenience method to convert this key to an RSAPublicKey Note that if the key is not an RSA key (eg it is DSA or DH), then this will produce a null key. */ RSAPublicKey toRSA() const; /** Convenience method to convert this key to a DSAPublicKey Note that if the key is not an DSA key (eg it is RSA or DH), then this will produce a null key. */ DSAPublicKey toDSA() const; /** Convenience method to convert this key to a DHPublicKey Note that if the key is not an DH key (eg it is DSA or RSA), then this will produce a null key. */ DHPublicKey toDH() const; /** Test if this key can be used for encryption \return true if the key can be used for encryption */ bool canEncrypt() const; /** Test if the key can be used for verifying signatures \return true of the key can be used for verification */ bool canVerify() const; /** The maximum message size that can be encrypted with a specified algorithm \param alg the algorithm to check */ int maximumEncryptSize(EncryptionAlgorithm alg) const; /** Encrypt a message using a specified algorithm \param a the message to encrypt \param alg the algorithm to use */ SecureArray encrypt(const SecureArray &a, EncryptionAlgorithm alg); /** Initialise the signature verification process \param alg the algorithm to use for signing \param format the specific format to use, for DSA */ void startVerify(SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); /** Update the signature verification process with more data \param a the array containing the data that should be added to the signature */ void update(const MemoryRegion &a); /** Check the signature is valid for the message The process to check that a signature is correct is shown below: \code // note that pubkey is a PublicKey if( pubkey.canVerify() ) { pubkey.startVerify( QCA::EMSA3_MD5 ); pubkey.update( theMessage ); // might be called multiple times if ( pubkey.validSignature( theSignature ) ) { // then signature is valid } else { // then signature is invalid } } \endcode \param sig the signature to check \return true if the signature is correct */ bool validSignature(const QByteArray &sig); /** Single step message verification If you have the whole message to be verified, then this offers a more convenient approach to verification. \param a the message to check the signature on \param sig the signature to be checked \param alg the algorithm to use \param format the signature format to use, for DSA \return true if the signature is valid for the message */ bool verifyMessage(const MemoryRegion &a, const QByteArray &sig, SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); /** Export the key in Distinguished Encoding Rules (DER) format */ QByteArray toDER() const; /** Export the key in Privacy Enhanced Mail (PEM) format \sa toPEMFile provides a convenient way to save the PEM encoded key to a file \sa fromPEM provides an inverse of toPEM, converting the PEM encoded key back to a PublicKey */ QString toPEM() const; /** Export the key in Privacy Enhanced Mail (PEM) to a file \param fileName the name (and path, if necessary) of the file to save the PEM encoded key to. \sa toPEM for a version that exports to a QString, which may be useful if you need to do more sophisticated handling \sa fromPEMFile provides an inverse of toPEMFile, reading a PEM encoded key from a file */ bool toPEMFile(const QString &fileName) const; /** Import a key in Distinguished Encoding Rules (DER) format This function takes a binary array, which is assumed to contain a public key in DER encoding, and returns the key. Unless you don't care whether the import succeeded, you should test the result, as shown below. \code QCA::ConvertResult conversionResult; QCA::PublicKey publicKey = QCA::PublicKey::fromDER(keyArray, &conversionResult); if (! QCA::ConvertGood == conversionResult) { std::cout << "Public key read failed" << std::endl; } \endcode \param a the array containing a DER encoded key \param result pointer to a variable, which returns whether the conversion succeeded (ConvertGood) or not \param provider the name of the provider to use for the import. */ static PublicKey fromDER(const QByteArray &a, ConvertResult *result = 0, const QString &provider = QString()); /** Import a key in Privacy Enhanced Mail (PEM) format This function takes a string, which is assumed to contain a public key in PEM encoding, and returns that key. Unless you don't care whether the import succeeded, you should test the result, as shown below. \code QCA::ConvertResult conversionResult; QCA::PublicKey publicKey = QCA::PublicKey::fromPEM(keyAsString, &conversionResult); if (! QCA::ConvertGood == conversionResult) { std::cout << "Public key read failed" << std::endl; } \endcode \param s the string containing a PEM encoded key \param result pointer to a variable, which returns whether the conversion succeeded (ConvertGood) or not \param provider the name of the provider to use for the import. \sa toPEM, which provides an inverse of fromPEM() \sa fromPEMFile, which provides an import direct from a file. */ static PublicKey fromPEM(const QString &s, ConvertResult *result = 0, const QString &provider = QString()); /** Import a key in Privacy Enhanced Mail (PEM) format from a file This function takes the name of a file, which is assumed to contain a public key in PEM encoding, and returns that key. Unless you don't care whether the import succeeded, you should test the result, as shown below. \code QCA::ConvertResult conversionResult; QCA::PublicKey publicKey = QCA::PublicKey::fromPEMFile(fileName, &conversionResult); if (! QCA::ConvertGood == conversionResult) { std::cout << "Public key read failed" << std::endl; } \endcode \param fileName a string containing the name of the file \param result pointer to a variable, which returns whether the conversion succeeded (ConvertGood) or not \param provider the name of the provider to use for the import. \sa toPEMFile, which provides an inverse of fromPEMFile() \sa fromPEM, which provides an import from a string \note there is also a constructor form that can import from a file */ static PublicKey fromPEMFile(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); protected: /** Create a new key of a specified type \param type the type of key to create \param provider the provider to use, if required */ PublicKey(const QString &type, const QString &provider); private: class Private; Private *d; }; /** \class PrivateKey qca_publickey.h QtCrypto Generic private key \ingroup UserAPI */ class QCA_EXPORT PrivateKey : public PKey { public: /** Create an empty private key */ PrivateKey(); /** Import a private key from a PEM representation in a file \param fileName the name of the file containing the private key \param passphrase the pass phrase for the private key \sa fromPEMFile for an alternative method \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ explicit PrivateKey(const QString &fileName, const SecureArray &passphrase = SecureArray()); /** Copy constructor \param from the PrivateKey to copy from */ PrivateKey(const PrivateKey &from); ~PrivateKey(); /** Assignment operator \param from the PrivateKey to copy from */ PrivateKey & operator=(const PrivateKey &from); /** Interpret / convert the key to an RSA key */ RSAPrivateKey toRSA() const; /** Interpret / convert the key to a DSA key */ DSAPrivateKey toDSA() const; /** Interpret / convert the key to a Diffie-Hellman key */ DHPrivateKey toDH() const; /** Test if this key can be used for decryption \return true if the key can be used for decryption */ bool canDecrypt() const; /** Test if this key can be used for signing \return true if the key can be used to make a signature */ bool canSign() const; /** Decrypt the message \param in the cipher (encrypted) data \param out the plain text data \param alg the algorithm to use \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg); /** Initialise the message signature process \param alg the algorithm to use for the message signature process \param format the signature format to use, for DSA \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ void startSign(SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); /** Update the signature process \param a the message to use to update the signature \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ void update(const MemoryRegion &a); /** The resulting signature \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ QByteArray signature(); /** One step signature process \param a the message to sign \param alg the algorithm to use for the signature \param format the signature format to use, for DSA \return the signature \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ QByteArray signMessage(const MemoryRegion &a, SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); /** Derive a shared secret key from a public key \param theirs the public key to derive from */ SymmetricKey deriveKey(const PublicKey &theirs); /** List the supported Password Based Encryption Algorithms that can be used to protect the key. \param provider the provider to use, if a particular provider is required */ static QList supportedPBEAlgorithms(const QString &provider = QString()); /** Export the key in Distinguished Encoding Rules (DER) format \param passphrase the pass phrase to use to protect the key \param pbe the symmetric encryption algorithm to use to protect the key \sa fromDER provides an inverse of toDER, converting the DER encoded key back to a PrivateKey */ SecureArray toDER(const SecureArray &passphrase = SecureArray(), PBEAlgorithm pbe = PBEDefault) const; /** Export the key in Privacy Enhanced Mail (PEM) format \param passphrase the pass phrase to use to protect the key \param pbe the symmetric encryption algorithm to use to protect the key \sa toPEMFile provides a convenient way to save the PEM encoded key to a file \sa fromPEM provides an inverse of toPEM, converting the PEM encoded key back to a PrivateKey */ QString toPEM(const SecureArray &passphrase = SecureArray(), PBEAlgorithm pbe = PBEDefault) const; /** Export the key in Privacy Enhanced Mail (PEM) format to a file \param fileName the name (and path, if required) that the key should be exported to. \param passphrase the pass phrase to use to protect the key \param pbe the symmetric encryption algorithm to use to protect the key \return true if the export succeeds \sa toPEM provides a convenient way to save the PEM encoded key to a file \sa fromPEM provides an inverse of toPEM, converting the PEM encoded key back to a PrivateKey */ bool toPEMFile(const QString &fileName, const SecureArray &passphrase = SecureArray(), PBEAlgorithm pbe = PBEDefault) const; /** Import the key from Distinguished Encoding Rules (DER) format \param a the array containing the DER representation of the key \param passphrase the pass phrase that is used to protect the key \param result a pointer to a ConvertResult, that if specified, will be set to reflect the result of the import \param provider the provider to use, if a particular provider is required \sa toDER provides an inverse of fromDER, exporting the key to an array \sa QCA::KeyLoader for an asynchronous loader approach. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ static PrivateKey fromDER(const SecureArray &a, const SecureArray &passphrase = SecureArray(), ConvertResult *result = 0, const QString &provider = QString()); /** Import the key from Privacy Enhanced Mail (PEM) format \param s the string containing the PEM representation of the key \param passphrase the pass phrase that is used to protect the key \param result a pointer to a ConvertResult, that if specified, will be set to reflect the result of the import \param provider the provider to use, if a particular provider is required \sa toPEM provides an inverse of fromPEM, exporting the key to a string in PEM encoding. \sa QCA::KeyLoader for an asynchronous loader approach. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ static PrivateKey fromPEM(const QString &s, const SecureArray &passphrase = SecureArray(), ConvertResult *result = 0, const QString &provider = QString()); /** Import the key in Privacy Enhanced Mail (PEM) format from a file \param fileName the name (and path, if required) of the file containing the PEM representation of the key \param passphrase the pass phrase that is used to protect the key \param result a pointer to a ConvertResult, that if specified, will be set to reflect the result of the import \param provider the provider to use, if a particular provider is required \sa toPEMFile provides an inverse of fromPEMFile \sa fromPEM which allows import from a string \sa QCA::KeyLoader for an asynchronous loader approach. \note there is also a constructor form, that allows you to create the key directly \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ static PrivateKey fromPEMFile(const QString &fileName, const SecureArray &passphrase = SecureArray(), ConvertResult *result = 0, const QString &provider = QString()); protected: /** Create a new private key \param type the type of key to create \param provider the provider to use, if a specific provider is required. */ PrivateKey(const QString &type, const QString &provider); private: class Private; Private *d; }; /** \class KeyGenerator qca_publickey.h QtCrypto Class for generating asymmetric key pairs This class is used for generating asymmetric keys (public/private key pairs). \ingroup UserAPI */ class QCA_EXPORT KeyGenerator : public QObject { Q_OBJECT public: /** Create a new key generator \param parent the parent object, if applicable */ KeyGenerator(QObject *parent = 0); ~KeyGenerator(); /** Test whether the key generator is set to operate in blocking mode, or not \return true if the key generator is in blocking mode \sa setBlockingEnabled */ bool blockingEnabled() const; /** Set whether the key generator is in blocking mode, nor not \param b if true, the key generator will be set to operate in blocking mode, otherwise it will operate in non-blocking mode \sa blockingEnabled() */ void setBlockingEnabled(bool b); /** Test if the key generator is currently busy, or not \return true if the key generator is busy generating a key already */ bool isBusy() const; /** Generate an RSA key of the specified length This method creates both the public key and corresponding private key. You almost certainly want to extract the public key part out - see PKey::toPublicKey for an easy way. Key length is a tricky judgment - using less than 2048 is probably being too liberal for long term use. Don't use less than 1024 without serious analysis. \param bits the length of key that is required \param exp the exponent - typically 3, 17 or 65537 \param provider the name of the provider to use, if a particular provider is required */ PrivateKey createRSA(int bits, int exp = 65537, const QString &provider = QString()); /** Generate a DSA key This method creates both the public key and corresponding private key. You almost certainly want to extract the public key part out - see PKey::toPublicKey for an easy way. \param domain the discrete logarithm group that this key should be generated from \param provider the name of the provider to use, if a particular provider is required \note Not every DLGroup makes sense for DSA. You should use one of DSA_512, DSA_768 and DSA_1024. */ PrivateKey createDSA(const DLGroup &domain, const QString &provider = QString()); /** Generate a Diffie-Hellman key This method creates both the public key and corresponding private key. You almost certainly want to extract the public key part out - see PKey::toPublicKey for an easy way. \param domain the discrete logarithm group that this key should be generated from \param provider the name of the provider to use, if a particular provider is required \note For compatibility, you should use one of the IETF_ groupsets as the domain argument. */ PrivateKey createDH(const DLGroup &domain, const QString &provider = QString()); /** Return the last generated key This is really only useful when you are working with non-blocking key generation */ PrivateKey key() const; /** Create a new discrete logarithm group \param set the set of discrete logarithm parameters to generate from \param provider the name of the provider to use, if a particular provider is required. */ DLGroup createDLGroup(QCA::DLGroupSet set, const QString &provider = QString()); /** The current discrete logarithm group */ DLGroup dlGroup() const; Q_SIGNALS: /** Emitted when the key generation is complete. This is only used in non-blocking mode */ void finished(); private: Q_DISABLE_COPY(KeyGenerator) class Private; friend class Private; Private *d; }; /** \class RSAPublicKey qca_publickey.h QtCrypto RSA Public Key \ingroup UserAPI */ class QCA_EXPORT RSAPublicKey : public PublicKey { public: /** Generate an empty RSA public key */ RSAPublicKey(); /** Generate an RSA public key from specified parameters \param n the public key value \param e the public key exponent \param provider the provider to use, if a particular provider is required */ RSAPublicKey(const BigInteger &n, const BigInteger &e, const QString &provider = QString()); /** Extract the public key components from an RSA private key \param k the private key to use as the basis for the public key */ RSAPublicKey(const RSAPrivateKey &k); /** The public key value This value is the actual public key value (the product of p and q, the random prime numbers used to generate the RSA key), also known as the public modulus. */ BigInteger n() const; /** The public key exponent This value is the exponent chosen in the original key generator step */ BigInteger e() const; }; /** \class RSAPrivateKey qca_publickey.h QtCrypto RSA Private Key \ingroup UserAPI */ class QCA_EXPORT RSAPrivateKey : public PrivateKey { public: /** Generate an empty RSA private key */ RSAPrivateKey(); /** Generate an RSA private key from specified parameters \param n the public key value \param e the public key exponent \param p one of the two chosen primes \param q the other of the two chosen primes \param d inverse of the exponent, modulo (p-1)(q-1) \param provider the provider to use, if a particular provider is required */ RSAPrivateKey(const BigInteger &n, const BigInteger &e, const BigInteger &p, const BigInteger &q, const BigInteger &d, const QString &provider = QString()); /** The public key value This value is the actual public key value (the product of p and q, the random prime numbers used to generate the RSA key), also known as the public modulus. */ BigInteger n() const; /** The public key exponent This value is the exponent chosen in the original key generator step */ BigInteger e() const; /** One of the two random primes used to generate the private key */ BigInteger p() const; /** The second of the two random primes used to generate the private key */ BigInteger q() const; /** The inverse of the exponent, module (p-1)(q-1) */ BigInteger d() const; }; /** \class DSAPublicKey qca_publickey.h QtCrypto Digital Signature %Algorithm Public Key \ingroup UserAPI */ class QCA_EXPORT DSAPublicKey : public PublicKey { public: /** Create an empty DSA public key */ DSAPublicKey(); /** Create a DSA public key \param domain the discrete logarithm group to use \param y the public random value \param provider the provider to use, if a specific provider is required */ DSAPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider = QString()); /** Create a DSA public key from a specified private key \param k the DSA private key to use as the source */ DSAPublicKey(const DSAPrivateKey &k); /** The discrete logarithm group that is being used */ DLGroup domain() const; /** The public random value associated with this key */ BigInteger y() const; }; /** \class DSAPrivateKey qca_publickey.h QtCrypto Digital Signature %Algorithm Private Key \ingroup UserAPI */ class QCA_EXPORT DSAPrivateKey : public PrivateKey { public: /** Create an empty DSA private key */ DSAPrivateKey(); /** Create a DSA public key \param domain the discrete logarithm group to use \param y the public random value \param x the private random value \param provider the provider to use, if a specific provider is required */ DSAPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider = QString()); /** The discrete logarithm group that is being used */ DLGroup domain() const; /** the public random value */ BigInteger y() const; /** the private random value */ BigInteger x() const; }; /** \class DHPublicKey qca_publickey.h QtCrypto Diffie-Hellman Public Key \ingroup UserAPI */ class QCA_EXPORT DHPublicKey : public PublicKey { public: /** Create an empty Diffie-Hellman public key */ DHPublicKey(); /** Create a Diffie-Hellman public key \param domain the discrete logarithm group to use \param y the public random value \param provider the provider to use, if a specific provider is required */ DHPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider = QString()); /** Create a Diffie-Hellman public key from a specified private key \param k the Diffie-Hellman private key to use as the source */ DHPublicKey(const DHPrivateKey &k); /** The discrete logarithm group that is being used */ DLGroup domain() const; /** The public random value associated with this key */ BigInteger y() const; }; /** \class DHPrivateKey qca_publickey.h QtCrypto Diffie-Hellman Private Key \ingroup UserAPI */ class QCA_EXPORT DHPrivateKey : public PrivateKey { public: /** Create an empty Diffie-Hellman private key */ DHPrivateKey(); /** Create a Diffie-Hellman private key \param domain the discrete logarithm group to use \param y the public random value \param x the private random value \param provider the provider to use, if a particular provider is required */ DHPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider = QString()); /** The discrete logarithm group that is being used */ DLGroup domain() const; /** The public random value associated with this key */ BigInteger y() const; /** The private random value associated with this key */ BigInteger x() const; }; /*@}*/ } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qcaprovider.h0000644000175000017500000022614011305557613022025 0ustar janjan/* * qcaprovider.h - QCA Plugin API * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qcaprovider.h Header file for provider implementation classes (plugins) \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCAPROVIDER_H #define QCAPROVIDER_H #include "qca_core.h" #include "qca_basic.h" #include "qca_publickey.h" #include "qca_cert.h" #include "qca_keystore.h" #include "qca_securelayer.h" #include "qca_securemessage.h" #include #ifndef DOXYGEN_NO_PROVIDER_API /** \defgroup ProviderAPI QCA provider API This group of classes is not normally needed by application writers, but can be used to extend QCA if required */ /** \class QCAPlugin qcaprovider.h QtCrypto Provider plugin base class QCA loads cryptographic provider plugins with QPluginLoader. The QObject obtained when loading the plugin must implement the QCAPlugin interface. This is done by inheriting QCAPlugin, and including Q_INTERFACES(QCAPlugin) in your class declaration. For example: \code class MyPlugin : public QObject, public QCAPlugin { Q_OBJECT Q_INTERFACES(QCAPlugin) public: virtual Provider *createProvider() { ... } }; \endcode There is only one function to reimplement, called createProvider(). This function should return a newly allocated Provider instance. \ingroup ProviderAPI */ class QCA_EXPORT QCAPlugin { public: /** Destructs the object */ virtual ~QCAPlugin() {} /** Returns a newly allocated Provider instance. */ virtual QCA::Provider *createProvider() = 0; }; Q_DECLARE_INTERFACE(QCAPlugin, "com.affinix.qca.Plugin/1.0") namespace QCA { /** \class InfoContext qcaprovider.h QtCrypto Extended provider information \note This class is part of the provider plugin interface and should not be used directly by applications. \ingroup ProviderAPI */ class QCA_EXPORT InfoContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ InfoContext(Provider *p) : BasicContext(p, "info") {} /** The hash algorithms supported by the provider */ virtual QStringList supportedHashTypes() const; /** The cipher algorithms supported by the provider */ virtual QStringList supportedCipherTypes() const; /** The mac algorithms supported by the provider */ virtual QStringList supportedMACTypes() const; }; /** \class RandomContext qcaprovider.h QtCrypto Random provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want Random instead. \ingroup ProviderAPI */ class QCA_EXPORT RandomContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ RandomContext(Provider *p) : BasicContext(p, "random") {} /** Return an array of random bytes \param size the number of random bytes to return */ virtual SecureArray nextBytes(int size) = 0; }; /** \class HashContext qcaprovider.h QtCrypto Hash provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want Hash instead. \ingroup ProviderAPI */ class QCA_EXPORT HashContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context \param type the name of the type of hash provided by this context */ HashContext(Provider *p, const QString &type) : BasicContext(p, type) {} /** Reset the object to its initial state */ virtual void clear() = 0; /** Process a chunk of data \param a the input data to process */ virtual void update(const MemoryRegion &a) = 0; /** Return the computed hash */ virtual MemoryRegion final() = 0; }; /** \class CipherContext qcaprovider.h QtCrypto Cipher provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want Cipher instead. \ingroup ProviderAPI */ class QCA_EXPORT CipherContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context \param type the name of the type of cipher provided by this context \note type includes the name of the cipher (e.g. "aes256"), the operating mode (e.g. "cbc" or "ofb") and the padding type (e.g. "pkcs7") if any. */ CipherContext(Provider *p, const QString &type) : BasicContext(p, type) {} /** Set up the object for encrypt/decrypt \param dir the direction for the cipher (encryption/decryption) \param key the symmetric key to use for the cipher \param iv the initialization vector to use for the cipher (not used in ECB mode) */ virtual void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv) = 0; /** Returns the KeyLength for this cipher */ virtual KeyLength keyLength() const = 0; /** Returns the block size for this cipher */ virtual int blockSize() const = 0; /** Process a chunk of data. Returns true if successful. \param in the input data to process \param out pointer to an array that should store the result */ virtual bool update(const SecureArray &in, SecureArray *out) = 0; /** Finish the cipher processing. Returns true if successful. \param out pointer to an array that should store the result */ virtual bool final(SecureArray *out) = 0; }; /** \class MACContext qcaprovider.h QtCrypto Message authentication code provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want MessageAuthenticationCode instead. \ingroup ProviderAPI */ class QCA_EXPORT MACContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context \param type the name of the type of MAC algorithm provided by this context */ MACContext(Provider *p, const QString &type) : BasicContext(p, type) {} /** Set up the object for hashing \param key the key to use with the MAC. */ virtual void setup(const SymmetricKey &key) = 0; /** Returns the KeyLength for this MAC algorithm */ virtual KeyLength keyLength() const = 0; /** Process a chunk of data \param in the input data to process */ virtual void update(const MemoryRegion &in) = 0; /** Compute the result after processing all data \param out pointer to an array that should store the result */ virtual void final(MemoryRegion *out) = 0; protected: /** Returns a KeyLength that supports any length */ KeyLength anyKeyLength() const { // this is used instead of a default implementation to make sure that // provider authors think about it, at least a bit. // See Meyers, Effective C++, Effective C++ (2nd Ed), Item 36 return KeyLength( 0, INT_MAX, 1 ); } }; /** \class KDFContext qcaprovider.h QtCrypto Key derivation function provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want KeyDerivationFunction instead. \ingroup ProviderAPI */ class QCA_EXPORT KDFContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context \param type the name of the KDF provided by this context (including algorithm) */ KDFContext(Provider *p, const QString &type) : BasicContext(p, type) {} /** Create a key and return it \param secret the secret part (typically password) \param salt the salt / initialization vector \param keyLength the length of the key to be produced \param iterationCount the number of iterations of the derivation algorith, */ virtual SymmetricKey makeKey(const SecureArray &secret, const InitializationVector &salt, unsigned int keyLength, unsigned int iterationCount) = 0; }; /** \class DLGroupContext qcaprovider.h QtCrypto Discrete logarithm provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want DLGroup instead. \ingroup ProviderAPI */ class QCA_EXPORT DLGroupContext : public Provider::Context { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ DLGroupContext(Provider *p) : Provider::Context(p, "dlgroup") {} /** The DLGroupSets supported by this object */ virtual QList supportedGroupSets() const = 0; /** Returns true if there is a result to obtain */ virtual bool isNull() const = 0; /** Attempt to create P, Q, and G values from the specified group set If \a block is true, then this function blocks until completion. Otherwise, this function returns immediately and finished() is emitted when the operation completes. If an error occurs during generation, then the operation will complete and isNull() will return true. \param set the group set to generate the key from \param block whether to block (true) or not (false) */ virtual void fetchGroup(DLGroupSet set, bool block) = 0; /** Obtain the result of the operation. Ensure isNull() returns false before calling this function. \param p the P value \param q the Q value \param g the G value */ virtual void getResult(BigInteger *p, BigInteger *q, BigInteger *g) const = 0; Q_SIGNALS: /** Emitted when the fetchGroup() operation completes in non-blocking mode. */ void finished(); }; /** \class PKeyBase qcaprovider.h QtCrypto Public key implementation provider base \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want PKey, PublicKey, or PrivateKey instead. \ingroup ProviderAPI */ class QCA_EXPORT PKeyBase : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context \param type type of key provided by this context */ PKeyBase(Provider *p, const QString &type); /** Returns true if this object is not valid. This is the default state, and the object may also become this state if a conversion or generation function fails. */ virtual bool isNull() const = 0; /** Returns the type of public key */ virtual PKey::Type type() const = 0; /** Returns true if this is a private key, otherwise false */ virtual bool isPrivate() const = 0; /** Returns true if the components of this key are accessible and whether it can be serialized into an output format. Private keys from a smart card device will often not be exportable. */ virtual bool canExport() const = 0; /** If the key is a private key, this function will convert it into a public key (all private key data includes the public data as well, which is why this is possible). If the key is already a public key, then this function has no effect. */ virtual void convertToPublic() = 0; /** Returns the number of bits in the key */ virtual int bits() const = 0; /** Returns the maximum number of bytes that can be encrypted by this key \param alg the algorithm to be used for encryption */ virtual int maximumEncryptSize(EncryptionAlgorithm alg) const; /** Encrypt data \param in the input data to encrypt \param alg the encryption algorithm to use */ virtual SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg); /** Decrypt data \param in the input data to decrypt \param out pointer to an array to store the plaintext result \param alg the encryption algorithm used to generate the input data */ virtual bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg); /** Begin a signing operation \param alg the signature algorithm to use \param format the signature format to use */ virtual void startSign(SignatureAlgorithm alg, SignatureFormat format); /** Begin a verify operation \param alg the signature algorithm used by the input signature \param format the signature format used by the input signature */ virtual void startVerify(SignatureAlgorithm alg, SignatureFormat format); /** Process the plaintext input data for either signing or verifying, whichever operation is active. \param in the input data to process */ virtual void update(const MemoryRegion &in); /** Complete a signing operation, and return the signature value If there is an error signing, an empty array is returned. */ virtual QByteArray endSign(); /** Complete a verify operation, and return true if successful If there is an error verifying, this function returns false. \param sig the signature to verify with the input data */ virtual bool endVerify(const QByteArray &sig); /** Compute a symmetric key based on this private key and some other public key Essentially for Diffie-Hellman only. \param theirs the other side (public key) to be used for key generation. */ virtual SymmetricKey deriveKey(const PKeyBase &theirs); Q_SIGNALS: /** Emitted when an asynchronous operation completes on this key. Such operations will be documented that they emit this signal. */ void finished(); }; /** \class RSAContext qcaprovider.h QtCrypto RSA provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want RSAPublicKey or RSAPrivateKey instead. \ingroup ProviderAPI */ class QCA_EXPORT RSAContext : public PKeyBase { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ RSAContext(Provider *p) : PKeyBase(p, "rsa") {} /** Generate an RSA private key If \a block is true, then this function blocks until completion. Otherwise, this function returns immediately and finished() is emitted when the operation completes. If an error occurs during generation, then the operation will complete and isNull() will return true. \param bits the length of the key to generate, in bits \param exp the exponent to use for generation \param block whether to use blocking mode */ virtual void createPrivate(int bits, int exp, bool block) = 0; /** Create an RSA private key based on the five components \param n the N parameter \param e the public exponent \param p the P parameter \param q the Q parameter \param d the D parameter */ virtual void createPrivate(const BigInteger &n, const BigInteger &e, const BigInteger &p, const BigInteger &q, const BigInteger &d) = 0; /** Create an RSA public key based on the two public components \param n the N parameter \param e the public exponent */ virtual void createPublic(const BigInteger &n, const BigInteger &e) = 0; /** Returns the public N component of this RSA key */ virtual BigInteger n() const = 0; /** Returns the public E component of this RSA key */ virtual BigInteger e() const = 0; /** Returns the private P component of this RSA key */ virtual BigInteger p() const = 0; /** Returns the private Q component of this RSA key */ virtual BigInteger q() const = 0; /** Returns the private D component of this RSA key */ virtual BigInteger d() const = 0; }; /** \class DSAContext qcaprovider.h QtCrypto DSA provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want DSAPublicKey or DSAPrivateKey instead. \ingroup ProviderAPI */ class QCA_EXPORT DSAContext : public PKeyBase { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ DSAContext(Provider *p) : PKeyBase(p, "dsa") {} /** Generate a DSA private key If \a block is true, then this function blocks until completion. Otherwise, this function returns immediately and finished() is emitted when the operation completes. If an error occurs during generation, then the operation will complete and isNull() will return true. \param domain the domain values to use for generation \param block whether to use blocking mode */ virtual void createPrivate(const DLGroup &domain, bool block) = 0; /** Create a DSA private key based on its numeric components \param domain the domain values to use for generation \param y the public Y component \param x the private X component */ virtual void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) = 0; /** Create a DSA public key based on its numeric components \param domain the domain values to use for generation \param y the public Y component */ virtual void createPublic(const DLGroup &domain, const BigInteger &y) = 0; /** Returns the public domain component of this DSA key */ virtual DLGroup domain() const = 0; /** Returns the public Y component of this DSA key */ virtual BigInteger y() const = 0; /** Returns the private X component of this DSA key */ virtual BigInteger x() const = 0; }; /** \class DHContext qcaprovider.h QtCrypto Diffie-Hellman provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want DHPublicKey or DHPrivateKey instead. \ingroup ProviderAPI */ class QCA_EXPORT DHContext : public PKeyBase { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ DHContext(Provider *p) : PKeyBase(p, "dh") {} /** Generate a Diffie-Hellman private key If \a block is true, then this function blocks until completion. Otherwise, this function returns immediately and finished() is emitted when the operation completes. If an error occurs during generation, then the operation will complete and isNull() will return true. \param domain the domain values to use for generation \param block whether to use blocking mode */ virtual void createPrivate(const DLGroup &domain, bool block) = 0; /** Create a Diffie-Hellman private key based on its numeric components \param domain the domain values to use for generation \param y the public Y component \param x the private X component */ virtual void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) = 0; /** Create a Diffie-Hellman public key based on its numeric components \param domain the domain values to use for generation \param y the public Y component */ virtual void createPublic(const DLGroup &domain, const BigInteger &y) = 0; /** Returns the public domain component of this Diffie-Hellman key */ virtual DLGroup domain() const = 0; /** Returns the public Y component of this Diffie-Hellman key */ virtual BigInteger y() const = 0; /** Returns the private X component of this Diffie-Hellman key */ virtual BigInteger x() const = 0; }; /** \class PKeyContext qcaprovider.h QtCrypto Public key container provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want PKey, PublicKey, or PrivateKey instead. This object "holds" a public key object. By default it contains no key (key() returns 0), but you can put a key into it with setKey(), or you can call an import function such as publicFromDER(). \ingroup ProviderAPI */ class QCA_EXPORT PKeyContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ PKeyContext(Provider *p) : BasicContext(p, "pkey") {} /** Returns a list of supported public key types */ virtual QList supportedTypes() const = 0; /** Returns a list of public key types that can be serialized and deserialized into DER and PEM format */ virtual QList supportedIOTypes() const = 0; /** Returns a list of password-based encryption algorithms that are supported for private key serialization and deserialization */ virtual QList supportedPBEAlgorithms() const = 0; /** Returns the key held by this object, or 0 if there is no key */ virtual PKeyBase *key() = 0; /** Returns the key held by this object, or 0 if there is no key */ virtual const PKeyBase *key() const = 0; /** Sets the key for this object. If this object already had a key, then the old one is destructed. This object takes ownership of the key. \param key the key to be set for this object */ virtual void setKey(PKeyBase *key) = 0; /** Attempt to import a key from another provider. Returns true if successful, otherwise false. Generally this function is used if the specified key's provider does not support serialization, but your provider does. The call to this function would then be followed by an export function, such as publicToDER(). \param key the key to be imported */ virtual bool importKey(const PKeyBase *key) = 0; /** Convert a public key to DER format, and return the value Returns an empty array on error. */ virtual QByteArray publicToDER() const; /** Convert a public key to PEM format, and return the value Returns an empty string on error. */ virtual QString publicToPEM() const; /** Read DER-formatted input and convert it into a public key Returns QCA::ConvertGood if successful, otherwise some error value. \param a the input data */ virtual ConvertResult publicFromDER(const QByteArray &a); /** Read PEM-formatted input and convert it into a public key Returns QCA::ConvertGood if successful, otherwise some error value. \param s the input data */ virtual ConvertResult publicFromPEM(const QString &s); /** Convert a private key to DER format, and return the value Returns an empty array on error. \param passphrase the passphrase to encode the result with, or an empty array if no encryption is desired \param pbe the encryption algorithm to use, if applicable */ virtual SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const; /** Convert a private key to PEM format, and return the value Returns an empty string on error. \param passphrase the passphrase to encode the result with, or an empty array if no encryption is desired \param pbe the encryption algorithm to use, if applicable */ virtual QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const; /** Read DER-formatted input and convert it into a private key Returns QCA::ConvertGood if successful, otherwise some error value. \param a the input data \param passphrase the passphrase needed to decrypt, if applicable */ virtual ConvertResult privateFromDER(const SecureArray &a, const SecureArray &passphrase); /** Read PEM-formatted input and convert it into a private key Returns QCA::ConvertGood if successful, otherwise some error value. \param s the input data \param passphrase the passphrase needed to decrypt, if applicable */ virtual ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase); }; /** \class CertBase qcaprovider.h QtCrypto X.509 certificate and certificate request provider base \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want Certificate, CertificateRequest, or CRL instead. \ingroup ProviderAPI */ class QCA_EXPORT CertBase : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context \param type the type of certificate-like object provided by this context */ CertBase(Provider *p, const QString &type) : BasicContext(p, type) {} /** Convert this object to DER format, and return the value Returns an empty array on error. */ virtual QByteArray toDER() const = 0; /** Convert this object to PEM format, and return the value Returns an empty string on error. */ virtual QString toPEM() const = 0; /** Read DER-formatted input and convert it into this object Returns QCA::ConvertGood if successful, otherwise some error value. \param a the input data */ virtual ConvertResult fromDER(const QByteArray &a) = 0; /** Read PEM-formatted input and convert it into this object Returns QCA::ConvertGood if successful, otherwise some error value. \param s the input data */ virtual ConvertResult fromPEM(const QString &s) = 0; }; /** \class CertContextProps qcaprovider.h QtCrypto X.509 certificate or certificate request properties \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want Certificate or CertificateRequest instead. Some fields are only for certificates or only for certificate requests, and these fields are noted. \ingroup ProviderAPI */ class QCA_EXPORT CertContextProps { public: /** The X.509 certificate version, usually 3 This field is for certificates only. */ int version; /** The time the certificate becomes valid (often the time of create) This field is for certificates only. */ QDateTime start; /** The time the certificate expires This field is for certificates only. */ QDateTime end; /** The subject information */ CertificateInfoOrdered subject; /** The issuer information This field is for certificates only. */ CertificateInfoOrdered issuer; /** The constraints */ Constraints constraints; /** The policies */ QStringList policies; /** A list of URIs for CRLs This field is for certificates only. */ QStringList crlLocations; /** A list of URIs for issuer certificates This field is for certificates only. */ QStringList issuerLocations; /** A list of URIs for OCSP services This field is for certificates only. */ QStringList ocspLocations; /** The certificate serial number This field is for certificates only. */ BigInteger serial; /** True if the certificate is a CA or the certificate request is requesting to be a CA, otherwise false */ bool isCA; /** True if the certificate is self-signed This field is for certificates only. */ bool isSelfSigned; /** The path limit */ int pathLimit; /** The signature data */ QByteArray sig; /** The signature algorithm used to create the signature */ SignatureAlgorithm sigalgo; /** The subject id This field is for certificates only. */ QByteArray subjectId; /** The issuer id This field is for certificates only. */ QByteArray issuerId; /** The SPKAC challenge value This field is for certificate requests only. */ QString challenge; /** The format used for the certificate request This field is for certificate requests only. */ CertificateRequestFormat format; }; /** \class CRLContextProps qcaprovider.h QtCrypto X.509 certificate revocation list properties \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want CRL instead. For efficiency and simplicity, the members are directly accessed. \ingroup ProviderAPI */ class QCA_EXPORT CRLContextProps { public: /** The issuer information of the CRL */ CertificateInfoOrdered issuer; /** The CRL number, which increases at each update */ int number; /** The time this CRL was created */ QDateTime thisUpdate; /** The time this CRL expires, and the next CRL should be fetched */ QDateTime nextUpdate; /** The revoked entries */ QList revoked; /** The signature data of the CRL */ QByteArray sig; /** The signature algorithm used by the issuer to sign the CRL */ SignatureAlgorithm sigalgo; /** The issuer id */ QByteArray issuerId; }; class CRLContext; /** \class CertContext qcaprovider.h QtCrypto X.509 certificate provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want Certificate instead. \ingroup ProviderAPI */ class QCA_EXPORT CertContext : public CertBase { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ CertContext(Provider *p) : CertBase(p, "cert") {} /** Create a self-signed certificate based on the given options and private key. Returns true if successful, otherwise false. If successful, this object becomes the self-signed certificate. If unsuccessful, this object is considered to be in an uninitialized state. \param opts the options to set on the certificate \param priv the key to be used to sign the certificate */ virtual bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv) = 0; /** Returns a pointer to the properties of this certificate */ virtual const CertContextProps *props() const = 0; /** Returns true if this certificate is equal to another certificate, otherwise false \param other the certificate to compare with */ virtual bool compare(const CertContext *other) const = 0; /** Returns a copy of this certificate's public key. The caller is responsible for deleting it. */ virtual PKeyContext *subjectPublicKey() const = 0; /** Returns true if this certificate is an issuer of another certificate, otherwise false \param other the issued certificate to check */ virtual bool isIssuerOf(const CertContext *other) const = 0; /** Validate this certificate This function is blocking. \param trusted list of trusted certificates \param untrusted list of untrusted certificates (can be empty) \param crls list of CRLs (can be empty) \param u the desired usage for this certificate \param vf validation options */ virtual Validity validate(const QList &trusted, const QList &untrusted, const QList &crls, UsageMode u, ValidateFlags vf) const = 0; /** Validate a certificate chain. This function makes no use of the certificate represented by this object, and it can be used even if this object is in an uninitialized state. This function is blocking. \param chain list of certificates in the chain, starting with the user certificate. It is not necessary for the chain to contain the final root certificate. \param trusted list of trusted certificates \param crls list of CRLs (can be empty) \param u the desired usage for the user certificate in the chain \param vf validation options */ virtual Validity validate_chain(const QList &chain, const QList &trusted, const QList &crls, UsageMode u, ValidateFlags vf) const = 0; }; /** \class CSRContext qcaprovider.h QtCrypto X.509 certificate request provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want CertificateRequest instead. \ingroup ProviderAPI */ class QCA_EXPORT CSRContext : public CertBase { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ CSRContext(Provider *p) : CertBase(p, "csr") {} /** Returns true if the provider of this object supports the specified format, otherwise false \param f the format to test for support for. */ virtual bool canUseFormat(CertificateRequestFormat f) const = 0; /** Create a certificate request based on the given options and private key. Returns true if successful, otherwise false. If successful, this object becomes the certificate request. If unsuccessful, this object is considered to be in an uninitialized state. \param opts the options to set on the certificate \param priv the key to be used to sign the certificate */ virtual bool createRequest(const CertificateOptions &opts, const PKeyContext &priv) = 0; /** Returns a pointer to the properties of this certificate request */ virtual const CertContextProps *props() const = 0; /** Returns true if this certificate request is equal to another certificate request, otherwise false \param other the certificate request to compare with */ virtual bool compare(const CSRContext *other) const = 0; /** Returns a copy of this certificate request's public key. The caller is responsible for deleting it. */ virtual PKeyContext *subjectPublicKey() const = 0; /** Convert this certificate request to Netscape SPKAC format, and return the value Returns an empty string on error. */ virtual QString toSPKAC() const = 0; /** Read Netscape SPKAC input and convert it into a certificate request Returns QCA::ConvertGood if successful, otherwise some error value. \param s the input data */ virtual ConvertResult fromSPKAC(const QString &s) = 0; }; /** \class CRLContext qcaprovider.h QtCrypto X.509 certificate revocation list provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want CRL instead. \ingroup ProviderAPI */ class QCA_EXPORT CRLContext : public CertBase { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ CRLContext(Provider *p) : CertBase(p, "crl") {} /** Returns a pointer to the properties of this CRL */ virtual const CRLContextProps *props() const = 0; /** Returns true if this CRL is equal to another CRL, otherwise false \param other the CRL to compare with */ virtual bool compare(const CRLContext *other) const = 0; }; /** \class CertCollectionContext qcaprovider.h QtCrypto X.509 certificate collection provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want CertificateCollection instead. \ingroup ProviderAPI */ class QCA_EXPORT CertCollectionContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context */ CertCollectionContext(Provider *p) : BasicContext(p, "certcollection") {} /** Create PKCS#7 DER output based on the input certificates and CRLs Returns an empty array on error. \param certs list of certificates to store in the output \param crls list of CRLs to store in the output */ virtual QByteArray toPKCS7(const QList &certs, const QList &crls) const = 0; /** Read PKCS#7 DER input and convert it into a list of certificates and CRLs The caller is responsible for deleting the returned items. Returns QCA::ConvertGood if successful, otherwise some error value. \param a the input data \param certs the destination list for the certificates \param crls the destination list for the CRLs */ virtual ConvertResult fromPKCS7(const QByteArray &a, QList *certs, QList *crls) const = 0; }; /** \class CAContext qcaprovider.h QtCrypto X.509 certificate authority provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want CertificateAuthority instead. \ingroup ProviderAPI */ class QCA_EXPORT CAContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context */ CAContext(Provider *p) : BasicContext(p, "ca") {} /** Prepare the object for usage This must be called before any CA operations are performed. \param cert the certificate of the CA \param priv the private key of the CA */ virtual void setup(const CertContext &cert, const PKeyContext &priv) = 0; /** Returns a copy of the CA's certificate. The caller is responsible for deleting it. */ virtual CertContext *certificate() const = 0; /** Issue a certificate based on a certificate request, and return the certificate. The caller is responsible for deleting it. \param req the certificate request \param notValidAfter the expiration date */ virtual CertContext *signRequest(const CSRContext &req, const QDateTime ¬ValidAfter) const = 0; /** Issue a certificate based on a public key and options, and return the certificate. The caller is responsible for deleting it. \param pub the public key of the certificate \param opts the options to use for generation */ virtual CertContext *createCertificate(const PKeyContext &pub, const CertificateOptions &opts) const = 0; /** Create a new CRL and return it. The caller is responsible for deleting it. The CRL has no entries in it. \param nextUpdate the expiration date of the CRL */ virtual CRLContext *createCRL(const QDateTime &nextUpdate) const = 0; /** Update an existing CRL, by examining an old one and creating a new one based on it. The new CRL is returned, and the caller is responsible for deleting it. \param crl an existing CRL issued by this CA \param entries the list of revoked entries \param nextUpdate the expiration date of the new CRL */ virtual CRLContext *updateCRL(const CRLContext &crl, const QList &entries, const QDateTime &nextUpdate) const = 0; }; /** \class PKCS12Context qcaprovider.h QtCrypto PKCS#12 provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want KeyBundle instead. \ingroup ProviderAPI */ class QCA_EXPORT PKCS12Context : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context */ PKCS12Context(Provider *p) : BasicContext(p, "pkcs12") {} /** Create PKCS#12 DER output based on a set of input items Returns an empty array on error. \param name the friendly name of the data \param chain the certificate chain to store \param priv the private key to store \param passphrase the passphrase to encrypt the PKCS#12 data with */ virtual QByteArray toPKCS12(const QString &name, const QList &chain, const PKeyContext &priv, const SecureArray &passphrase) const = 0; /** Read PKCS#12 DER input and convert it into a set of output items The caller is responsible for deleting the returned items. Returns QCA::ConvertGood if successful, otherwise some error value. \param in the input data \param passphrase the passphrase needed to decrypt the input data \param name the destination string for the friendly name \param chain the destination list for the certificate chain \param priv address of a pointer to accept the private key */ virtual ConvertResult fromPKCS12(const QByteArray &in, const SecureArray &passphrase, QString *name, QList *chain, PKeyContext **priv) const = 0; }; /** \class PGPKeyContextProps qcaprovider.h QtCrypto OpenPGP key properties \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want PGPKey instead. For efficiency and simplicity, the members are directly accessed. \ingroup ProviderAPI */ class QCA_EXPORT PGPKeyContextProps { public: /** The key id */ QString keyId; /** List of user id strings for the key, the first one being the primary user id */ QStringList userIds; /** True if this key is a secret key, otherwise false */ bool isSecret; /** The time the key was created */ QDateTime creationDate; /** The time the key expires */ QDateTime expirationDate; /** The hex fingerprint of the key The format is all lowercase with no spaces. */ QString fingerprint; /** True if this key is in a keyring (and thus usable), otherwise false */ bool inKeyring; /** True if this key is trusted (e.g. signed by the keyring owner or via some web-of-trust), otherwise false */ bool isTrusted; }; /** \class PGPKeyContext qcaprovider.h QtCrypto OpenPGP key provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want PGPKey instead. \ingroup ProviderAPI */ class QCA_EXPORT PGPKeyContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context */ PGPKeyContext(Provider *p) : BasicContext(p, "pgpkey") {} /** Returns a pointer to the properties of this key */ virtual const PGPKeyContextProps *props() const = 0; /** Convert the key to binary format, and return the value */ virtual QByteArray toBinary() const = 0; /** Convert the key to ascii-armored format, and return the value */ virtual QString toAscii() const = 0; /** Read binary input and convert it into a key Returns QCA::ConvertGood if successful, otherwise some error value. \param a the input data */ virtual ConvertResult fromBinary(const QByteArray &a) = 0; /** Read ascii-armored input and convert it into a key Returns QCA::ConvertGood if successful, otherwise some error value. \param s the input data */ virtual ConvertResult fromAscii(const QString &s) = 0; }; /** \class KeyStoreEntryContext qcaprovider.h QtCrypto KeyStoreEntry provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want KeyStoreEntry instead. \ingroup ProviderAPI */ class QCA_EXPORT KeyStoreEntryContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context */ KeyStoreEntryContext(Provider *p) : BasicContext(p, "keystoreentry") {} /** Returns the entry type */ virtual KeyStoreEntry::Type type() const = 0; /** Returns the entry id This id must be unique among all other entries in the same store. */ virtual QString id() const = 0; /** Returns the name of this entry */ virtual QString name() const = 0; /** Returns the id of the store that contains this entry */ virtual QString storeId() const = 0; /** Returns the name of the store that contains this entry */ virtual QString storeName() const = 0; /** Returns true if the private key of this entry is present for use */ virtual bool isAvailable() const; /** Serialize the information about this entry This allows the entry object to be restored later, even if the store that contains it is not present. \sa KeyStoreListContext::entryPassive() */ virtual QString serialize() const = 0; /** If this entry is of type KeyStoreEntry::TypeKeyBundle, this function returns the KeyBundle of the entry */ virtual KeyBundle keyBundle() const; /** If this entry is of type KeyStoreEntry::TypeCertificate, this function returns the Certificate of the entry */ virtual Certificate certificate() const; /** If this entry is of type KeyStoreEntry::TypeCRL, this function returns the CRL of the entry */ virtual CRL crl() const; /** If this entry is of type KeyStoreEntry::TypePGPSecretKey, this function returns the secret PGPKey of the entry */ virtual PGPKey pgpSecretKey() const; /** If this entry is of type KeyStoreEntry::TypePGPPublicKey or KeyStoreEntry::TypePGPSecretKey, this function returns the public PGPKey of the entry */ virtual PGPKey pgpPublicKey() const; /** Attempt to ensure the private key of this entry is usable and accessible, potentially prompting the user and/or performing a login to a token device. Returns true if the entry is now accessible, or false if the entry cannot be made accessible. This function is blocking. */ virtual bool ensureAccess(); }; /** \class KeyStoreListContext qcaprovider.h QtCrypto KeyStore provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want KeyStore instead. \ingroup ProviderAPI */ class QCA_EXPORT KeyStoreListContext : public Provider::Context { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context */ KeyStoreListContext(Provider *p) : Provider::Context(p, "keystorelist") {} /** Starts the keystore provider */ virtual void start(); /** Enables or disables update events The updated() and storeUpdated() signals might not be emitted if updates are not enabled. \param enabled whether update notifications are enabled (true) or disabled (false) */ virtual void setUpdatesEnabled(bool enabled); /** Returns a list of integer context ids, each representing a keystore instance If a keystore becomes unavailable and then later becomes available again (for example, if a smart card is removed and then the same one is inserted again), the integer context id must be different than last time. */ virtual QList keyStores() = 0; /** Returns the type of the specified store, or -1 if the integer context id is invalid \param id the id for the store context */ virtual KeyStore::Type type(int id) const = 0; /** Returns the string id of the store, or an empty string if the integer context id is invalid The string id of the store should be unique to a single store, and it should persist between availability/unavailability. For example, a smart card that is removed and inserted again should have the same string id (despite having a new integer context id). \param id the id for the store context */ virtual QString storeId(int id) const = 0; /** Returns the friendly name of the store, or an empty string if the integer context id is invalid \param id the id for the store context */ virtual QString name(int id) const = 0; /** Returns true if the store is read-only If the integer context id is invalid, this function should return true. \param id the id for the store context */ virtual bool isReadOnly(int id) const; /** Returns the types supported by the store, or an empty list if the integer context id is invalid This function should return all supported types, even if the store doesn't actually contain entries for all of the types. \param id the id for the store context */ virtual QList entryTypes(int id) const = 0; /** Returns the entries of the store, or an empty list if the integer context id is invalid The caller is responsible for deleting the returned entry objects. \param id the id for the store context */ virtual QList entryList(int id) = 0; /** Returns a single entry in the store, if the entry id is already known. If the entry does not exist, the function returns 0. The caller is responsible for deleting the returned entry object. \param id the id for the store context \param entryId the entry to retrieve */ virtual KeyStoreEntryContext *entry(int id, const QString &entryId); /** Returns a single entry, created from the serialization string of a previous entry (using KeyStoreEntryContext::serialize()). If the serialization string cannot be parsed by this provider, or the entry cannot otherwise be created, the function returns 0. The caller is responsible for deleting the returned entry object. This function must be thread-safe. \param serialized the serialized data to create the entry from */ virtual KeyStoreEntryContext *entryPassive(const QString &serialized); /** Write a KeyBundle to the store Returns the entry id of the new item, or an empty string if there was an error writing the item. \param id the id for the store context \param kb the key bundle to add to the store */ virtual QString writeEntry(int id, const KeyBundle &kb); /** Write a Certificate to the store Returns the entry id of the new item, or an empty string if there was an error writing the item. \param id the id for the store context \param cert the certificate to add to the store */ virtual QString writeEntry(int id, const Certificate &cert); /** Write a CRL to the store Returns the entry id of the new item, or an empty string if there was an error writing the item. \param id the id for the store context \param crl the revocation list to add to the store */ virtual QString writeEntry(int id, const CRL &crl); /** Write a PGPKey to the store Returns the entry id of the new item, or an empty string if there was an error writing the item. \param id the id for the store context \param key the PGP key to add to the store */ virtual QString writeEntry(int id, const PGPKey &key); /** Remove an entry from the store Returns true if the entry is successfully removed, otherwise false. \param id the id for the store context \param entryId the entry to remove from the store */ virtual bool removeEntry(int id, const QString &entryId); Q_SIGNALS: /** Emit this when the provider is busy looking for keystores. The provider goes into a busy state when it has reason to believe there are keystores present, but it still needs to check or query some devices to see for sure. For example, if a smart card is inserted, then the provider may immediately go into a busy state upon detecting the insert. However, it may take some seconds before the smart card information can be queried and reported by the provider. Once the card is queried successfully, the provider would leave the busy state and report the new keystore. When this object is first started with start(), it is assumed to be in the busy state, so there is no need to emit this signal at the beginning. */ void busyStart(); /** Emit this to leave the busy state When this object is first started with start(), it is assumed to be in the busy state. You must emit busyEnd() at some point, or QCA will never ask you about keystores. */ void busyEnd(); /** Indicates the list of keystores has changed, and that QCA should call keyStores() to obtain the latest list */ void updated(); /** Emitted when there is diagnostic text to report \param str the diagnostic text */ void diagnosticText(const QString &str); /** Indicates that the entry list of a keystore has changed (entries added, removed, or modified) \param id the id of the key store that has changed */ void storeUpdated(int id); }; /** \class TLSSessionContext qcaprovider.h QtCrypto TLS "session" provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want TLSSession instead. \ingroup ProviderAPI */ class QCA_EXPORT TLSSessionContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the Provider associated with this context */ TLSSessionContext(Provider *p) : BasicContext(p, "tlssession") {} }; /** \class TLSContext qcaprovider.h QtCrypto TLS provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want TLS instead. \ingroup ProviderAPI */ class QCA_EXPORT TLSContext : public Provider::Context { Q_OBJECT public: /** \class QCA::TLSContext::SessionInfo qcaprovider.h QtCrypto Information about an active TLS connection For efficiency and simplicity, the members are directly accessed. \ingroup ProviderAPI */ class SessionInfo { public: /** True if the TLS connection is compressed, otherwise false */ bool isCompressed; /** The TLS protocol version being used for this connection */ TLS::Version version; /** The cipher suite being used for this connection \sa TLSContext::supportedCipherSuites() */ QString cipherSuite; /** The bit size of the cipher used for this connection */ int cipherBits; /** The maximum bit size possible of the cipher used for this connection */ int cipherMaxBits; /** Pointer to the id of this TLS session, for use with resuming */ TLSSessionContext *id; }; /** Result of a TLS operation */ enum Result { Success, ///< Operation completed Error, ///< Operation failed Continue ///< More data needed to complete operation }; /** Standard constructor \param p the Provider associated with this context \param type the name of the type of feature that supported by this context */ TLSContext(Provider *p, const QString &type) : Provider::Context(p, type) {} /** Reset the object to its initial state */ virtual void reset() = 0; /** Returns a list of supported cipher suites for the specified SSL/TLS version. The cipher suites are specified as strings, for example: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA" (without quotes). \param version the version of TLS to search for */ virtual QStringList supportedCipherSuites(const TLS::Version &version) const = 0; /** Returns true if the provider supports compression */ virtual bool canCompress() const = 0; /** Returns true if the provider supports server name indication */ virtual bool canSetHostName() const = 0; /** Returns the maximum SSF supported by this provider */ virtual int maxSSF() const = 0; /** Configure a new session This function will be called before any other configuration functions. \param serverMode whether to operate as a server (true) or client (false) \param hostName the hostname to use \param compress whether to compress (true) or not (false) */ virtual void setup(bool serverMode, const QString &hostName, bool compress) = 0; /** Set the constraints of the session using SSF values This function will be called before start(). \param minSSF the minimum strength factor that is acceptable \param maxSSF the maximum strength factor that is acceptable */ virtual void setConstraints(int minSSF, int maxSSF) = 0; /** \overload Set the constraints of the session using a cipher suite list This function will be called before start(). \param cipherSuiteList the list of cipher suites that may be used for this session. \sa supportedCipherSuites */ virtual void setConstraints(const QStringList &cipherSuiteList) = 0; /** Set the list of trusted certificates This function may be called at any time. \param trusted the trusted certificates and CRLs to be used. */ virtual void setTrustedCertificates(const CertificateCollection &trusted) = 0; /** Set the list of acceptable issuers This function may be called at any time. This function is for server mode only. \param issuerList the list of issuers that may be used */ virtual void setIssuerList(const QList &issuerList) = 0; /** Set the local certificate This function may be called at any time. \param cert the certificate and associated trust chain \param key the private key for the local certificate */ virtual void setCertificate(const CertificateChain &cert, const PrivateKey &key) = 0; /** Set the TLS session id, for session resuming This function will be called before start(). \param id the session identification */ virtual void setSessionId(const TLSSessionContext &id) = 0; /** Sets the session to the shutdown state. The actual shutdown operation will happen at a future call to update(). This function is for normal TLS only (not DTLS). */ virtual void shutdown() = 0; /** Set the maximum transmission unit size This function is for DTLS only. \param size the maximum number of bytes in a datagram */ virtual void setMTU(int size); /** Begins the session, starting with the handshake This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, the result() function will return Success if the TLS session is able to begin, or Error if there is a failure to initialize the TLS subsystem. If successful, the session is now in the handshake state, and update() will be called repeatedly until the session ends. */ virtual void start() = 0; /** Performs one iteration of the TLS session processing This function returns immediately, and completion is signaled with the resultsReady() signal. If the session is in a handshake state, result() and to_net() will be valid. If result() is Success, then the session is now in the connected state. If the session is in a shutdown state, result() and to_net() will be valid. If result() is Success, then the session has ended. If the session is in a connected state, result(), to_net(), encoded(), to_app(), and eof() are valid. The result() function will return Success or Error. Note that eof() does not apply to DTLS. For DTLS, this function operates with single packets. Many update() operations must be performed repeatedly to exchange multiple packets. \param from_net the data from the "other side" of the connection \param from_app the data from the application of the protocol */ virtual void update(const QByteArray &from_net, const QByteArray &from_app) = 0; /** Waits for a start() or update() operation to complete. In this case, the resultsReady() signal is not emitted. Returns true if the operation completed or false if this function times out. This function is blocking. \param msecs number of milliseconds to wait (-1 to wait forever) */ virtual bool waitForResultsReady(int msecs) = 0; /** Returns the result code of an operation */ virtual Result result() const = 0; /** Returns data that should be sent across the network */ virtual QByteArray to_net() = 0; /** Returns the number of bytes of plaintext data that is encoded inside of to_net() */ virtual int encoded() const = 0; /** Returns data that is decoded from the network and should be processed by the application */ virtual QByteArray to_app() = 0; /** Returns true if the peer has closed the stream */ virtual bool eof() const = 0; /** Returns true if the TLS client hello has been received This is only valid if a handshake is in progress or completed. */ virtual bool clientHelloReceived() const = 0; /** Returns true if the TLS server hello has been received This is only valid if a handshake is in progress or completed. */ virtual bool serverHelloReceived() const = 0; /** Returns the host name sent by the client using server name indication (server mode only) This is only valid if a handshake is in progress or completed. */ virtual QString hostName() const = 0; /** Returns true if the peer is requesting a certificate This is only valid if a handshake is in progress or completed. */ virtual bool certificateRequested() const = 0; /** Returns the issuer list sent by the server (client mode only) This is only valid if a handshake is in progress or completed. */ virtual QList issuerList() const = 0; /** Returns the QCA::Validity of the peer certificate This is only valid if a handshake is completed. */ virtual Validity peerCertificateValidity() const = 0; /** Returns the peer certificate chain This is only valid if a handshake is completed. */ virtual CertificateChain peerCertificateChain() const = 0; /** Returns information about the active TLS session This is only valid if a handshake is completed. */ virtual SessionInfo sessionInfo() const = 0; /** Returns any unprocessed network input data This is only valid after a successful shutdown. */ virtual QByteArray unprocessed() = 0; Q_SIGNALS: /** Emit this when a start() or update() operation has completed. */ void resultsReady(); /** Emit this to force the application to call update(), even with empty arguments. */ void dtlsTimeout(); }; /** \class SASLContext qcaprovider.h QtCrypto SASL provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want SASL instead. \ingroup ProviderAPI */ class QCA_EXPORT SASLContext : public Provider::Context { Q_OBJECT public: /** \class QCA::SASLContext::HostPort qcaprovider.h QtCrypto Convenience class to hold an IP address and an associated port For efficiency and simplicity, the members are directly accessed. \ingroup ProviderAPI */ class HostPort { public: /** The IP address */ QString addr; /** The port */ quint16 port; }; /** Result of a SASL operation */ enum Result { Success, ///< Operation completed Error, ///< Operation failed Params, ///< Parameters are needed to complete authentication AuthCheck, ///< Client login can be inspected (server only) Continue ///< More steps needed to complete authentication }; /** Standard constructor \param p the Provider associated with this context */ SASLContext(Provider *p) : Provider::Context(p, "sasl") {} /** Reset the object to its initial state */ virtual void reset() = 0; /** Configure a new session This function will be called before any other configuration functions. \param service the name of the network service being provided by this application, which can be used by the SASL system for policy control. Examples: "imap", "xmpp" \param host the hostname that the application is interacting with or as \param local pointer to a HostPort representing the local end of a network socket, or 0 if this information is unknown or not available \param remote pointer to a HostPort representing the peer end of a network socket, or 0 if this information is unknown or not available \param ext_id the id to be used for SASL EXTERNAL (client only) \param ext_ssf the SSF of the external authentication channel (client only) */ virtual void setup(const QString &service, const QString &host, const HostPort *local, const HostPort *remote, const QString &ext_id, int ext_ssf) = 0; /** Set the constraints of the session using SSF values This function will be called before startClient() or startServer(). \param f the flags to use \param minSSF the minimum strength factor that is acceptable \param maxSSF the maximum strength factor that is acceptable */ virtual void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) = 0; /** Begins the session in client mode, starting with the authentication This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, result(), mech(), haveClientInit(), and stepData() will be valid. If result() is Success, then the session is now in the connected state. \param mechlist the list of mechanisms \param allowClientSendFirst whether the client sends first (true) or the server sends first (false) */ virtual void startClient(const QStringList &mechlist, bool allowClientSendFirst) = 0; /** Begins the session in server mode, starting with the authentication This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, result() and mechlist() will be valid. The result() function will return Success or Error. If the result is Success, then serverFirstStep() will be called next. \param realm the realm to authenticate in \param disableServerSendLast whether the client sends first (true) or the server sends first (false) */ virtual void startServer(const QString &realm, bool disableServerSendLast) = 0; /** Finishes server startup This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, result() and stepData() will be valid. If result() is Success, then the session is now in the connected state. \param mech the mechanism to use \param clientInit initial data from the client, or 0 if there is no such data */ virtual void serverFirstStep(const QString &mech, const QByteArray *clientInit) = 0; /** Perform another step of the SASL authentication This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, result() and stepData() will be valid. \param from_net the data from the "other side" of the protocol to be used for the next step. */ virtual void nextStep(const QByteArray &from_net) = 0; /** Attempt the most recent operation again. This is used if the result() of an operation is Params or AuthCheck. This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, result() and stepData() will be valid. */ virtual void tryAgain() = 0; /** Performs one iteration of the SASL security layer processing This function returns immediately, and completion is signaled with the resultsReady() signal. On completion, result(), to_net(), encoded(), and to_app() will be valid. The result() function will return Success or Error. \param from_net the data from the "other side" of the protocol \param from_app the data from the application of the protocol */ virtual void update(const QByteArray &from_net, const QByteArray &from_app) = 0; /** Waits for a startClient(), startServer(), serverFirstStep(), nextStep(), tryAgain(), or update() operation to complete. In this case, the resultsReady() signal is not emitted. Returns true if the operation completed or false if this function times out. This function is blocking. \param msecs number of milliseconds to wait (-1 to wait forever) */ virtual bool waitForResultsReady(int msecs) = 0; /** Returns the result code of an operation */ virtual Result result() const = 0; /** Returns the mechanism list (server mode only) */ virtual QStringList mechlist() const = 0; /** Returns the mechanism selected */ virtual QString mech() const = 0; /** Returns true if the client has initialization data */ virtual bool haveClientInit() const = 0; /** Returns an authentication payload for to be transmitted over the network */ virtual QByteArray stepData() const = 0; /** Returns data that should be sent across the network (for the security layer) */ virtual QByteArray to_net() = 0; /** Returns the number of bytes of plaintext data that is encoded inside of to_net() */ virtual int encoded() const = 0; /** Returns data that is decoded from the network and should be processed by the application */ virtual QByteArray to_app() = 0; /** Returns the SSF of the active SASL session This is only valid after authentication success. */ virtual int ssf() const = 0; /** Returns the reason for failure, if the authentication was not successful. This is only valid after authentication failure. */ virtual SASL::AuthCondition authCondition() const = 0; /** Returns the needed/optional client parameters This is only valid after receiving the Params result code. */ virtual SASL::Params clientParams() const = 0; /** Set some of the client parameters (pass 0 to not set a field) \param user the user name \param authzid the authorization name / role \param pass the password \param realm the realm to authenticate in */ virtual void setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) = 0; /** Returns the realm list (client mode only) This is only valid after receiving the Params result code and SASL::Params::canSendRealm is set to true. */ virtual QStringList realmlist() const = 0; /** Returns the username attempting to authenticate (server mode only) This is only valid after receiving the AuthCheck result code. */ virtual QString username() const = 0; /** Returns the authzid attempting to authorize (server mode only) This is only valid after receiving the AuthCheck result code. */ virtual QString authzid() const = 0; Q_SIGNALS: /** Emit this when a startClient(), startServer(), serverFirstStep(), nextStep(), tryAgain(), or update() operation has completed. */ void resultsReady(); }; /** \class MessageContext qcaprovider.h QtCrypto SecureMessage provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want SecureMessage instead. \ingroup ProviderAPI */ class QCA_EXPORT MessageContext : public Provider::Context { Q_OBJECT public: /** The type of operation being performed */ enum Operation { Encrypt, ///< Encrypt operation Decrypt, ///< Decrypt (or Decrypt and Verify) operation Sign, ///< Sign operation Verify, ///< Verify operation SignAndEncrypt ///< Sign and Encrypt operation }; /** Standard constructor \param p the Provider associated with this context \param type the name of the type of secure message to be created */ MessageContext(Provider *p, const QString &type) : Provider::Context(p, type) {} /** Returns true if the provider supports multiple signers for signature creation or signature verification */ virtual bool canSignMultiple() const = 0; /** The type of secure message (e.g. PGP or CMS) */ virtual SecureMessage::Type type() const = 0; /** Reset the object to its initial state */ virtual void reset() = 0; /** Configure a new encrypting operation \param keys the keys to be used for encryption. */ virtual void setupEncrypt(const SecureMessageKeyList &keys) = 0; /** Configure a new signing operation \param keys the keys to use for signing \param m the mode to sign in \param bundleSigner whether to bundle the signing keys (true) or not (false) \param smime whether to use smime format (true) or not (false) */ virtual void setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool bundleSigner, bool smime) = 0; /** Configure a new verify operation \param detachedSig the detached signature to use (if applicable) for verification */ virtual void setupVerify(const QByteArray &detachedSig) = 0; /** Begins the secure message operation This function returns immediately. If there is input data, update() will be called (potentially repeatedly) afterwards. Emit updated() if there is data to read, if input data has been accepted, or if the operation has finished. \param f the format of the message to be produced \param op the operation to be performed */ virtual void start(SecureMessage::Format f, Operation op) = 0; /** Provide input to the message operation \param in the data to use for the message operation */ virtual void update(const QByteArray &in) = 0; /** Extract output from the message operation */ virtual QByteArray read() = 0; /** Returns the number of input bytes accepted since the last call to update() */ virtual int written() = 0; /** Indicates the end of input */ virtual void end() = 0; /** Returns true if the operation has finished, otherwise false */ virtual bool finished() const = 0; /** Waits for the secure message operation to complete. In this case, the updated() signal is not emitted. Returns true if the operation completed or false if this function times out. This function is blocking. \param msecs number of milliseconds to wait (-1 to wait forever) */ virtual bool waitForFinished(int msecs) = 0; /** Returns true if the operation was successful This is only valid if the operation has finished. */ virtual bool success() const = 0; /** Returns the reason for failure, if the operation was not successful This is only valid if the operation has finished. */ virtual SecureMessage::Error errorCode() const = 0; /** Returns the signature, in the case of a detached signature operation This is only valid if the operation has finished. */ virtual QByteArray signature() const = 0; /** Returns the name of the hash used to generate the signature, in the case of a signature operation This is only valid if the operation has finished. */ virtual QString hashName() const = 0; /** Returns a list of signatures, in the case of a verify or decrypt and verify operation This is only valid if the operation has finished. */ virtual SecureMessageSignatureList signers() const = 0; /** Returns any diagnostic text for the operation, potentially useful to show the user in the event the operation is unsuccessful. For example, this could be the stderr output of gpg. This is only valid if the operation has finished. */ virtual QString diagnosticText() const; Q_SIGNALS: /** Emitted when there is data to read, if input data has been accepted, or if the operation has finished */ void updated(); }; /** \class SMSContext qcaprovider.h QtCrypto SecureMessageSystem provider \note This class is part of the provider plugin interface and should not be used directly by applications. You probably want SecureMessageSystem instead. \ingroup ProviderAPI */ class QCA_EXPORT SMSContext : public BasicContext { Q_OBJECT public: /** Standard constructor \param p the provider associated with this context \param type the name of the type of secure message system */ SMSContext(Provider *p, const QString &type) : BasicContext(p, type) {} /** Set the trusted certificates and for this secure message system, to be used for validation The collection may also contain CRLs. This function is only valid for CMS. \param trusted a set of trusted certificates and CRLs. */ virtual void setTrustedCertificates(const CertificateCollection &trusted); /** Set the untrusted certificates and CRLs for this secure message system, to be used for validation This function is only valid for CMS. \param untrusted a set of untrusted certificates and CRLs. */ virtual void setUntrustedCertificates(const CertificateCollection &untrusted); /** Set the private keys for this secure message system, to be used for decryption This function is only valid for CMS. \param keys the keys to be used for decryption */ virtual void setPrivateKeys(const QList &keys); /** Create a new message object for this system. The caller is responsible for deleting it. */ virtual MessageContext *createMessage() = 0; }; } #endif #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_textfilter.h0000644000175000017500000001663711305557613022534 0ustar janjan/* * qca_textfilter.h - Qt Cryptographic Architecture * Copyright (C) 2003-2005 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_textfilter.h Header file for text encoding/decoding classes \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_TEXTFILTER_H #define QCA_TEXTFILTER_H #include "qca_core.h" namespace QCA { /** \class TextFilter qca_textfilter.h QtCrypto Superclass for text based filtering algorithms This differs from Filter in that it has the concept of an algorithm that works in two directions, and supports operations on QString arguments. \ingroup UserAPI */ class QCA_EXPORT TextFilter : public Filter { public: /** Standard constructor \param dir the Direction that this TextFilter should use. */ TextFilter(Direction dir); /** Reset the TextFilter \param dir the Direction that this TextFilter should use. */ void setup(Direction dir); /** The direction the TextFilter is set up to use */ Direction direction() const; /** Process an array in the "forward" direction, returning an array This method runs in the forward direction, so for something like a Base64 encoding, it takes the "native" array, and returns that array encoded in base64. \param a the array to encode */ MemoryRegion encode(const MemoryRegion &a); /** Process an array in the "reverse" direction, returning an array This method runs in the reverse direction, so for something like a Base64 encoding, it takes a Base64 encoded array, and returns the "native" representation. \param a the array to decode */ MemoryRegion decode(const MemoryRegion &a); /** Process an array in the "forward" direction, returning a QString This is equivalent to encode(), except that it returns a QString, rather than a byte array. \param a the array to encode */ QString arrayToString(const MemoryRegion &a); /** Process an string in the "reverse" direction, returning a byte array This is equivalent to decode(), except that it takes a QString, rather than a byte array. \param s the array to decode */ MemoryRegion stringToArray(const QString &s); /** Process a string in the "forward" direction, returning a string This is equivalent to encode(), except that it takes and returns a QString, rather than byte arrays. \param s the string to encode */ QString encodeString(const QString &s); /** Process a string in the "reverse" direction, returning a string This is equivalent to decode(), except that it takes and returns a QString, rather than byte arrays. \param s the string to decode */ QString decodeString(const QString &s); protected: /** Internal state variable for the Direction that the filter operates in */ Direction _dir; }; /** \class Hex qca_textfilter.h QtCrypto Hexadecimal encoding / decoding \ingroup UserAPI */ class QCA_EXPORT Hex : public TextFilter { public: /** Standard constructor \param dir the Direction that should be used. \note The direction can be changed using the setup() call. */ Hex(Direction dir = Encode); /** Reset the internal state. This is useful to reuse an existing Hex object */ virtual void clear(); /** Process more data, returning the corresponding encoded or decoded (depending on the Direction set in the constructor or setup() call) representation. If you find yourself with code that only calls this method once, you might be better off using encode() or decode(). Similarly, if the data is really a string, you might be better off using arrayToString(), encodeString(), stringToArray() or decodeString(). \param a the array containing data to process */ virtual MemoryRegion update(const MemoryRegion &a); /** Complete the algorithm \return any remaining output. Because of the way hexadecimal encoding works, this will return a zero length array - any output will have been returned from the update() call. */ virtual MemoryRegion final(); /** Test if an update() or final() call succeeded. \return true if the previous call succeeded */ virtual bool ok() const; private: Q_DISABLE_COPY(Hex) uchar val; bool partial; bool _ok; }; /** \class Base64 qca_textfilter.h QtCrypto %Base64 encoding / decoding \ingroup UserAPI */ class QCA_EXPORT Base64 : public TextFilter { public: /** Standard constructor \param dir the Direction that should be used. \note The direction can be changed using the setup() call. */ Base64(Direction dir = Encode); /** Returns true if line breaks are enabled */ bool lineBreaksEnabled() const; /** Returns the line break column */ int lineBreaksColumn() const; /** Sets line break mode. If enabled, linebreaks will be added to encoded output or accepted in encoded input. If disabled, linebreaks in encoded input will cause a failure to decode. The default is disabled. \param b whether to enable line breaks (true) or disable line breaks (false) */ void setLineBreaksEnabled(bool b); /** Sets the column that linebreaks should be inserted at when encoding. \param column the column number that line breaks should be inserted at. */ void setLineBreaksColumn(int column); /** Reset the internal state. This is useful to reuse an existing Base64 object */ virtual void clear(); /** Process more data, returning the corresponding encoded or decoded (depending on the Direction set in the constructor or setup() call) representation. If you find yourself with code that only calls this method once, you might be better off using encode() or decode(). Similarly, if the data is really a string, you might be better off using arrayToString(), encodeString(), stringToArray() or decodeString(). \param a the array containing data to process */ virtual MemoryRegion update(const MemoryRegion &a); /** Complete the algorithm \return any remaining output. Because of the way Base64 encoding works, you will get either an empty array, or an array containing one or two "=" (equals, 0x3D) characters. */ virtual MemoryRegion final(); /** Test if an update() or final() call succeeded. \return true if the previous call succeeded */ virtual bool ok() const; private: Q_DISABLE_COPY(Base64) QByteArray partial; bool _ok; int col; bool _lb_enabled; int _lb_column; class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qpipe.h0000644000175000017500000002570611305557613020631 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qpipe.h Header file for the QPipe FIFO class \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QPIPE_H #define QPIPE_H #ifndef DOXYGEN_SHOULD_SKIP_THIS #ifndef QPIPE_NO_SECURE # define QPIPE_SECURE #endif #ifdef QPIPE_SECURE # include "QtCrypto" #else # define QCA_EXPORT #endif // defs adapted qprocess_p.h #ifdef Q_OS_WIN #include typedef HANDLE Q_PIPE_ID; #define INVALID_Q_PIPE_ID INVALID_HANDLE_VALUE #else typedef int Q_PIPE_ID; #define INVALID_Q_PIPE_ID -1 #endif #endif // Note: for Windows console, I/O must be in UTF-8. Reads are guaranteed to // to completely decode (no partial characters). Likewise, writes must // not contain partial characters. namespace QCA { /** \class QPipeDevice qpipe.h QtCrypto Unbuffered direct pipe. This class is not usually required except for very low level operations. You should use QPipe and QPipeEnd for most applications. \ingroup UserAPI */ class QCA_EXPORT QPipeDevice : public QObject { Q_OBJECT public: /** The type of device */ enum Type { Read, ///< The pipe end can be read from Write ///< The pipe end can be written to }; /** Standard constructor \param parent the parent object to this object */ QPipeDevice(QObject *parent = 0); ~QPipeDevice(); /** The Type of the pipe device (that is, read or write) */ Type type() const; /** Test whether this object corresponds to a valid pipe */ bool isValid() const; /** The low level identification for this pipe. On Windows, this is a HANDLE. On Unix, this is a file descriptor (i.e. integer). Code using this method should be carefully tested for portability. \sa idAsInt */ Q_PIPE_ID id() const; /** The low level identification for this pipe, returned as an integer. Code using this method should be carefully tested for portability. \sa id(). */ int idAsInt() const; /** Take over an existing pipe id, closing the old pipe if any. \param id the identification of the pipe end to take over. \param t the type of pipe end (read or write). */ void take(Q_PIPE_ID id, Type t); /** Enable the pipe for reading or writing (depending on Type) */ void enable(); /** Close the pipe end. */ void close(); /** Release the pipe end, but do not close it. */ void release(); /** Set the pipe end to be inheritable \note On Windows, this operation changes the pipe end id value. \param enabled whether the pipe is inheritable (true) or not (false) */ bool setInheritable(bool enabled); /** Obtain the number of bytes available to be read. */ int bytesAvailable() const; /** Read from the pipe end \param data where to put the data that has been read \param maxsize the maximum number of bytes to be read. \return the actual number of bytes read, 0 on end-of-file, or -1 on error. */ int read(char *data, int maxsize); /** Write to the pipe end. \param data the source of the data to be written \param size the number of bytes in the data to be written \note the data source must remain valid \return the number of bytes written, or -1 on error. */ int write(const char *data, int size); /** The result of a write operation \param written if not null, this will be set to the number of bytes written in the last operation. \return 0 on success (all data written), or -1 on error */ int writeResult(int *written) const; Q_SIGNALS: /** Emitted when the pipe end can be read from or written to (depending on its Type). */ void notify(); private: Q_DISABLE_COPY(QPipeDevice) class Private; friend class Private; Private *d; }; /** \class QPipeEnd qpipe.h QtCrypto A buffered higher-level pipe end This is either the read end or write end of a QPipe. \ingroup UserAPI */ class QCA_EXPORT QPipeEnd : public QObject { Q_OBJECT public: /** The type of error */ enum Error { ErrorEOF, ///< End of file error ErrorBroken ///< Broken pipe error }; /** Standard constructor \param parent the parent object for this object */ QPipeEnd(QObject *parent = 0); ~QPipeEnd(); /** Reset the pipe end to an inactive state */ void reset(); /** The type of pipe end (either read or write) */ QPipeDevice::Type type() const; /** Determine whether the pipe end is valid. \note This does not mean the pipe is ready to be used - you may need to call enable() first */ bool isValid() const; /** Pipe identification */ Q_PIPE_ID id() const; /** Pipe identification */ int idAsInt() const; /** Take over an existing pipe handle \param id the pipe handle \param t the type of the pipe (read or write) */ void take(Q_PIPE_ID id, QPipeDevice::Type t); #ifdef QPIPE_SECURE /** Sets whether the pipe uses secure memory for read/write Enabling this may reduce performance, and it should only be used if sensitive data is being transmitted (such as a passphrase). \param secure whether the pipe uses secure memory (true) or not (false). */ void setSecurityEnabled(bool secure); #endif /** Enable the endpoint for the pipe When an endpoint is created, it is not able to be used until it is enabled. */ void enable(); /** Close the end of the pipe \sa closed() */ void close(); /** Let go of the active pipe handle, but don't close it Use this before destructing QPipeEnd, if you don't want the pipe to automatically close. */ void release(); /** Sets whether the pipe should be inheritable to child processes Returns true if inheritability was successfully changed, otherwise false. \param enabled whether the pipe is inheritable (true) or not (false). */ bool setInheritable(bool enabled); /** Clear the contents of the pipe, and invalidate the pipe */ void finalize(); /** Clear the contents of the pipe, and release the pipe */ void finalizeAndRelease(); /** Determine how many bytes are available to be read. This only makes sense at the read end of the pipe \sa readyRead() for a signal that can be used to determine when there are bytes available to read. */ int bytesAvailable() const; /** Returns the number of bytes pending to write This only makes sense at the write end of the pipe \sa bytesWritten() for a signal that can be used to determine when bytes have been written */ int bytesToWrite() const; /** Read bytes from the pipe. You can only call this on the read end of the pipe If the pipe is using secure memory, you should use readSecure() \param bytes the number of bytes to read (-1 for all content). */ QByteArray read(int bytes = -1); /** Write bytes to the pipe. You can only call this on the write end of the pipe. If the pipe is using secure memory, you should use writeSecure(). \param a the array to write to the pipe */ void write(const QByteArray &a); #ifdef QPIPE_SECURE /** Read bytes from the pipe. You can only call this on the read end of the pipe If the pipe is using insecure memory, you should use read() \param bytes the number of bytes to read (-1 for all content). */ SecureArray readSecure(int bytes = -1); /** Write bytes to the pipe. You can only call this on the write end of the pipe. If the pipe is using insecure memory, you should use write(). \param a the array to write to the pipe */ void writeSecure(const SecureArray &a); #endif /** Returns any unsent bytes queued for writing If the pipe is using secure memory, you should use takeBytesToWriteSecure(). */ QByteArray takeBytesToWrite(); #ifdef QPIPE_SECURE /** Returns any unsent bytes queued for writing If the pipe is using insecure memory, you should use takeBytesToWrite(). */ SecureArray takeBytesToWriteSecure(); #endif Q_SIGNALS: /** Emitted when there are bytes available to be read from the read end of the pipe. \sa bytesAvailable() */ void readyRead(); /** Emitted when bytes have been written to the write end of the pipe. \param bytes the number of bytes written */ void bytesWritten(int bytes); /** Emitted when this end of the pipe is closed as a result of calling close() If this is the write end of the pipe and there is data still pending to write, this signal will be emitted once all of the data has been written. To be notified if the other end of the pipe has been closed, see error(). */ void closed(); /** Emitted when the pipe encounters an error trying to read or write, or if the other end of the pipe has been closed \param e the reason for error */ void error(QCA::QPipeEnd::Error e); private: Q_DISABLE_COPY(QPipeEnd) class Private; friend class Private; Private *d; }; /** \class QPipe qpipe.h QtCrypto A FIFO buffer (named pipe) abstraction This class creates a full buffer, consisting of two ends (QPipeEnd). You can obtain each end (after calling create()) using readEnd() and writeEnd(), however you must call enable() on each end before using the pipe. By default, the pipe ends are not inheritable by child processes. On Windows, the pipe is created with inheritability disabled. On Unix, the FD_CLOEXEC flag is set on each end's file descriptor. \ingroup UserAPI */ class QCA_EXPORT QPipe { public: /** Standard constructor \note You must call create() before using the pipe ends. \param parent the parent object for this object */ QPipe(QObject *parent = 0); ~QPipe(); /** Reset the pipe. At this point, the readEnd() and writeEnd() calls will no longer be valid. */ void reset(); #ifdef QPIPE_SECURE /** Create the pipe \param secure whether to use secure memory (true) or not (false) */ bool create(bool secure = false); #else /** Create the pipe */ bool create(); #endif /** The read end of the pipe. */ QPipeEnd & readEnd() { return i; } /** The write end of the pipe. */ QPipeEnd & writeEnd() { return o; } private: Q_DISABLE_COPY(QPipe) QPipeEnd i, o; }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_securemessage.h0000644000175000017500000005432611305557613023172 0ustar janjan/* * qca_securemessage.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_securemessage.h Header file for secure message (PGP, CMS) classes \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_SECUREMESSAGE_H #define QCA_SECUREMESSAGE_H #include #include "qca_core.h" #include "qca_publickey.h" #include "qca_cert.h" class QDateTime; namespace QCA { class SecureMessageSystem; /** \class SecureMessageKey qca_securemessage.h QtCrypto Key for SecureMessage system \ingroup UserAPI */ class QCA_EXPORT SecureMessageKey { public: /** The key type */ enum Type { None, ///< no key PGP, ///< Pretty Good Privacy key X509 ///< X.509 CMS key }; /** Construct an empty key */ SecureMessageKey(); /** Standard copy constructor \param from the source key */ SecureMessageKey(const SecureMessageKey &from); ~SecureMessageKey(); /** Standard assignment operator \param from the source key */ SecureMessageKey & operator=(const SecureMessageKey &from); /** Returns true for null object */ bool isNull() const; /** The key type */ Type type() const; /** Public key part of a PGP key */ PGPKey pgpPublicKey() const; /** Private key part of a PGP key */ PGPKey pgpSecretKey() const; /** Set the public key part of a PGP key \param pub the PGP public key */ void setPGPPublicKey(const PGPKey &pub); /** Set the private key part of a PGP key \param sec the PGP secretkey */ void setPGPSecretKey(const PGPKey &sec); /** The X.509 certificate chain (public part) for this key */ CertificateChain x509CertificateChain() const; /** The X.509 private key part of this key */ PrivateKey x509PrivateKey() const; /** Set the public key part of this X.509 key. \param c the Certificate chain containing the public keys */ void setX509CertificateChain(const CertificateChain &c); /** Set the private key part of this X.509 key. \param k the private key */ void setX509PrivateKey(const PrivateKey &k); /** Set the public and private part of this X.509 key with KeyBundle. \param kb the public and private key bundle */ void setX509KeyBundle(const KeyBundle &kb); /** Test if this key contains a private key part */ bool havePrivate() const; /** The name associated with this key For a PGP key, this is the primary user ID For an X.509 key, this is the Common Name */ QString name() const; private: class Private; QSharedDataPointer d; }; /** A list of message keys */ typedef QList SecureMessageKeyList; /** \class SecureMessageSignature qca_securemessage.h QtCrypto SecureMessage signature \ingroup UserAPI */ class QCA_EXPORT SecureMessageSignature { public: /** The result of identity verification */ enum IdentityResult { Valid, ///< indentity is verified, matches signature InvalidSignature, ///< valid key provided, but signature failed InvalidKey, ///< invalid key provided NoKey ///< identity unknown }; /** Create an empty signature check object. User applications don't normally need to create signature checks. You normally get the object back as a result of a SecureMessage operation. */ SecureMessageSignature(); /** Create a signature check object User applications don't normally need to create signature checks. You normally get the object back as a result of a SecureMessage operation. \param r the result of the check \param v the Validity of the key validation check \param key the key associated with the signature \param ts the timestamp associated with the signature */ SecureMessageSignature(IdentityResult r, Validity v, const SecureMessageKey &key, const QDateTime &ts); /** Standard copy constructor \param from the source signature object */ SecureMessageSignature(const SecureMessageSignature &from); ~SecureMessageSignature(); /** Standard assignment operator \param from the source signature object */ SecureMessageSignature & operator=(const SecureMessageSignature &from); /** get the results of the identity check on this signature */ IdentityResult identityResult() const; /** get the results of the key validation check on this signature */ Validity keyValidity() const; /** get the key associated with this signature */ SecureMessageKey key() const; /** get the timestamp associated with this signature */ QDateTime timestamp() const; private: class Private; QSharedDataPointer d; }; /** A list of signatures */ typedef QList SecureMessageSignatureList; /** \class SecureMessage qca_securemessage.h QtCrypto Class representing a secure message SecureMessage presents a unified interface for working with both OpenPGP and CMS (S/MIME) messages. Prepare the object by calling setFormat(), setRecipient(), and setSigner() as necessary, and then begin the operation by calling an appropriate 'start' function, such as startSign(). Here is an example of how to perform a Clearsign operation using PGP: \code // first make the SecureMessageKey PGPKey myPGPKey = getSecretKeyFromSomewhere(); SecureMessageKey key; key.setPGPSecretKey(myPGPKey); // our data to sign QByteArray plain = "Hello, world"; // let's do it OpenPGP pgp; SecureMessage msg(&pgp); msg.setSigner(key); msg.startSign(SecureMessage::Clearsign); msg.update(plain); msg.end(); msg.waitForFinished(-1); if(msg.success()) { QByteArray result = msg.read(); // result now contains the clearsign text data } else { // error ... } \endcode Performing a CMS sign operation is similar. Simply set up the SecureMessageKey with a Certificate instead of a PGPKey, and operate on a CMS object instead of an OpenPGP object. \sa SecureMessageKey \sa SecureMessageSignature \sa OpenPGP \sa CMS \ingroup UserAPI */ class QCA_EXPORT SecureMessage : public QObject, public Algorithm { Q_OBJECT public: /** The type of secure message */ enum Type { OpenPGP, ///< a Pretty Good Privacy message CMS ///< a Cryptographic Message Syntax message }; /** The type of message signature */ enum SignMode { Message, ///< the message includes the signature Clearsign, ///< the message is clear signed Detached ///< the signature is detached }; /** Formats for secure messages */ enum Format { Binary, ///< DER/binary Ascii ///< PEM/ascii-armored }; /** Errors for secure messages */ enum Error { ErrorPassphrase, ///< passphrase was either wrong or not provided ErrorFormat, ///< input format was bad ErrorSignerExpired, ///< signing key is expired ErrorSignerInvalid, ///< signing key is invalid in some way ErrorEncryptExpired, ///< encrypting key is expired ErrorEncryptUntrusted, ///< encrypting key is untrusted ErrorEncryptInvalid, ///< encrypting key is invalid in some way ErrorNeedCard, ///< pgp card is missing ErrorCertKeyMismatch, ///< certificate and private key don't match ErrorUnknown ///< other error }; /** Create a new secure message This constructor uses an existing SecureMessageSystem object (for example, an OpenPGP or CMS object) to generate a specific kind of secure message. \param system a pre-existing and configured SecureMessageSystem object */ SecureMessage(SecureMessageSystem *system); ~SecureMessage(); /** The Type of secure message */ Type type() const; /** Test if the message type supports multiple (parallel) signatures. \return true if the secure message support multiple parallel signatures \note PGP cannot do this - it is primarily a CMS feature */ bool canSignMultiple() const; /** True if the SecureMessageSystem can clearsign messages. \note CMS cannot clearsign - this is normally only available for PGP */ bool canClearsign() const; /** True if the SecureMessageSystem can both sign and encrypt (in the same operation). \note CMS cannot do an integrated sign/encrypt - this is normally only available for PGP. You can do separate signing and encrypting operations on the same message with CMS though. */ bool canSignAndEncrypt() const; /** Reset the object state to that of original construction. Now a new operation can be performed immediately. */ void reset(); /** Returns true if bundling of the signer certificate chain is enabled */ bool bundleSignerEnabled() const; /** Returns true if inclusion of S/MIME attributes is enabled */ bool smimeAttributesEnabled() const; /** Return the format type set for this message */ Format format() const; /** Return the recipient(s) set for this message with setRecipient() or setRecipients() */ SecureMessageKeyList recipientKeys() const; /** Return the signer(s) set for this message with setSigner() or setSigners() */ SecureMessageKeyList signerKeys() const; /** For CMS only, this will bundle the signer certificate chain into the message. This allows a message to be verified on its own, without the need to have obtained the signer's certificate in advance. Email clients using S/MIME often bundle the signer, greatly simplifying key management. This behavior is enabled by default. \param b whether to bundle (if true) or not (false) */ void setBundleSignerEnabled(bool b); /** For CMS only, this will put extra attributes into the message related to S/MIME, such as the preferred type of algorithm to use in replies. The attributes used are decided by the provider. This behavior is enabled by default. \param b whether to embed extra attribues (if true) or not (false) */ void setSMIMEAttributesEnabled(bool b); /** Set the Format used for messages The default is Binary. \param f whether to use Binary or Ascii */ void setFormat(Format f); /** Set the recipient for an encrypted message \param key the recipient's key \sa setRecipients */ void setRecipient(const SecureMessageKey &key); /** Set the list of recipients for an encrypted message. For a list with one item, this has the same effect as setRecipient. \param keys the recipients' key \sa setRecipient */ void setRecipients(const SecureMessageKeyList &keys); /** Set the signer for a signed message. This is used for both creating signed messages as well as for verifying CMS messages that have no signer bundled. \param key the key associated with the signer \sa setSigners */ void setSigner(const SecureMessageKey &key); /** Set the list of signers for a signed message. This is used for both creating signed messages as well as for verifying CMS messages that have no signer bundled. For a list with one item, this has the same effect as setSigner. \param keys the key associated with the signer \sa setSigner */ void setSigners(const SecureMessageKeyList &keys); /** Start an encryption operation You will normally use this with some code along these lines: \code encryptingObj.startEncrypt(); encryptingObj.update(message); // perhaps some more update()s encryptingObj.end(); \endcode Each update() may (or may not) result in some encrypted data, as indicated by the readyRead() signal being emitted. Alternatively, you can wait until the whole message is available (using either waitForFinished(), or use the finished() signal. The encrypted message can then be read using the read() method. */ void startEncrypt(); /** Start an decryption operation You will normally use this with some code along these lines: \code decryptingObj.startEncrypt(); decryptingObj.update(message); // perhaps some more update()s decryptingObj.end(); \endcode Each update() may (or may not) result in some decrypted data, as indicated by the readyRead() signal being emitted. Alternatively, you can wait until the whole message is available (using either waitForFinished(), or the finished() signal). The decrypted message can then be read using the read() method. \note If decrypted result is also signed (not for CMS), then the signature will be verified during this operation. */ void startDecrypt(); /** Start a signing operation You will normally use this with some code along these lines: \code signingObj.startSign(QCA::SecureMessage::Detached) signingObj.update(message); // perhaps some more update()s signingObj.end(); \endcode For Detached signatures, you won't get any results until the whole process is done - you either waitForFinished(), or use the finished() signal, to figure out when you can get the signature (using the signature() method, not using read()). For other formats, you can use the readyRead() signal to determine when there may be part of a signed message to read(). \param m the mode that will be used to generate the signature */ void startSign(SignMode m = Message); /** Start a verification operation \param detachedSig the detached signature to verify. Do not pass a signature for other signature types. */ void startVerify(const QByteArray &detachedSig = QByteArray()); /** Start a combined signing and encrypting operation. You use this in the same way as startEncrypt(). \note This may not be possible (e.g. CMS cannot do this) - see canSignAndEncrypt() for a suitable test. */ void startSignAndEncrypt(); /** Process a message (or the next part of a message) in the current operation. You need to have already set up the message (startEncrypt(), startDecrypt(), startSign(), startSignAndEncrypt() and startVerify()) before calling this method. \param in the data to process */ void update(const QByteArray &in); /** Read the available data. \note For detached signatures, you don't get anything back using this method. Use signature() to get the detached signature(). */ QByteArray read(); /** The number of bytes available to be read. */ int bytesAvailable() const; /** Complete an operation. You need to call this method after you have processed the message (which you pass in as the argument to update(). \note the results of the operation are not available as soon as this method returns. You need to wait for the finished() signal, or use waitForFinished(). */ void end(); /** Block until the operation (encryption, decryption, signing or verifying) completes. \param msecs the number of milliseconds to wait for the operation to complete. Pass -1 to wait indefinitely. \note You should not use this in GUI applications where the blocking behaviour looks like a hung application. Instead, connect the finished() signal to a slot that handles the results. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ bool waitForFinished(int msecs = 30000); /** Indicates whether or not the operation was successful or failed. If this function returns false, then the reason for failure can be obtained with errorCode(). \sa errorCode \sa diagnosticText */ bool success() const; /** Returns the failure code. \sa success \sa diagnosticText */ Error errorCode() const; /** The signature for the message. This is only used for Detached signatures. For other message types, you get the message and signature together using read(). */ QByteArray signature() const; /** The name of the hash used for the signature process */ QString hashName() const; /** Test if the message was signed. This is true for OpenPGP if the decrypted message was also signed. \return true if the message was signed. */ bool wasSigned() const; /** Verify that the message signature is correct. \return true if the signature is valid for the message, otherwise return false */ bool verifySuccess() const; /** Information on the signer for the message */ SecureMessageSignature signer() const; /** Information on the signers for the message. This is only meaningful if the message type supports multiple signatures (see canSignMultiple() for a suitable test). */ SecureMessageSignatureList signers() const; /** Returns a log of technical information about the operation, which may be useful for presenting to the user in an advanced error dialog. */ QString diagnosticText() const; Q_SIGNALS: /** This signal is emitted when there is some data to read. Typically you connect this signal to a slot that does a read() of the available data. \note This signal does not mean that the processing of a message is necessarily complete - see finished(). */ void readyRead(); /** This signal is emitted when data has been accepted by the message processor. \param bytes the number of bytes written */ void bytesWritten(int bytes); /** This signal is emitted when the message is fully processed. */ void finished(); private: Q_DISABLE_COPY(SecureMessage) class Private; friend class Private; Private *d; }; /** \class SecureMessageSystem qca_securemessage.h QtCrypto Abstract superclass for secure messaging systems \sa SecureMessage \sa SecureMessageKey \ingroup UserAPI */ class QCA_EXPORT SecureMessageSystem : public QObject, public Algorithm { Q_OBJECT public: ~SecureMessageSystem(); protected: /** Protected constructor for SecureMessageSystem classes. You are meant to be using a subclass (such as OpenPGP or CMS) - you only need to worry about this class if you are creating a whole new SecureMessageSystem type. \param parent the parent object for this object \param type the name of the Type of SecureMessageSystem to create \param provider the provider to use, if a specific provider is required. */ SecureMessageSystem(QObject *parent, const QString &type, const QString &provider); private: Q_DISABLE_COPY(SecureMessageSystem) }; /** \class OpenPGP qca_securemessage.h QtCrypto Pretty Good Privacy messaging system \sa SecureMessage \sa SecureMessageKey \ingroup UserAPI */ class QCA_EXPORT OpenPGP : public SecureMessageSystem { Q_OBJECT public: /** Standard constructor \param parent the parent object for this object \param provider the provider to use, if a specific provider is required */ explicit OpenPGP(QObject *parent = 0, const QString &provider = QString()); ~OpenPGP(); private: Q_DISABLE_COPY(OpenPGP) class Private; Private *d; }; /** \class CMS qca_securemessage.h QtCrypto Cryptographic Message Syntax messaging system Cryptographic Message Syntax (%CMS) "is used to digitally sign, digest, authenticate, or encrypt arbitrary message content. The %CMS describes an encapsulation syntax for data protection. It supports digital signatures and encryption. The syntax allows multiple encapsulations; one encapsulation envelope can be nested inside another. Likewise, one party can digitally sign some previously encapsulated data. It also allows arbitrary attributes, such as signing time, to be signed along with the message content, and provides for other attributes such as countersignatures to be associated with a signature." (from RFC3852 "Cryptographic Message Syntax") \sa SecureMessage \sa SecureMessageKey \ingroup UserAPI */ class QCA_EXPORT CMS : public SecureMessageSystem { Q_OBJECT public: /** Standard constructor \param parent the parent object for this object \param provider the provider to use, if a specific provider is required */ explicit CMS(QObject *parent = 0, const QString &provider = QString()); ~CMS(); /** Return the trusted certificates set for this object */ CertificateCollection trustedCertificates() const; /** Return the untrusted certificates set for this object */ CertificateCollection untrustedCertificates() const; /** Return the private keys set for this object */ SecureMessageKeyList privateKeys() const; /** Set the trusted certificates to use for the messages built using this CMS object. \param trusted the collection of trusted certificates to use */ void setTrustedCertificates(const CertificateCollection &trusted); /** Set the untrusted certificates to use for the messages built using this CMS object. This function is useful when verifying messages that don't contain the certificates (or intermediate signers) within the CMS blob. In order to verify such messages, you'll have to pass the possible signer certs with this function. \param untrusted the collection of untrusted certificates to use */ void setUntrustedCertificates(const CertificateCollection &untrusted); /** Set the private keys to use for the messages built using this CMS object. Keys are required for decrypting and signing (not for encrypting or verifying). \param keys the collection of keys to use */ void setPrivateKeys(const SecureMessageKeyList &keys); private: Q_DISABLE_COPY(CMS) class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_tools.h0000644000175000017500000004764011305557613021500 0ustar janjan/* * qca_tools.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_tools.h Header file for "tool" classes used in %QCA These classes differ from those in qca_support.h, in that they have some cryptographic relationship, and require secure memory. \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_TOOLS_H #define QCA_TOOLS_H #include #include #include #include "qca_export.h" class QString; class QByteArray; class QTextStream; /** Allocate a block of memory from the secure memory pool. This is intended to be used when working with C libraries. \param bytes the number of bytes to allocate */ QCA_EXPORT void *qca_secure_alloc(int bytes); /** Free (de-allocate) a block of memory that has been previously allocated from the secure memory pool. This is intended to be used when working with C libraries. \param p pointer to the block of memory to be free'd */ QCA_EXPORT void qca_secure_free(void *p); /** Resize (re-allocate) a block of memory that has been previously allocated from the secure memory pool. \param p pointer to the block of memory to be resized. \param bytes the new size that is required. */ QCA_EXPORT void *qca_secure_realloc(void *p, int bytes); namespace QCA { /** \class MemoryRegion qca_tools.h QtCrypto Array of bytes that may be optionally secured This class is mostly unusable on its own. Either use it as a SecureArray subclass or call toByteArray() to convert to QByteArray. Note that this class is implicitly shared (that is, copy on write). \ingroup UserAPI */ class QCA_EXPORT MemoryRegion { public: MemoryRegion(); /** Constructs a new Memory Region from a null terminated character array \param str pointer to the array of data to copy */ MemoryRegion(const char *str); /** Constructs a new MemoryRegion from the data in a byte array \param from the QByteArray to copy from */ MemoryRegion(const QByteArray &from); /** Standard copy constructor \param from the MemoryRegion to copy from */ MemoryRegion(const MemoryRegion &from); ~MemoryRegion(); /** Standard assignment operator \param from the MemoryRegion to copy from */ MemoryRegion & operator=(const MemoryRegion &from); /** Standard assignment operator \param from the QByteArray to copy from */ MemoryRegion & operator=(const QByteArray &from); /** Test if the MemoryRegion is null (i.e. was created as a null array, and hasn't been resized). This is probably not what you are trying to do. If you are trying to determine whether there are any bytes in the array, use isEmpty() instead. */ bool isNull() const; /** Test if the MemoryRegion is using secure memory, or not. In this context, memory is secure if it will not be paged out to disk. \return true if the memory region is secure */ bool isSecure() const; /** Convert this memory region to a byte array. \note For secure data, this will make it insecure \sa data() and constData() for other ways to convert to an "accessible" format. */ QByteArray toByteArray() const; /** Returns true if the size of the memory region is zero. */ bool isEmpty() const; /** Returns the number of bytes in the memory region. */ int size() const; /** Convert the contents of the memory region to a C-compatible character array. This consists of size() bytes, followed by a null terminator. \sa toByteArray for an alternative approach. \sa constData, which is equivalent to this method, but avoids the possibility that the compiler picks the wrong version. */ const char *data() const; /** Convert the contents of the memory region to a C-compatible character array. This consists of size() bytes, followed by a null terminator. \sa toByteArray for an alternative approach. \sa data which is equivalent to this method */ const char *constData() const; /** Obtain the value of the memory location at the specified position. \param index the offset into the memory region. \note The contents of a memory region are between 0 and size()-1. The content at position size() is always a null terminator. */ const char & at(int index) const; protected: /** Create a memory region, optionally using secure storage. \param secure if this is true, the memory region will use secure storage. \note This will create a memory region without any content (i.e. both isNull() and isEmpty() will return true. */ MemoryRegion(bool secure); /** Create a memory region, optionally using secure storage. \param size the number of bytes in the memory region. \param secure if this is true, the memory region will use secure storage. */ MemoryRegion(int size, bool secure); /** Create a memory region, optionally using secure storage. This constructor variant allows you to initialize the memory region from an existing array. \param from the byte array to copy from. \param secure if this is true, the memory region will use secure storage. */ MemoryRegion(const QByteArray &from, bool secure); /** Convert the contents of the memory region to a C-compatible character array. This consists of size() bytes, followed by a null terminator. */ char *data(); /** Obtain the value of the memory location at the specified position. \param index the offset into the memory region. \note The contents of a memory region are between 0 and size()-1. The content at position size() is always a null terminator. */ char & at(int index); /** Resize the memory region to the specified size. \param size the new size of the region. */ bool resize(int size); /** Modify the memory region to match a specified byte array. This resizes the memory region as required to match the byte array size. \param from the byte array to copy from. \param secure if this is true, the memory region will use secure storage. */ void set(const QByteArray &from, bool secure); /** Convert the memory region to use the specified memory type. This may involve copying data from secure to insecure storage, or from insecure to secure storage. \param secure if true, use secure memory; otherwise use insecure memory. */ void setSecure(bool secure); private: bool _secure; class Private; QSharedDataPointer d; }; /** \class SecureArray qca_tools.h QtCrypto Secure array of bytes The %SecureArray provides an array of memory from a pool that is, at least partly, secure. In this sense, secure means that the contents of the memory should not be made available to other applications. By comparison, a QByteArray or QString may be held in pages that might be swapped to disk or free'd without being cleared first. Note that this class is implicitly shared (that is, copy on write). \ingroup UserAPI */ class QCA_EXPORT SecureArray : public MemoryRegion { public: /** Construct a secure byte array, zero length */ SecureArray(); /** Construct a secure byte array of the specified length \param size the number of bytes in the array \param ch the value every byte should be set to */ explicit SecureArray(int size, char ch = 0); /** Construct a secure byte array from a string Note that this copies, rather than references the source array. \param str the source of the data (as a null terminated string). */ SecureArray(const char *str); /** Construct a secure byte array from a QByteArray Note that this copies, rather than references the source array. \param a the source of the data. \sa operator=() */ SecureArray(const QByteArray &a); /** Construct a secure byte array from a MemoryRegion Note that this copies, rather than references the source array \param a the source of the data. \sa operator=() */ SecureArray(const MemoryRegion &a); /** Construct a (shallow) copy of another secure byte array \param from the source of the data and length. */ SecureArray(const SecureArray &from); ~SecureArray(); /** Creates a reference, rather than a deep copy. \param from the array to reference */ SecureArray & operator=(const SecureArray &from); /** Creates a copy, rather than references \param a the array to copy from */ SecureArray & operator=(const QByteArray &a); /** Clears the contents of the array and makes it empty */ void clear(); /** Returns a reference to the byte at the index position \param index the zero-based offset to obtain */ char & operator[](int index); /** Returns a reference to the byte at the index position \param index the zero-based offset to obtain */ const char & operator[](int index) const; /** Pointer to the data in the secure array You can use this for memcpy and similar functions. If you are trying to obtain data at a particular offset, you might be better off using at() or operator[] */ char *data(); /** Pointer to the data in the secure array You can use this for memcpy and similar functions. If you are trying to obtain data at a particular offset, you might be better off using at() or operator[] */ const char *data() const; /** Pointer to the data in the secure array You can use this for memcpy and similar functions. If you are trying to obtain data at a particular offset, you might be better off using at() or operator[] */ const char *constData() const; /** Returns a reference to the byte at the index position \param index the zero-based offset to obtain */ char & at(int index); /** Returns a reference to the byte at the index position \param index the zero-based offset to obtain */ const char & at(int index) const; /** Returns the number of bytes in the array */ int size() const; /** Test if the array contains any bytes. This is equivalent to testing (size() != 0). Note that if the array is allocated, isEmpty() is false (even if no data has been added) \return true if the array has zero length, otherwise false */ bool isEmpty() const; /** Change the length of this array If the new length is less than the old length, the extra information is (safely) discarded. If the new length is equal to or greater than the old length, the existing data is copied into the array. \param size the new length */ bool resize(int size); /** Fill the data array with a specified character \param fillChar the character to use as the fill \param fillToPosition the number of characters to fill to. If not specified (or -1), fills array to current length. \note This function does not extend the array - if you ask for fill beyond the current length, only the current length will be used. \note The number of characters is 1 based, so if you ask for fill('x', 10), it will fill from */ void fill(char fillChar, int fillToPosition = -1); /** Copy the contents of the secure array out to a standard QByteArray. Note that this performs a deep copy of the data. */ QByteArray toByteArray() const; /** Append a secure byte array to the end of this array \param a the array to append to this array */ SecureArray & append(const SecureArray &a); /** Equality operator. Returns true if both arrays have the same data (and the same length, of course). \param other the MemoryRegion to compare to */ bool operator==(const MemoryRegion &other) const; /** Inequality operator. Returns true if both arrays have different length, or the same length but different data. \param other the MemoryRegion to compare to */ inline bool operator!=(const MemoryRegion &other) const { return !(*this == other); } /** Append a secure byte array to the end of this array \param a the array to append to this array */ SecureArray & operator+=(const SecureArray &a); protected: /** Assign the contents of a provided byte array to this object. \param from the byte array to copy */ void set(const SecureArray &from); /** Assign the contents of a provided byte array to this object. \param from the byte array to copy */ void set(const QByteArray &from); }; /** Returns an array that is the result of concatenating a and b \param a the string to put at the start of the result \param b the string to put at the end of the result */ QCA_EXPORT const SecureArray operator+(const SecureArray &a, const SecureArray &b); /** \class BigInteger qca_tools.h QtCrypto Arbitrary precision integer BigInteger provides arbitrary precision integers. \code if ( BigInteger("3499543804349") == BigInteger("38493290803248") + BigInteger( 343 ) ) { // do something } \endcode \ingroup UserAPI */ class QCA_EXPORT BigInteger { public: /** Constructor. Creates a new BigInteger, initialised to zero. */ BigInteger(); /** \overload \param n an alternative integer initialisation value. */ BigInteger(int n); /** \overload \param c an alternative initialisation value, encoded as a character array \code BigInteger b ( "9890343" ); \endcode */ BigInteger(const char *c); /** \overload \param s an alternative initialisation value, encoded as a string */ BigInteger(const QString &s); /** \overload \param a an alternative initialisation value, encoded as SecureArray */ BigInteger(const QCA::SecureArray &a); /** \overload \param from an alternative initialisation value, encoded as a %BigInteger */ BigInteger(const BigInteger &from); ~BigInteger(); /** Assignment operator \param from the BigInteger to copy from \code BigInteger a; // a is zero BigInteger b( 500 ); a = b; // a is now 500 \endcode */ BigInteger & operator=(const BigInteger &from); /** \overload \param s the QString containing an integer representation \sa bool fromString(const QString &s) \note it is the application's responsibility to make sure that the QString represents a valid integer (ie it only contains numbers and an optional minus sign at the start) */ BigInteger & operator=(const QString &s); /** Increment in place operator \param b the amount to increment by \code BigInteger a; // a is zero BigInteger b( 500 ); a += b; // a is now 500 a += b; // a is now 1000 \endcode */ BigInteger & operator+=(const BigInteger &b); /** Decrement in place operator \param b the amount to decrement by \code BigInteger a; // a is zero BigInteger b( 500 ); a -= b; // a is now -500 a -= b; // a is now -1000 \endcode */ BigInteger & operator-=(const BigInteger &b); /** Multiply in place operator \param b the amount to multiply by */ BigInteger & operator*=(const BigInteger &b); /** Divide in place operator \param b the amount to divide by */ BigInteger & operator/=(const BigInteger &b); /** Modulo in place operator \param b the amount to divide by */ BigInteger & operator%=(const BigInteger &b); /** Output %BigInteger as a byte array, useful for storage or transmission. The format is a binary integer in sign-extended network-byte-order. \sa void fromArray(const SecureArray &a); */ QCA::SecureArray toArray() const; /** Assign from an array. The input is expected to be a binary integer in sign-extended network-byte-order. \param a a SecureArray that represents an integer \sa BigInteger(const SecureArray &a); \sa SecureArray toArray() const; */ void fromArray(const QCA::SecureArray &a); /** Convert %BigInteger to a QString \code QString aString; BigInteger aBiggishInteger( 5878990 ); aString = aBiggishInteger.toString(); // aString is now "5878990" \endcode */ QString toString() const; /** Assign from a QString \param s a QString that represents an integer \note it is the application's responsibility to make sure that the QString represents a valid integer (ie it only contains numbers and an optional minus sign at the start) \sa BigInteger(const QString &s) \sa BigInteger & operator=(const QString &s) */ bool fromString(const QString &s); /** Compare this value with another %BigInteger Normally it is more readable to use one of the operator overloads, so you don't need to use this method directly. \param n the BigInteger to compare with \return zero if the values are the same, negative if the argument is less than the value of this BigInteger, and positive if the argument value is greater than this BigInteger \code BigInteger a( "400" ); BigInteger b( "-400" ); BigInteger c( " 200 " ); int result; result = a.compare( b ); // return positive 400 > -400 result = a.compare( c ); // return positive, 400 > 200 result = b.compare( c ); // return negative, -400 < 200 \endcode */ int compare(const BigInteger &n) const; /** Equality operator. Returns true if the two BigInteger values are the same, including having the same sign. \param other the BigInteger to compare to */ inline bool operator==(const BigInteger &other) const { return (compare(other) == 0); } /** Inequality operator. Returns true if the two BigInteger values are different in magnitude, sign or both. \param other the BigInteger to compare to */ inline bool operator!=(const BigInteger &other) const { return !(*this == other); } /** Less than or equal operator. Returns true if the BigInteger value on the left hand side is equal to or less than the BigInteger value on the right hand side. \param other the BigInteger to compare to */ inline bool operator<=(const BigInteger &other) const { return (compare(other) <= 0); } /** Greater than or equal operator. Returns true if the BigInteger value on the left hand side is equal to or greater than the BigInteger value on the right hand side. \param other the BigInteger to compare to */ inline bool operator>=(const BigInteger &other) const { return (compare(other) >= 0); } /** Less than operator. Returns true if the BigInteger value on the left hand side is less than the BigInteger value on the right hand side. \param other the BigInteger to compare to */ inline bool operator<(const BigInteger &other) const { return (compare(other) < 0); } /** Greater than operator. Returns true if the BigInteger value on the left hand side is greater than the BigInteger value on the right hand side. \param other the BigInteger to compare to */ inline bool operator>(const BigInteger &other) const { return (compare(other) > 0); } private: class Private; QSharedDataPointer d; }; /** Stream operator \param stream the stream to write to \param b the integer to write to the stream \relates BigInteger */ QCA_EXPORT QTextStream &operator<<(QTextStream &stream, const BigInteger &b); } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_export.h0000644000175000017500000000260511305557613021651 0ustar janjan/* * qca_export.h - Qt Cryptographic Architecture * Copyright (C) 2003-2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_export.h Preprocessor magic to allow export of library symbols. This is strictly internal. \note You should not include this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_EXPORT_H #define QCA_EXPORT_H #include #ifdef Q_OS_WIN # ifndef QCA_STATIC # ifdef QCA_MAKEDLL # define QCA_EXPORT Q_DECL_EXPORT # else # define QCA_EXPORT Q_DECL_IMPORT # endif # endif #endif #ifndef QCA_EXPORT # define QCA_EXPORT #endif #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_support.h0000644000175000017500000006562011305557613022052 0ustar janjan/* * qca_support.h - Qt Cryptographic Architecture * Copyright (C) 2003-2005 Justin Karneges * Copyright (C) 2004,2005, 2007 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_support.h Header file for "support" classes used in %QCA The classes in this header do not have any cryptographic content - they are used in %QCA, and are included for convenience. \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_SUPPORT_H #define QCA_SUPPORT_H #include #include #include #include #include #include #include #include #include #include "qca_export.h" #include "qca_tools.h" namespace QCA { /** Convenience method to determine the return type of a method This function identifies the return type of a specified method. This function can be used as shown: \code class TestClass : public QObject { Q_OBJECT // ... public slots: QString qstringMethod() { return QString(); }; bool boolMethod( const QString & ) { return true; }; }; QByteArray myTypeName; TestClass testClass; QList argsList; // empty list, since no args myTypeName = QCA::methodReturnType( testClass.metaObject(), QByteArray( "qstringMethod" ), argsList ); // myTypeName is "QString" myTypeName = QCA::methodReturnType( testClass.metaObject(), QByteArray( "boolMethod" ), argsList ); // myTypeName is "", because there is no method called "boolMethod" that has no arguments argsList << "QString"; // now we have one argument myTypeName = QCA::methodReturnType( testClass.metaObject(), QByteArray( "boolMethod" ), argsList ); // myTypeName is "bool" \endcode The return type name of a method returning void is an empty string, not "void" \note This function is not normally required for use with %QCA. It is provided for use in your code, if required. \param obj the QMetaObject for the object \param method the name of the method (without the arguments or brackets) \param argTypes the list of argument types of the method \return the name of the type that this method will return with the specified argument types. \sa QMetaType for more information on the Qt meta type system. \relates SyncThread */ QCA_EXPORT QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList argTypes); /** Convenience method to invoke a method by name, using a variant list of arguments. This function can be used as shown: \code class TestClass : public QObject { Q_OBJECT // ... public slots: QString qstringMethod() { return QString( "the result" ); }; bool boolMethod( const QString & ) { return true; }; }; TestClass *testClass = new TestClass; QVariantList args; QVariant stringRes; // calls testClass->qstringMethod() with no arguments ( since args is an empty list) bool ret = QCA::invokeMethodWithVariants( testClass, QByteArray( "qstringMethod" ), args, &stringRes ); // ret is true (since call succeeded), stringRes.toString() is a string - "the result" QVariant boolResult; QString someString( "not important" ); args << someString; // calls testClass->boolMethod( someString ), returning result in boolResult ret = QCA::invokeMethodWithVariants( testClass1, QByteArray( "boolMethod" ), args, &boolResult ); // ret is true (since call succeeded), boolResult.toBool() is true. \endcode \param obj the object to call the method on \param method the name of the method (without the arguments or brackets) \param args the list of arguments to use in the method call \param ret the return value of the method (unchanged if the call fails) \param type the type of connection to use \return true if the call succeeded, otherwise false \relates SyncThread */ QCA_EXPORT bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection); /** \class SyncThread qca_support.h QtCrypto Convenience class to run a thread and interact with it synchronously SyncThread makes it easy to perform the common practice of starting a thread, running some objects in that thread, and then interacting with those objects safely. Often, there is no need to directly use threading primitives (e.g. QMutex), resulting in very clean multi-threaded code. \note The following is an excerpt from http://delta.affinix.com/2006/11/13/synchronized-threads-part-3/ ---
With SyncThread, you can start, stop, and call a method in another thread while the main thread sleeps. The only requirement is that the methods be declared as slots. Below is a contrived example, where we have an object in another thread that increments a counter over a some interval, using the Qt event loop, and provides a method to inspect the value. First, the Counter object: \code class Counter : public QObject { Q_OBJECT private: int x; QTimer timer; public: Counter() : timer(this) { x = 0; connect(&timer, SIGNAL(timeout()), SLOT(t_timeout())); } public slots: void start(int seconds) { timer.setInterval(seconds * 1000); timer.start(); } int value() const { return x; } private slots: void t_timeout() { ++x; } }; \endcode Looks like a typical object, no surprises. Now to wrap Counter with SyncThread. We went over how to do this in the first article, and it is very straightforward: \code class CounterThread : public SyncThread { Q_OBJECT public: Counter *counter; CounterThread(QObject *parent) : SyncThread(parent) { counter = 0; } ~CounterThread() { // SyncThread will stop the thread on destruct, but since our // atStop() function makes references to CounterThread's // members, we need to shutdown here, before CounterThread // destructs. stop(); } protected: virtual void atStart() { counter = new Counter; } virtual void atStop() { delete counter; } }; \endcode We can then use it like this: \code CounterThread *thread = new CounterThread; // after this call, the thread is started and the Counter is ready thread->start(); // let's start the counter with a 1 second interval thread->call(thread->counter, "start", QVariantList() << 1); ... // after some time passes, let's check on the value int x = thread->call(thread->counter, "value").toInt(); // we're done with this thing delete thread; \endcode Do you see a mutex anywhere? I didn't think so.
--- Even without the call() function, SyncThread is still very useful for preparing objects in another thread, which you can then QObject::connect() to and use signals and slots like normal. \ingroup UserAPI */ class QCA_EXPORT SyncThread : public QThread { Q_OBJECT public: /** Standard constructor \param parent the parent object for this parent. */ SyncThread(QObject *parent = 0); /** Calls stop() and then destructs \note Subclasses should call stop() in their own destructor */ ~SyncThread(); /** Starts the thread, begins the event loop the thread, and then calls atStart() in the thread. This function will block until atStart() has returned. */ void start(); /** Stops the event loop of the thread, calls atStop() in the thread, and instructs the thread to finish. This function will block until the thread has finished. */ void stop(); /** Calls a slot of an object in the thread. This function will block until the slot has returned. It is possible for the call to fail, for example if the method does not exist. The arguments and return value of the call use QVariant. If the method has no return value (returns void), then the returned QVariant will be null. \param obj the object to call the method on \param method the name of the method (without the arguments or brackets) \param args the list of arguments to use in the method call \param ok if not 0, true is stored here if the call succeeds, otherwise false is stored here. */ QVariant call(QObject *obj, const QByteArray &method, const QVariantList &args = QVariantList(), bool *ok = 0); protected: /** Reimplement this to perform your initialization */ virtual void atStart() = 0; /** Reimplement this to perform your deinitialization */ virtual void atEnd() = 0; /** Starts the event loop and calls atStart and atStop as necessary */ virtual void run(); private: Q_DISABLE_COPY(SyncThread) class Private; friend class Private; Private *d; }; /** \class Synchronizer qca_support.h QtCrypto Enable synchronization between two threads. */ class QCA_EXPORT Synchronizer : public QObject { Q_OBJECT public: /** Standard constructor \param parent the parent object to this object */ Synchronizer(QObject *parent); ~Synchronizer(); /** Call to pause execution in this thread. This function will block until conditionMet() is called. \param msecs the time to wait before proceeding. The default timeout value (-1) indicates to wait indefinitely. */ bool waitForCondition(int msecs = -1); /** Call to continue execution in the paused thread. */ void conditionMet(); private: Q_DISABLE_COPY(Synchronizer) class Private; Private *d; }; /** \class DirWatch qca_support.h QtCrypto Support class to monitor a directory for activity. %DirWatch monitors a specified file for any changes. When the directory changes, the changed() signal is emitted. \note QFileSystemWatcher has very similar functionality to this class. You should evaluate this class and QFileSystemWatcher to determine which better suits your application needs. \ingroup UserAPI */ class QCA_EXPORT DirWatch : public QObject { Q_OBJECT public: /** Standard constructor \param dir the name of the directory to watch. If not set in the constructor, you can set it using setDirName() \param parent the parent object for this object */ explicit DirWatch(const QString &dir = QString(), QObject *parent = 0); ~DirWatch(); /** The name of the directory that is being monitored */ QString dirName() const; /** Change the directory being monitored \param dir the name of the directory to monitor */ void setDirName(const QString &dir); Q_SIGNALS: /** The changed signal is emitted when the directory is changed (e.g. modified by addition or deletion of a file within the directory, or the deletion of the directory) */ void changed(); private: Q_DISABLE_COPY(DirWatch) class Private; friend class Private; Private *d; }; /** \class FileWatch qca_support.h QtCrypto Support class to monitor a file for activity %FileWatch monitors a specified file for any changes. When the file changes, the changed() signal is emitted. \note QFileSystemWatcher has very similar functionality to this class. You should evaluate this class and QFileSystemWatcher to determine which better suits your application needs. \ingroup UserAPI */ class QCA_EXPORT FileWatch : public QObject { Q_OBJECT public: /** Standard constructor \param file the name of the file to watch. If not in this object, you can set it using setFileName() \param parent the parent object for this object */ explicit FileWatch(const QString &file = QString(), QObject *parent = 0); ~FileWatch(); /** The name of the file that is being monitored */ QString fileName() const; /** Change the file being monitored \param file the name of the file to monitor */ void setFileName(const QString &file); Q_SIGNALS: /** The changed signal is emitted when the file is changed (e.g. modified, deleted) */ void changed(); private: Q_DISABLE_COPY(FileWatch) class Private; friend class Private; Private *d; }; class ConsolePrivate; class ConsoleReferencePrivate; class ConsoleReference; /** \class Console qca_support.h QtCrypto %QCA %Console system %QCA provides an API for asynchronous, event-based access to the console and stdin/stdout, as these facilities are otherwise not portable. The primary use of this system within %QCA is for passphrase prompting in command-line applications, using the tty console type. How it works: Create a %Console object for the type of console desired, and then use ConsoleReference to act on the console. Only one ConsoleReference may operate on a %Console at a time. A %Console object takes over either the physical console (Console::Tty type) or stdin/stdout (Console::Stdio type). Only one of each type may be created at a time. Whenever code is written that needs a tty or stdio object, the code should first call one of the static methods (ttyInstance() or stdioInstance()) to see if a console object for the desired type exists already. If the object exists, use it. If it does not exist, the rule is that the relevant code should create the object, use the object, and then destroy the object when the operation is completed. By following the above rule, you can write code that utilizes a console without the application having to create some master console object for you. Of course, if the application has created a console then it will be used. The reason why there is a master console object is that it is not guaranteed that all I/O will survive creation and destruction of a console object. If you are using the Stdio Type, then you probably want a long-lived console object. It is possible to capture unprocessed I/O by calling bytesLeftToRead or bytesLeftToWrite. However, it is not expected that general console-needing code will call these functions when utilizing a temporary console. Thus, an application developer would need to create his own console object, invoke the console-needing code, and then do his own extraction of the unprocessed I/O if necessary. Another reason to extract unprocessed I/O is if you need to switch from %Console back to standard functions (e.g. fgets() ). \ingroup UserAPI */ class QCA_EXPORT Console : public QObject { Q_OBJECT public: /** The type of console object */ enum Type { Tty, ///< physical console Stdio ///< stdin/stdout }; /** The type of I/O to use with the console object. */ enum ChannelMode { Read, ///< Read only (equivalent to stdin) ReadWrite ///< Read/write (equivalent to stdin and stdout) }; /** The nature of the console operation */ enum TerminalMode { Default, ///< use default terminal settings Interactive ///< char-by-char input, no echo }; /** Standard constructor Note that library code should not create a new Console object without checking whether there is already a Console object of the required Type. See the main documentation for Console for the rationale for this. \param type the Type of Console object to create \param cmode the ChannelMode (I/O type) to use \param tmode the TerminalMode to use \param parent the parent object for this object \sa ttyInstance() and stdioInstance for static methods that allow you to test whether there is already a Console object of the required Type, and if there is, obtain a reference to that object. */ Console(Type type, ChannelMode cmode, TerminalMode tmode, QObject *parent = 0); ~Console(); /** The Type of this Console object */ Type type() const; /** The ChannelMode of this Console object */ ChannelMode channelMode() const; /** The TerminalMode of this Console object */ TerminalMode terminalMode() const; /** Test whether standard input is redirected. \sa type() and channelMode() */ static bool isStdinRedirected(); /** Test whether standard output is redirected. \sa type() and channelMode() */ static bool isStdoutRedirected(); /** The current terminal-type console object \return null if there is no current Console of this type, otherwise the Console to use */ static Console *ttyInstance(); /** The current stdio-type console object \return null if there is no current Console of this type, otherwise the Console to use */ static Console *stdioInstance(); /** Release the Console This allows access to buffers containing any remaining data */ void release(); /** Obtain remaining data from the Console, awaiting a read operation */ QByteArray bytesLeftToRead(); /** Obtain remaining data from the Console, awaiting a write operation */ QByteArray bytesLeftToWrite(); private: Q_DISABLE_COPY(Console) friend class ConsolePrivate; ConsolePrivate *d; friend class ConsoleReference; }; /** \class ConsoleReference qca_support.h QtCrypto Manager for a Console \note Only one %ConsoleReference object can be active at a time \ingroup UserAPI */ class QCA_EXPORT ConsoleReference : public QObject { Q_OBJECT public: /** The security setting to use for the Console being managed. */ enum SecurityMode { SecurityDisabled, SecurityEnabled }; /** Standard constructor \param parent the parent object for this object */ ConsoleReference(QObject *parent = 0); ~ConsoleReference(); /** Set the Console object to be managed, and start processing. You typically want to use Console::ttyInstance() or Console::stdioInstance() to obtain the required Console reference. \param console reference to the Console to be managed \param mode the SecurityMode to use for this Console. \sa QCA::Console for more information on how to handle the console aspects of your application or library code. */ bool start(Console *console, SecurityMode mode = SecurityDisabled); /** Stop processing, and release the Console */ void stop(); /** The Console object managed by this object \sa start() to set the Console to be managed */ Console *console() const; /** The security mode setting for the Console object managed by this object. \sa start() to set the SecurityMode */ SecurityMode securityMode() const; /** Read data from the Console. \param bytes the number of bytes to read. The default is to read all available bytes \sa readSecure() for a method suitable for reading sensitive data. */ QByteArray read(int bytes = -1); /** Write data to the Console. \param a the array of data to write to the Console \sa writeSecure() for a method suitable for writing sensitive data. */ void write(const QByteArray &a); /** Read secure data from the Console \param bytes the number of bytes to read. The default is to read all available bytes \sa read() which is suitable for non-sensitive data */ SecureArray readSecure(int bytes = -1); /** Write secure data to the Console \param a the array of data to write to the Console \sa write() which is suitable for non-sensitive data */ void writeSecure(const SecureArray &a); /** Close the write channel You only need to call this if writing is enabled on the Console being managed. */ void closeOutput(); /** The number of bytes available to read from the Console being managed. */ int bytesAvailable() const; /** The number of bytes remaining to be written to the Console being managed */ int bytesToWrite() const; Q_SIGNALS: /** Emitted when there are bytes available to read from the Console being managed */ void readyRead(); /** Emitted when bytes are written to the Console \param bytes the number of bytes that were written \sa bytesAvailable() */ void bytesWritten(int bytes); /** Emitted when the console input is closed */ void inputClosed(); /** Emitted when the console output is closed */ void outputClosed(); private: Q_DISABLE_COPY(ConsoleReference) friend class ConsoleReferencePrivate; ConsoleReferencePrivate *d; friend class Console; }; /** \class ConsolePrompt qca_support.h QtCrypto Console prompt handler. This class provides a convenient way to get user input in a secure way, as shown below: \code QCA::ConsolePrompt prompt; prompt.getHidden("Passphrase"); prompt.waitForFinished(); QCA:SecureArray pass = prompt.result(); \endcode \note It is not necessary to use waitForFinished(), because you can just connect the finished() signal to a suitable method, however command line (console) applications often require waitForFinished(). \ingroup UserAPI */ class QCA_EXPORT ConsolePrompt : public QObject { Q_OBJECT public: /** Standard constructor \param parent the parent object for this object */ ConsolePrompt(QObject *parent = 0); ~ConsolePrompt(); /** Allow the user to enter data without it being echo'd to the terminal. This is particularly useful for entry of passwords, passphrases and PINs. \param promptStr the prompt to display to the user \sa result() for how to get the input back. */ void getHidden(const QString &promptStr); /** Obtain one character from the user \sa resultChar() for how to get the input back. */ void getChar(); /** Block waiting for user input. You may wish to use the finished() signal to avoid blocking. */ void waitForFinished(); /** Obtain the result of the user input. This method is usually called to obtain data from the user that was requested by the getHidden() call. */ SecureArray result() const; /** Obtain the result of the user input. This method is usually called to obtain data from the user that was requested by the getChar() call. */ QChar resultChar() const; Q_SIGNALS: /** Emitted when the user input activity has been completed. This corresponds to the provision of a string for getHidden() or a single character for getChar(). \sa waitForFinished */ void finished(); private: Q_DISABLE_COPY(ConsolePrompt) class Private; friend class Private; Private *d; }; class AbstractLogDevice; /** \class Logger qca_support.h QtCrypto A simple logging system This class provides a simple but flexible approach to logging information that may be used for debugging or system operation diagnostics. There is a single %Logger for each application that uses %QCA. You do not need to create this %Logger yourself - %QCA automatically creates it on startup. You can get access to the %Logger using the global QCA::logger() method. By default the Logger just accepts all messages (binary and text). If you want to get access to those messages, you need to subclass AbstractLogDevice, and register your subclass (using registerLogDevice()). You can then take whatever action is appropriate (e.g. show to the user using the GUI, log to a file or send to standard error). \ingroup UserAPI */ class QCA_EXPORT Logger : public QObject { Q_OBJECT public: /** The severity of the message This information may be used by the log device to determine what the appropriate action is. */ enum Severity { Quiet = 0, ///< Quiet: turn of logging Emergency = 1, ///< Emergency: system is unusable Alert = 2, ///< Alert: action must be taken immediately Critical = 3, ///< Critical: critical conditions Error = 4, ///< Error: error conditions Warning = 5, ///< Warning: warning conditions Notice = 6, ///< Notice: normal but significant condition Information = 7, ///< Informational: informational messages Debug = 8 ///< Debug: debug-level messages }; /** Get the current logging level \return Current level */ inline Severity level() const { return m_logLevel; } /** Set the current logging level \param level new logging level Only severities less or equal than the log level one will be logged */ void setLevel(Severity level); /** Log a message to all available log devices \param message the text to log */ void logTextMessage(const QString &message, Severity = Information); /** Log a binary blob to all available log devices \param blob the information to log \note how this is handled is quite logger specific. For example, it might be logged as a binary, or it might be encoded in some way */ void logBinaryMessage(const QByteArray &blob, Severity = Information); /** Add an AbstractLogDevice subclass to the existing list of loggers \param logger the LogDevice to add */ void registerLogDevice(AbstractLogDevice *logger); /** Remove an AbstractLogDevice subclass from the existing list of loggers \param loggerName the name of the LogDevice to remove \note If there are several log devices with the same name, all will be removed. */ void unregisterLogDevice(const QString &loggerName); /** Get a list of the names of all registered log devices */ QStringList currentLogDevices() const; private: Q_DISABLE_COPY(Logger) friend class Global; /** Create a new message logger */ Logger(); ~Logger(); QStringList m_loggerNames; QList m_loggers; Severity m_logLevel; }; /** \class AbstractLogDevice qca_support.h QtCrypto An abstract log device \ingroup UserAPI */ class QCA_EXPORT AbstractLogDevice : public QObject { Q_OBJECT public: /** The name of this log device */ QString name() const; /** Log a message The default implementation does nothing - you should override this method in your subclass to do whatever logging is required \param message the message to log \param severity the severity level of the message */ virtual void logTextMessage(const QString &message, Logger::Severity severity); /** Log a binary blob The default implementation does nothing - you should override this method in your subclass to do whatever logging is required \param blob the message (as a byte array) to log \param severity the severity level of the message */ virtual void logBinaryMessage(const QByteArray &blob, Logger::Severity severity); protected: /** Create a new message logger \param name the name of this log device \param parent the parent for this logger */ explicit AbstractLogDevice(const QString &name, QObject *parent = 0); virtual ~AbstractLogDevice() = 0; private: Q_DISABLE_COPY(AbstractLogDevice) class Private; Private *d; QString m_name; }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_core.h0000644000175000017500000012065611305557613021267 0ustar janjan/* * qca_core.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_core.h Header file for core %QCA infrastructure \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_CORE_H #define QCA_CORE_H /** The current version of %QCA This provides you a compile time check of the %QCA version. \sa qcaVersion for a runtime check. */ #define QCA_VERSION 0x020002 #include #include #include #include #include #include "qca_export.h" #include "qca_support.h" #include "qca_tools.h" /** The current version of %QCA. This is equivalent to QCA_VERSION, except it provides a runtime check of the version of %QCA that is being used. */ QCA_EXPORT int qcaVersion(); /** QCA - the Qt Cryptographic Architecture */ namespace QCA { class Provider; class Random; class CertificateCollection; class Global; class KeyStore; class KeyStoreEntry; class KeyStoreInfo; class KeyStoreManager; class Logger; /** Convenience representation for the plugin providers You can get a list of providers using the providers() function \sa ProviderListIterator \sa providers() */ typedef QList ProviderList; /** Mode settings for memory allocation QCA can use secure memory, however most operating systems restrict the amount of memory that can be pinned by user applications, to prevent a denial-of-service attack. QCA supports two approaches to getting memory - the mlock method, which generally requires root (administrator) level privileges, and the mmap method which is not as secure, but which should be able to be used by any process. \sa Initializer */ enum MemoryMode { Practical, ///< mlock and drop root if available, else mmap Locking, ///< mlock and drop root LockingKeepPrivileges ///< mlock, retaining root privileges }; /** Direction settings for symmetric algorithms For some algorithms, it makes sense to have a "direction", such as Cipher algorithms which can be used to encrypt or decrypt. */ enum Direction { Encode, ///< Operate in the "forward" direction; for example, encrypting Decode ///< Operate in the "reverse" direction; for example, decrypting }; /** Initialise %QCA. This call is not normally required, because it is cleaner to use an Initializer. */ QCA_EXPORT void init(); /** \overload \param m the MemoryMode to use \param prealloc the amount of memory in kilobytes to allocate for secure storage */ QCA_EXPORT void init(MemoryMode m, int prealloc); /** Clean up routine This routine cleans up %QCA, including memory allocations This call is not normally required, because it is cleaner to use an Initializer */ QCA_EXPORT void deinit(); /** Test if secure storage memory is available \return true if secure storage memory is available */ QCA_EXPORT bool haveSecureMemory(); /** Test if secure random is available Secure random is considered available if the global random provider is not the default provider. \return true if secure random is available */ QCA_EXPORT bool haveSecureRandom(); /** Test if a capability (algorithm) is available. Since capabilities are made available at runtime, you should always check before using a capability the first time, as shown below. \code QCA::init(); if(!QCA::isSupported("sha1")) printf("SHA1 not supported!\n"); else { QString result = QCA::SHA1::hashToString(myString); printf("sha1(\"%s\") = [%s]\n", myString.data(), qPrintable(result)); } \endcode \param features the name of the capability to test for \param provider if specified, only check for the capability in that specific provider. If not provided, or provided as an empty string, then check for capabilities in all available providers \return true if the capability is available, otherwise false Note that you can test for a combination of capabilities, using a comma delimited list: \code QCA::isSupported("sha1,md5"): \endcode which will return true if all of the capabilities listed are present. */ QCA_EXPORT bool isSupported(const char *features, const QString &provider = QString()); /** \overload \param features a list of features to test for \param provider if specified, only check for the capability in that specific provider. If not provided, or provided as an empty string, then check for capabilities in all available providers */ QCA_EXPORT bool isSupported(const QStringList &features, const QString &provider = QString()); /** Generate a list of all the supported features in plugins, and in built in capabilities \return a list containing the names of the features The following code writes a list of features to standard out \code QStringList capabilities; capabilities = QCA::supportedFeatures(); std::cout << "Supported:" << capabilities.join(",") << std::endl; \endcode \sa isSupported(const char *features) \sa isSupported(const QStringList &features) \sa defaultFeatures() */ QCA_EXPORT QStringList supportedFeatures(); /** Generate a list of the built in features. This differs from supportedFeatures() in that it does not include features provided by plugins. \return a list containing the names of the features The following code writes a list of features to standard out \code QStringList capabilities; capabilities = QCA::defaultFeatures(); std::cout << "Default:" << capabilities.join(",") << std::endl; \endcode \sa isSupported \sa supportedFeatures() */ QCA_EXPORT QStringList defaultFeatures(); /** Add a provider to the current list of providers This function allows you to add a provider to the current plugin providers at a specified priority. If a provider with the name already exists, this call fails. \param p a pointer to a Provider object, which must be set up. \param priority the priority level to set the provider to \return true if the provider is added, and false if the provider is not added (failure) \sa setProviderPriority for a description of the provider priority system */ QCA_EXPORT bool insertProvider(Provider *p, int priority = 0); /** Change the priority of a specified provider QCA supports a number of providers, and if a number of providers support the same algorithm, it needs to choose between them. You can do this at object instantiation time (by specifying the name of the provider that should be used). Alternatively, you can provide a relative priority level at an application level, using this call. Priority is used at object instantiation time. The provider is selected according to the following logic: - if a particular provider is nominated, and that provider supports the required algorithm, then the nominated provider is used - if no provider is nominated, or it doesn't support the required algorithm, then the provider with the lowest priority number will be used, if that provider supports the algorithm. - if the provider with the lowest priority number doesn't support the required algorithm, the provider with the next lowest priority number will be tried, and so on through to the provider with the largest priority number - if none of the plugin providers support the required algorithm, then the default (built-in) provider will be tried. \param name the name of the provider \param priority the new priority of the provider. As a special case, if you pass in -1, then this provider gets the same priority as the the last provider that was added or had its priority set using this call. \sa providerPriority */ QCA_EXPORT void setProviderPriority(const QString &name, int priority); /** Return the priority of a specified provider The name of the provider (eg "qca-ossl") is used to look up the current priority associated with that provider. If the provider is not found (or something else went wrong), -1 is returned. \param name the name of the provider \return the current priority level \sa setProviderPriority for a description of the provider priority system */ QCA_EXPORT int providerPriority(const QString &name); /** Return a list of the current providers The current plugin providers are provided as a list, which you can iterate over using ProviderListIterator. \sa ProviderList \sa ProviderListIterator */ QCA_EXPORT ProviderList providers(); /** Return the named provider, or 0 if not found \param name the name of the provider to search for. */ QCA_EXPORT Provider *findProvider(const QString &name); /** Return the default provider */ QCA_EXPORT Provider *defaultProvider(); /** Scan for new plugins */ QCA_EXPORT void scanForPlugins(); /** Unload the current plugins */ QCA_EXPORT void unloadAllPlugins(); /** Retrieve plugin diagnostic text */ QCA_EXPORT QString pluginDiagnosticText(); /** Clear plugin diagnostic text */ QCA_EXPORT void clearPluginDiagnosticText(); /** Add plugin diagnostic text This function should only be called by providers. \param text the diagnostic message to append */ QCA_EXPORT void appendPluginDiagnosticText(const QString &text); /** Set a global property \param name the name of the property \param value the value to set the property to \sa getProperty */ QCA_EXPORT void setProperty(const QString &name, const QVariant &value); /** Retrieve a global property \param name the name of the property to look up \sa setProperty */ QCA_EXPORT QVariant getProperty(const QString &name); /** Set provider configuration Allowed value types: QString, int, bool \param name the name of the provider to set the configuration to \param config the configuration */ QCA_EXPORT void setProviderConfig(const QString &name, const QVariantMap &config); /** Retrieve provider configuration \param name the name of the provider to retrieve the configuration of */ QCA_EXPORT QVariantMap getProviderConfig(const QString &name); /** Save provider configuration to persistent storage \param name the name of the provider to have its configuration saved */ QCA_EXPORT void saveProviderConfig(const QString &name); /** Return the name of the global random number provider */ QCA_EXPORT QString globalRandomProvider(); /** Change the global random number provider The Random capabilities of %QCA are provided as part of the built in capabilities, however the generator can be changed if required. \param provider the name of the provider to use as the global random provider. */ QCA_EXPORT void setGlobalRandomProvider(const QString &provider); /** Return a reference to the %QCA Logger, which is used for diagnostics and error recording. The system Logger is automatically created for you on start. */ QCA_EXPORT Logger *logger(); /** Log a text message. This is an efficient function to avoid overhead of argument executions when log level blocks the message. \param message the text to log \param severity the type of information to log \note This is a macro, so arguments may or may not be evaluated. */ #define QCA_logTextMessage(message, severity) \ do { \ register QCA::Logger::Severity s = severity; \ register QCA::Logger *l = QCA::logger (); \ if (s <= l->level ()) { \ l->logTextMessage (message, s); \ } \ } while (false) /** Log a binary message. This is an efficient function to avoid overhead of argument executions when log level blocks the message. \param blob the blob to log \param severity the type of information to log \note This is a macro, so arguments may or may not be evaluated. */ #define QCA_logBinaryMessage(blob, severity) \ do { \ register QCA::Logger::Severity s = severity; \ register QCA::Logger *l = QCA::logger (); \ if (s <= l->level ()) { \ l->logBinaryMessage (blob, s); \ } \ } while (false) /** Test if QCA can access the root CA certificates If root certificates are available, this function returns true, otherwise it returns false. \sa systemStore */ QCA_EXPORT bool haveSystemStore(); /** Get system-wide root Certificate Authority (CA) certificates Many operating systems (or distributions, on Linux-type systems) come with some trusted certificates. Typically, these include the root certificates for major Certificate Authorities (for example, Verisign, Comodo) and some additional certificates that are used for system updates. They are provided in different ways for different systems. This function provides an common way to access the system certificates. There are other ways to access certificates - see the various I/O methods (such as fromDER() and fromPEM()) in the Certificate and CertificateCollection classes. \note Availability of the system certificates depends on how %QCA was built. You can test whether the system certificates are available using the haveSystemStore() function. */ QCA_EXPORT CertificateCollection systemStore(); /** Get the application name that will be used by SASL server mode The application name is used by SASL in server mode, as some systems might have different security policies depending on the app. The default application name is 'qca' */ QCA_EXPORT QString appName(); /** Set the application name that will be used by SASL server mode The application name is used by SASL in server mode, as some systems might have different security policies depending on the app. This should be set before using SASL objects, and it cannot be changed later. \param name the name string to use for SASL server mode */ QCA_EXPORT void setAppName(const QString &name); /** Convert a byte array to printable hexadecimal representation. This is a convenience function to convert an arbitrary QByteArray to a printable representation. \code QByteArray test(10); test.fill('a'); // 0x61 is 'a' in ASCII if (QString("61616161616161616161") == QCA::arrayToHex(test) ) { printf ("arrayToHex passed\n"); } \endcode \param array the array to be converted \return a printable representation */ QCA_EXPORT QString arrayToHex(const QByteArray &array); /** Convert a QString containing a hexadecimal representation of a byte array into a QByteArray This is a convenience function to convert a printable representation into a QByteArray - effectively the inverse of QCA::arrayToHex. \code QCA::init(); QByteArray test(10); test.fill('b'); // 0x62 in hexadecimal test[7] = 0x00; // can handle strings with nulls if (QCA::hexToArray(QString("62626262626262006262") ) == test ) { printf ("hexToArray passed\n"); } \endcode \param hexString the string containing a printable representation to be converted \return the equivalent QByteArray */ QCA_EXPORT QByteArray hexToArray(const QString &hexString); /** \class Initializer qca_core.h QtCrypto Convenience method for initialising and cleaning up %QCA To ensure that QCA is properly initialised and cleaned up, it is convenient to create an Initializer object, and let it go out of scope at the end of %QCA usage. \ingroup UserAPI */ class QCA_EXPORT Initializer { public: /** Standard constructor \param m the MemoryMode to use for secure memory \param prealloc the amount of secure memory to pre-allocate, in units of 1024 bytes (1K). */ explicit Initializer(MemoryMode m = Practical, int prealloc = 64); ~Initializer(); }; /** \class KeyLength qca_core.h QtCrypto Simple container for acceptable key lengths The KeyLength specifies the minimum and maximum byte sizes allowed for a key, as well as a "multiple" which the key size must evenly divide into. As an example, if the key can be 4, 8 or 12 bytes, you can express this as \code KeyLength keyLen( 4, 12, 4 ); \endcode If you want to express a KeyLength that takes any number of bytes (including zero), you may want to use \code #include KeyLength( 0, std::numeric_limits::max(), 1 ); \endcode \ingroup UserAPI */ class QCA_EXPORT KeyLength { public: /** Construct a %KeyLength object \param min the minimum length of the key, in bytes \param max the maximum length of the key, in bytes \param multiple the number of bytes that the key must be a multiple of. */ KeyLength(int min, int max, int multiple) : _min( min ), _max(max), _multiple( multiple ) { } /** Obtain the minimum length for the key, in bytes */ int minimum() const { return _min; } /** Obtain the maximum length for the key, in bytes */ int maximum() const { return _max; } /** Return the number of bytes that the key must be a multiple of If this is one, then anything between minimum and maximum (inclusive) is acceptable. */ int multiple() const { return _multiple; } private: const int _min, _max, _multiple; }; /** \class Provider qca_core.h QtCrypto Algorithm provider Provider represents a plugin provider (or as a special case, the built-in provider). This is the class you need to inherit from to create your own plugin. You don't normally need to worry about this class if you are just using existing QCA capabilities and plugins, however there is nothing stopping you from using it to obtain information about specific plugins, as shown in the example below. \ingroup ProviderAPI */ class QCA_EXPORT Provider { public: virtual ~Provider(); class Context; /** Initialisation routine This routine will be called when your plugin is loaded, so this is a good place to do any one-off initialisation tasks. If you don't need any initialisation, just implement it as an empty routine. */ virtual void init(); /** Deinitialisation routine This routine will be called just before provider destruction. Notably, during QCA shutdown, deinit() will be called on all providers before any of the providers are destructed. Use this opportunity to free any resources that may be used by other providers. */ virtual void deinit(); /** Version number of the plugin The format is the same as QCA itself. Version 1.2.3 would be represented as 0x010203. The default returns 0 (version 0.0.0). */ virtual int version() const; /** Target QCA version for the provider. This is used to verify compatibility between the provider and QCA. For a provider to be used, it must supply major and minor version numbers here that are less-than or equal to the actual QCA version (the patch version number is ignored). This means an older provider may be used with a newer QCA, but a newer provider cannot be used with an older QCA. */ virtual int qcaVersion() const = 0; /** The name of the provider. Typically you just return a string containing a convenient name. \code QString name() const { return "qca-myplugin"; } \endcode \note The name is used to tell if a provider is already loaded, so you need to make sure it is unique amongst the various plugins. */ virtual QString name() const = 0; /** The capabilities (algorithms) of the provider. Typically you just return a fixed QStringList: \code QStringList features() const { QStringList list; list += "sha1"; list += "sha256"; list += "hmac(sha1)"; return list; } \endcode */ virtual QStringList features() const = 0; /** Optional credit text for the provider. You might display this information in a credits or "About" dialog. Returns an empty string if the provider has no credit text. Only report credit text when absolutely required (for example, an "advertisement clause" related to licensing). Do not use it for reporting general author information. */ virtual QString credit() const; /** Routine to create a plugin context You need to return a pointer to an algorithm Context that corresponds with the algorithm name specified. \param type the name of the algorithm required \code Context *createContext(const QString &type) { if ( type == "sha1" ) return new SHA1Context( this ); else if ( type == "sha256" ) return new SHA0256Context( this ); else if ( type == "hmac(sha1)" ) return new HMACSHA1Context( this ); else return 0; } \endcode Naturally you also need to implement the specified Context subclasses as well. */ virtual Context *createContext(const QString &type) = 0; /** Method to set up the default configuration options. If your provider needs some configuration options, this method allows you to establish default options. The user can then change the configuration options as required, and set them using configChanged(). You need to return a QVariantMap that has configuration options as the keys, and the default configuration as the values, as shown below: \code QVariantMap defaultConfig() const { QVariantMap myConfig; myConfig[ "firstOption" ] = QString("firstOptionValue"); myConfig[ "secondOption" ] = true; myConfig[ "thirdOpt" ] = 1243; return myConfig; } \endcode \sa configChanged for how to set the configuration; */ virtual QVariantMap defaultConfig() const; /** Method to set the configuration options. If your provider supports configuration options, you will be advised of user changes to the configuration when this method is called. \param config the new configuration to be used by the provider */ virtual void configChanged(const QVariantMap &config); }; /** \class QCA::Provider::Context qca_core.h QtCrypto Internal context class used for the plugin \internal \ingroup ProviderAPI */ class QCA_EXPORT Provider::Context : public QObject { Q_OBJECT public: virtual ~Context(); /** The Provider associated with this Context */ Provider *provider() const; /** The type of context, as passed to the constructor */ QString type() const; /** Create a duplicate of this Context */ virtual Context *clone() const = 0; /** Test if two Contexts have the same Provider \param c pointer to the Context to compare to \return true if the argument and this Context have the same provider. */ bool sameProvider(const Context *c) const; protected: /** Standard constructor \param parent the parent provider for this context \param type the name of the provider context type */ Context(Provider *parent, const QString &type); /** Copy constructor \param from the Context to copy from */ Context(const Context &from); private: // disable assignment Context & operator=(const Context &from); Provider *_provider; QString _type; }; /** \class BasicContext qca_core.h QtCrypto Base class to use for primitive provider contexts \internal This class inherits Provider::Context and calls moveToThread(0) on itself, thereby disabling the event properties of the underlying QObject. Context types that need to be a QObject should inherit from Provider::Context, those that don't should inherit from BasicContext. \ingroup ProviderAPI */ class QCA_EXPORT BasicContext : public Provider::Context { Q_OBJECT public: ~BasicContext(); protected: /** Standard constructor \param parent the parent provider for this context \param type the name of the provider context type */ BasicContext(Provider *parent, const QString &type); /** Copy constructor \param from the Context to copy from */ BasicContext(const BasicContext &from); private: // disable assignment BasicContext & operator=(const BasicContext &from); }; /** \class BufferedComputation qca_core.h QtCrypto General superclass for buffered computation algorithms A buffered computation is characterised by having the algorithm take data in an incremental way, then having the results delivered at the end. Conceptually, the algorithm has some internal state that is modified when you call update() and returned when you call final(). \ingroup UserAPI */ class QCA_EXPORT BufferedComputation { public: virtual ~BufferedComputation(); /** Reset the internal state */ virtual void clear() = 0; /** Update the internal state with a byte array \param a the byte array of data that is to be used to update the internal state. */ virtual void update(const MemoryRegion &a) = 0; /** Complete the algorithm and return the internal state */ virtual MemoryRegion final() = 0; /** Perform an "all in one" update, returning the result. This is appropriate if you have all the data in one array - just call process on that array, and you will get back the results of the computation. \note This will invalidate any previous computation using this object. \param a the data to process. */ MemoryRegion process(const MemoryRegion &a); }; /** \class Filter qca_core.h QtCrypto General superclass for filtering transformation algorithms A filtering computation is characterised by having the algorithm take input data in an incremental way, with results delivered for each input, or block of input. Some internal state may be managed, with the transformation completed when final() is called. If this seems a big vague, then you might try deriving your class from a subclass with stronger semantics, or if your update() function is always returning null results, and everything comes out at final(), try BufferedComputation. \ingroup UserAPI */ class QCA_EXPORT Filter { public: virtual ~Filter(); /** Reset the internal state */ virtual void clear() = 0; /** Process more data, returning the corresponding filtered version of the data. \param a the array containing data to process */ virtual MemoryRegion update(const MemoryRegion &a) = 0; /** Complete the algorithm, returning any additional results. */ virtual MemoryRegion final() = 0; /** Test if an update() or final() call succeeded. \return true if the previous call succeeded */ virtual bool ok() const = 0; /** Perform an "all in one" update, returning the result. This is appropriate if you have all the data in one array - just call process on that array, and you will get back the results of the computation. \note This will invalidate any previous computation using this object. \param a the data to process in this step */ MemoryRegion process(const MemoryRegion &a); }; /** \class Algorithm qca_core.h QtCrypto General superclass for an algorithm. This is a fairly abstract class, mainly used for implementing the backend "provider" interface. \ingroup UserAPI */ class QCA_EXPORT Algorithm { public: /** Standard copy constructor \param from the Algorithm to copy from */ Algorithm(const Algorithm &from); virtual ~Algorithm(); /** Assignment operator \param from the Algorithm to copy state from */ Algorithm & operator=(const Algorithm &from); /** The name of the algorithm type. */ QString type() const; /** The name of the provider Each algorithm is implemented by a provider. This allows you to figure out which provider is associated */ Provider *provider() const; // Note: The next five functions are not public! /** \internal The context associated with this algorithm */ Provider::Context *context(); /** \internal The context associated with this algorithm */ const Provider::Context *context() const; /** \internal Set the Provider for this algorithm \param c the context for the Provider to use */ void change(Provider::Context *c); /** \internal \overload \param type the name of the algorithm to use \param provider the name of the preferred provider */ void change(const QString &type, const QString &provider); /** \internal Take the Provider from this algorithm */ Provider::Context *takeContext(); protected: /** Constructor for empty algorithm */ Algorithm(); /** Constructor of a particular algorithm. \param type the algorithm to construct \param provider the name of a particular Provider */ Algorithm(const QString &type, const QString &provider); private: class Private; QSharedDataPointer d; }; /** \class SymmetricKey qca_core.h QtCrypto Container for keys for symmetric encryption algorithms. \ingroup UserAPI */ class QCA_EXPORT SymmetricKey : public SecureArray { public: /** Construct an empty (zero length) key */ SymmetricKey(); /** Construct an key of specified size, with random contents This is intended to be used as a random session key. \param size the number of bytes for the key */ SymmetricKey(int size); /** Construct a key from a provided byte array \param a the byte array to copy */ SymmetricKey(const SecureArray &a); /** Construct a key from a provided byte array \param a the byte array to copy */ SymmetricKey(const QByteArray &a); /** Test for weak DES keys \return true if the key is a weak key for DES */ bool isWeakDESKey(); }; /** \class InitializationVector qca_core.h QtCrypto Container for initialisation vectors and nonces \ingroup UserAPI */ class QCA_EXPORT InitializationVector : public SecureArray { public: /** Construct an empty (zero length) initisation vector */ InitializationVector(); /** Construct an initialisation vector of the specified size \param size the length of the initialisation vector, in bytes */ InitializationVector(int size); /** Construct an initialisation vector from a provided byte array \param a the byte array to copy */ InitializationVector(const SecureArray &a); /** Construct an initialisation vector from a provided byte array \param a the byte array to copy */ InitializationVector(const QByteArray &a); }; /** \class Event qca_core.h QtCrypto An asynchronous event Events are produced in response to the library's need for some user intervention, such as entering a pin or password, or inserting a cryptographic token. Event is an abstraction, so you can handle this need in a way that makes sense for your application. \ingroup UserAPI */ class QCA_EXPORT Event { public: /** %Type of event \sa type() */ enum Type { Password, ///< Asking for a password, PIN or passphrase. Token ///< Asking for a token }; /** %Source of the event Events are associated with access to a KeyStore, or access to a file (or bytearray/stream or equivalent). This tells you the type of source that caused the Event. \sa source() \sa fileName() for the name, if source is Event::Data \sa keyStoreInfo() and keyStoreEntry() for the keystore and entry, if the source is Event::KeyStore */ enum Source { KeyStore, ///< KeyStore generated the event Data ///< File or bytearray generated the event }; /** password variation If the Type of Event is Password, PasswordStyle tells you whether it is a PIN, passphrase or password. \sa passwordStyle() */ enum PasswordStyle { StylePassword, ///< User should be prompted for a "Password" StylePassphrase, ///< User should be prompted for a "Passphrase" StylePIN ///< User should be prompted for a "PIN" }; /** Constructor */ Event(); /** Copy constructor \param from the Event to copy from */ Event(const Event &from); /** Destructor */ ~Event(); /** Assignment operator \param from the Event to copy from */ Event & operator=(const Event &from); /** test if this event has been setup correctly */ bool isNull() const; /** the Type of this event */ Type type() const; /** the Source of this event */ Source source() const; /** the style of password required. This is not meaningful unless the Type is Event::Password. \sa PasswordStyle */ PasswordStyle passwordStyle() const; /** The info of the KeyStore associated with this event This is not meaningful unless the Source is KeyStore. */ KeyStoreInfo keyStoreInfo() const; /** The KeyStoreEntry associated with this event This is not meaningful unless the Source is KeyStore. */ KeyStoreEntry keyStoreEntry() const; /** Name or other identifier for the file or byte array associated with this event. This is not meaningful unless the Source is Data. */ QString fileName() const; /** opaque data */ void *ptr() const; /** Set the values for this Event This creates a Password type event, for a keystore. \param pstyle the style of information required (e.g. PIN, password or passphrase) \param keyStoreInfo info about the keystore that the information is required for \param keyStoreEntry the entry in the keystore that the information is required for \param ptr opaque data */ void setPasswordKeyStore(PasswordStyle pstyle, const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); /** Set the values for this Event This creates a Password type event, for a file. \param pstyle the style of information required (e.g. PIN, password or passphrase) \param fileName the name of the file (or other identifier) that the information is required for \param ptr opaque data */ void setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr); /** Set the values for this Event This creates a Token type event. \param keyStoreInfo info about the keystore that the token is required for \param keyStoreEntry the entry in the keystore that the token is required for \param ptr opaque data */ void setToken(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); private: class Private; QSharedDataPointer d; }; /** \class EventHandler qca_core.h QtCrypto Interface class for password / passphrase / PIN and token handlers This class is used on client side applications to handle the provision of passwords, passphrases and PINs by users, and to indicate that tokens have been correctly inserted. The concept behind this class is that the library can raise events (typically using PasswordAsker or TokenAsker), which may (or may not) be handled by the application using a handler object (that has-a EventHandler, or possibly is-a EventHandler) that is connected to the eventReady() signal. \ingroup UserAPI */ class QCA_EXPORT EventHandler : public QObject { Q_OBJECT public: /** Constructor \param parent the parent object for this object */ EventHandler(QObject *parent = 0); ~EventHandler(); /** mandatory function to call after connecting the signal to a slot in your application specific password / passphrase / PIN or token handler */ void start(); /** function to call to return the user provided password, passphrase or PIN. \param id the id corresponding to the password request \param password the user-provided password, passphrase or PIN. \note the id parameter is the same as that provided in the eventReady() signal. */ void submitPassword(int id, const SecureArray &password); /** function to call to indicate that the token has been inserted by the user. \param id the id corresponding to the password request \note the id parameter is the same as that provided in the eventReady() signal. */ void tokenOkay(int id); /** function to call to indicate that the user declined to provide a password, passphrase, PIN or token. \param id the id corresponding to the password request \note the id parameter is the same as that provided in the eventReady() signal. */ void reject(int id); Q_SIGNALS: /** signal emitted when an Event requires attention. You typically need to connect this signal to a compatible slot in your callback handler \param id the identification number for the event \param context information about the type of response required */ void eventReady(int id, const QCA::Event &context); private: Q_DISABLE_COPY(EventHandler) class Private; friend class Private; Private *d; }; /** \class PasswordAsker qca_core.h QtCrypto User password / passphrase / PIN handler This class is used to obtain a password from a user. \ingroup UserAPI */ class QCA_EXPORT PasswordAsker : public QObject { Q_OBJECT public: /** Construct a new asker \param parent the parent object for this QObject */ PasswordAsker(QObject *parent = 0); ~PasswordAsker(); /** queue a password / passphrase request associated with a key store \param pstyle the type of information required (e.g. PIN, passphrase or password) \param keyStoreInfo info of the key store that the information is required for \param keyStoreEntry the item in the key store that the information is required for (if applicable) \param ptr opaque data */ void ask(Event::PasswordStyle pstyle, const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); /** queue a password / passphrase request associated with a file \param pstyle the type of information required (e.g. PIN, passphrase or password) \param fileName the name of the file that the information is required for \param ptr opaque data */ void ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr); /** Cancel the pending password / passphrase request */ void cancel(); /** Block until the password / passphrase request is completed You can use the responseReady signal instead of blocking, if appropriate. */ void waitForResponse(); /** Determine whether the password / passphrase was accepted or not In this context, returning true is indicative of the user clicking "Ok" or equivalent; and returning false indicates that either the user clicked "Cancel" or equivalent, or that the cancel() function was called, or that the request is still pending. */ bool accepted() const; /** The password / passphrase / PIN provided by the user in response to the asker request. This may be empty. */ SecureArray password() const; Q_SIGNALS: /** Emitted when the asker process has been completed. You should check whether the user accepted() the response prior to relying on the password(). */ void responseReady(); private: Q_DISABLE_COPY(PasswordAsker) class Private; friend class Private; Private *d; }; /** \class TokenAsker qca_core.h QtCrypto User token handler This class is used to request the user to insert a token. \ingroup UserAPI */ class QCA_EXPORT TokenAsker : public QObject { Q_OBJECT public: /** Construct a new asker \param parent the parent object for this QObject */ TokenAsker(QObject *parent = 0); ~TokenAsker(); /** queue a token request associated with a key store \param keyStoreInfo info of the key store that the information is required for \param keyStoreEntry the item in the key store that the information is required for (if applicable) \param ptr opaque data */ void ask(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); /** Cancel the pending password / passphrase request */ void cancel(); /** Block until the token request is completed You can use the responseReady signal instead of blocking, if appropriate. */ void waitForResponse(); /** Test if the token request was accepted or not. \return true if the token request was accepted */ bool accepted() const; Q_SIGNALS: /** Emitted when the asker process has been completed. You should check whether the user accepted() the response prior to relying on token being present. */ void responseReady(); private: Q_DISABLE_COPY(TokenAsker) class Private; friend class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_keystore.h0000644000175000017500000004565311305557613022207 0ustar janjan/* * qca_keystore.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004,2005 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_keystore.h Header file for classes that provide and manage keys \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_KEYSTORE_H #define QCA_KEYSTORE_H #include "qca_core.h" #include "qca_cert.h" namespace QCA { class KeyStoreTracker; class KeyStoreManagerPrivate; class KeyStorePrivate; /** \class KeyStoreEntry qca_keystore.h QtCrypto Single entry in a KeyStore This is a container for any kind of object in a KeyStore (such as PGP keys, or X.509 certificates / private keys). KeyStoreEntry objects are obtained through KeyStore or loaded from a serialized string format. The latter method requires a KeyStoreEntry obtained through KeyStore to be serialized for future loading. For example: \code QString str = someKeyStoreEntry.toString(); [ app saves str to disk ] [ app quits ] ... [ app launches ] [ app reads str from disk ] KeyStoreEntry entry(str); printf("Entry name: [%s]\n", qPrintable(entry.name())); \endcode KeyStoreEntry objects may or may not be available. An entry is unavailable if it has a private content that is not present. The private content might exist on external hardware. To determine if an entry is available, call isAvailable(). To ensure an entry is available before performing a private key operation, call ensureAvailable. For example: \code if(entry.ensureAvailable()) { entry.keyBundle().privateKey().signMessage(...); ... } \endcode ensureAvailable() blocks and may cause hardware access, but if it completes successfully then you may use the entry's private content. It also means, in the case of a Smart Card token, that it is probably inserted. To watch this entry asynchronously, you would do: \code KeyStoreEntryWatcher *watcher = new KeyStoreEntryWatcher(entry); connect(watcher, SIGNAL(available()), SLOT(entry_available())); ... void entry_available() { // entry now available watcher->entry().keyBundle().privateKey().signMessage(...); } \endcode Unlike private content, public content is always usable even if the entry is not available. Serialized entry data contains all of the metadata necessary to reconstruct the public content. Now, even though an entry may be available, it does not mean you have access to use it for operations. For example, even though a KeyBundle entry offered by a Smart Card may be available, as soon as you try to use the PrivateKey object for a signing operation, a PIN might be asked for. You can call ensureAccess() if you want to synchronously provide the PIN early on: \code if(entry.ensureAccess()) { // do private key stuff ... } \endcode Note that you don't have to call ensureAvailable() before ensureAccess(). Calling the latter is enough to imply both. After an application is configured to use a particular key, it is expected that its usual running procedure will be: 1) Construct KeyStoreEntry from the serialized data. 2) If the content object is not available, wait for it (with either ensureAvailable() or KeyStoreEntryWatcher). 3) Pass the content object(s) to a high level operation like TLS. In this case, any PIN prompting and private key operations would be caused/handled from the TLS object. Omit step 2 and the private key operations might cause token prompting. \ingroup UserAPI */ class QCA_EXPORT KeyStoreEntry : public Algorithm { public: /** The type of entry in the KeyStore */ enum Type { TypeKeyBundle, TypeCertificate, TypeCRL, TypePGPSecretKey, TypePGPPublicKey }; /** Create an empty KeyStoreEntry */ KeyStoreEntry(); /** Create a passive KeyStoreEntry based on a serialized string \param serialized the string containing the keystore entry information \sa fromString */ KeyStoreEntry(const QString &serialized); /** Standard copy constructor \param from the source entry */ KeyStoreEntry(const KeyStoreEntry &from); ~KeyStoreEntry(); /** Standard assignment operator \param from the source entry */ KeyStoreEntry & operator=(const KeyStoreEntry &from); /** Test if this key is empty (null) */ bool isNull() const; /** Test if the key is available for use. A key is considered available if the key's private content is present. \sa ensureAvailable \sa isAccessible */ bool isAvailable() const; /** Test if the key is currently accessible. This means that the private key part can be used at this time. For a smartcard, this means that all required operations (e.g. login / PIN entry) are completed. If isAccessible() is true, then the key is necessarily available (i.e. isAvailable() is also true). \sa ensureAccessible \sa isAvailable */ bool isAccessible() const; /** Determine the type of key stored in this object */ Type type() const; /** The name associated with the key stored in this object */ QString name() const; /** The ID associated with the key stored in this object. */ QString id() const; /** The name of the KeyStore for this key object */ QString storeName() const; /** The id of the KeyStore for this key object \sa KeyStore::id() */ QString storeId() const; /** Serialize into a string for use as a passive entry */ QString toString() const; /** Load a passive entry by using a serialized string as input \param serialized the string containing the keystore entry information \return the newly created KeyStoreEntry */ static KeyStoreEntry fromString(const QString &serialized); /** If a KeyBundle is stored in this object, return that bundle. */ KeyBundle keyBundle() const; /** If a Certificate is stored in this object, return that certificate. */ Certificate certificate() const; /** If a CRL is stored in this object, return the value of the CRL */ CRL crl() const; /** If the key stored in this object is a private PGP key, return the contents of that key. */ PGPKey pgpSecretKey() const; /** If the key stored in this object is either an public or private PGP key, extract the public key part of that PGP key. */ PGPKey pgpPublicKey() const; /** Returns true if the entry is available, otherwise false. Available means that any private content for this entry is present and ready for use. In the case of a smart card, this will ensure the card is inserted, and may invoke a token prompt. Calling this function on an already available entry may cause the entry to be refreshed. \sa isAvailable \sa ensureAccess \note This function is blocking. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ bool ensureAvailable(); /** Like ensureAvailable, but will also ensure that the PIN is provided if needed. \sa isAccessible \sa ensureAvailable \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ bool ensureAccess(); private: class Private; Private *d; friend class KeyStoreTracker; }; /** \class KeyStoreEntryWatcher qca_keystore.h QtCrypto Class to monitor the availability of a KeyStoreEntry Some KeyStore types have the concept of an entry that can be available only part of the time (for example, a smart card that can be removed). This class allows you to identify when a KeyStoreEntry becomes available / unavailable. \note You can also monitor availability of a whole KeyStore, using KeyStoreManager::keyStoreAvailable() signal, and the KeyStore::unavailable() signal. \sa KeyStore for more discussion on availability of keys and related objects. \ingroup UserAPI */ class QCA_EXPORT KeyStoreEntryWatcher : public QObject { Q_OBJECT public: /** Standard constructor. This creates an object that monitors the specified KeyStore entry, emitting available() and unavailable() as the entry becomes available and unavailable respectively. \param e the KeyStoreEntry to monitor \param parent the parent object for this object */ explicit KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent = 0); ~KeyStoreEntryWatcher(); /** The KeyStoreEntry that is being monitored */ KeyStoreEntry entry() const; Q_SIGNALS: /** This signal is emitted when the entry that is being monitored becomes available. */ void available(); /** This signal is emitted when the entry that is being monitored becomes unavailble. */ void unavailable(); private: Q_DISABLE_COPY(KeyStoreEntryWatcher) class Private; friend class Private; Private *d; }; /** \class KeyStore qca_keystore.h QtCrypto General purpose key storage object Examples of use of this are: - systemstore: System TrustedCertificates - accepted self-signed: Application TrustedCertificates - apple keychain: User Identities - smartcard: SmartCard Identities - gnupg: PGPKeyring Identities,PGPPublicKeys \note - there can be multiple KeyStore objects referring to the same id - when a KeyStore is constructed, it refers to a given id (deviceId) and internal contextId. if the context goes away, the KeyStore becomes invalid (isValid() == false), and unavailable() is emitted. even if the device later reappears, the KeyStore remains invalid. a new KeyStore will have to be created to use the device again. \ingroup UserAPI */ class QCA_EXPORT KeyStore : public QObject, public Algorithm { Q_OBJECT public: /** The type of keystore */ enum Type { System, ///< objects such as root certificates User, ///< objects such as Apple Keychain, KDE Wallet Application, ///< for caching accepted self-signed certificates SmartCard, ///< for smartcards PGPKeyring ///< for a PGP keyring }; /** Obtain a specific KeyStore \param id the identification for the key store \param keyStoreManager the parent manager for this keystore */ KeyStore(const QString &id, KeyStoreManager *keyStoreManager); ~KeyStore(); /** Check if this KeyStore is valid \return true if the KeyStore is valid */ bool isValid() const; /** The KeyStore Type */ Type type() const; /** The name associated with the KeyStore */ QString name() const; /** The ID associated with the KeyStore */ QString id() const; /** Test if the KeyStore is writeable or not \return true if the KeyStore is read-only */ bool isReadOnly() const; /** Turns on asynchronous mode for this KeyStore instance. Normally, entryList() and writeEntry() are blocking calls. However, if startAsynchronousMode() is called, then these functions will return immediately. entryList() will return with the latest known entries, or an empty list if none are known yet (in this mode, updated() will be emitted once the initial entries are known, even if the store has not actually been altered). writeEntry() will always return an empty string, and the entryWritten() signal indicates the result of a write. */ void startAsynchronousMode(); /** A list of the KeyStoreEntry objects in this store \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler (this is not a concern if asynchronous mode is enabled). \sa startAsynchronousMode */ QList entryList() const; /** test if the KeyStore holds trusted certificates (and CRLs) */ bool holdsTrustedCertificates() const; /** test if the KeyStore holds identities (eg KeyBundle or PGPSecretKey) */ bool holdsIdentities() const; /** test if the KeyStore holds PGPPublicKey objects */ bool holdsPGPPublicKeys() const; /** Add a entry to the KeyStore Returns the entryId of the written entry or an empty string on failure. \param kb the KeyBundle to add to the KeyStore \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler (this is not a concern if asynchronous mode is enabled). \sa startAsynchronousMode */ QString writeEntry(const KeyBundle &kb); /** \overload \param cert the Certificate to add to the KeyStore */ QString writeEntry(const Certificate &cert); /** \overload \param crl the CRL to add to the KeyStore */ QString writeEntry(const CRL &crl); /** \overload \param key the PGPKey to add to the KeyStore \return a ref to the key in the keyring */ QString writeEntry(const PGPKey &key); /** Delete the a specified KeyStoreEntry from this KeyStore \param id the ID for the entry to be deleted \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler (this is not a concern if asynchronous mode is enabled). \sa startAsynchronousMode */ bool removeEntry(const QString &id); Q_SIGNALS: /** Emitted when the KeyStore is changed This occurs if entries are added, removed, or changed in this KeyStore, including changes in entry availability. */ void updated(); /** Emitted when the KeyStore becomes unavailable */ void unavailable(); /** Emitted when an entry has been written, in asynchronous mode. \param entryId is the newly written entry id on success, or an empty string if the write failed. */ void entryWritten(const QString &entryId); /** Emitted when an entry has been removed, in asynchronous mode. \param success indicates if the removal succeeded (true) or not (false). */ void entryRemoved(bool success); private: Q_DISABLE_COPY(KeyStore) friend class KeyStorePrivate; KeyStorePrivate *d; friend class KeyStoreManagerPrivate; }; /** \class KeyStoreInfo qca_keystore.h QtCrypto Key store information, outside of a KeyStore object This class is used in conjunction with the Event class, and related classes such as PasswordAsker and TokenAsker, to describe the key store source of the Event. Each KeyStoreInfo represents a single KeyStore, and describes the type of store (e.g. smartcard or PGP keyring - see KeyStore::Type), and a couple of names. The id() of a KeyStore is used to reference it, and is typically of the form "qca-mystorename". The name() of a KeyStore is used to describe it (i.e. this is the "pretty" name to show the user), and is typically of the form "My Store Name". \ingroup UserAPI */ class QCA_EXPORT KeyStoreInfo { public: /** Constructor. \note This form of constructor for KeyStoreInfo produces an object that does not describe any KeyStore, and isNull() will return true. */ KeyStoreInfo(); /** Standard constructor. This builds a KeyStoreInfo object that descibes a KeyStore. \param type the type of KeyStore \param id the identification of the KeyStore \param name the descriptive name of the KeyStore */ KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name); /** Copy constructor. \param from the KeyStoreInfo to copy from */ KeyStoreInfo(const KeyStoreInfo &from); ~KeyStoreInfo(); /** Assignment operator. \param from the KeyStoreInfo to copy from */ KeyStoreInfo & operator=(const KeyStoreInfo &from); /** Test if this object is valid \return true if the object is not valid */ bool isNull() const; /** The Type of KeyStore that this KeyStoreInfo object describes. */ KeyStore::Type type() const; /** The unique identification of the KeyStore that this KeyStoreInfo object describes. */ QString id() const; /** The descriptive name of the KeyStore that this KeyStoreInfo object describes. */ QString name() const; private: class Private; QSharedDataPointer d; }; /** \class KeyStoreManager qca_keystore.h QtCrypto Access keystores, and monitor keystores for changes. Before you can access a KeyStore, you must create a KeyStoreManager. You then need to start() the KeyStoreManager, and either wait for the busyFinished() signal, or block using waitForBusyFinished(). If you know the KeyStoreEntry that you need, you can use KeyStore passively, as described in the KeyStoreEntry documentation. \ingroup UserAPI */ class QCA_EXPORT KeyStoreManager : public QObject { Q_OBJECT public: /** Create a new KeyStoreManager \param parent the parent for this object */ KeyStoreManager(QObject *parent = 0); ~KeyStoreManager(); /** Initialize all key store providers */ static void start(); /** Initialize a specific key store provider \param provider the name of the provider to start */ static void start(const QString &provider); /** Indicates if the manager is busy looking for key stores */ bool isBusy() const; /** Blocks until the manager is done looking for key stores */ void waitForBusyFinished(); /** A list of all the key stores */ QStringList keyStores() const; /** The diagnostic result of key store operations, such as warnings and errors */ static QString diagnosticText(); /** Clears the diagnostic result log */ static void clearDiagnosticText(); /** If you are not using the eventloop, call this to update the object state to the present */ void sync(); Q_SIGNALS: /** emitted when the manager has started looking for key stores */ void busyStarted(); /** emitted when the manager has finished looking for key stores */ void busyFinished(); /** emitted when a new key store becomes available \param id the name of the key store that has become available */ void keyStoreAvailable(const QString &id); private: Q_DISABLE_COPY(KeyStoreManager) friend class KeyStoreManagerPrivate; KeyStoreManagerPrivate *d; friend class Global; friend class KeyStorePrivate; static void scan(); static void shutdown(); }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_securelayer.h0000644000175000017500000010305111305557613022650 0ustar janjan/* * qca_securelayer.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004-2006 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_securelayer.h Header file for SecureLayer and its subclasses \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_SECURELAYER_H #define QCA_SECURELAYER_H #include #include "qca_core.h" #include "qca_publickey.h" #include "qca_cert.h" namespace QCA { /** Specify the lower-bound for acceptable TLS/SASL security layers For TLS, the interpretation of these levels is: - Any cipher suite that provides non-authenticated communications (usually anonymous Diffie-Hellman) is SL_Integrity. - Any cipher suite that is limited to 40 bits (export-version crippled forms of RC2, RC4 or DES) is SL_Export. Standard DES (56 bits) and some forms of RC4 (64 bits) are also SL_Export. - Any normal cipher (AES, Camellia, RC4 or similar) with 128 bits, or Elliptic Curve Ciphers with 283 bits, is SL_Baseline - AES or Camellia at least 192 bits, triple-DES and similar ciphers are SL_High. ECC with 409 or more bits is also SL_High. - Highest does not have an equivalent strength. It indicates that the provider should use the strongest ciphers available (but not less than SL_High). */ enum SecurityLevel { SL_None, ///< indicates that no security is ok SL_Integrity, ///< must at least get integrity protection SL_Export, ///< must be export level bits or more SL_Baseline, ///< must be 128 bit or more SL_High, ///< must be more than 128 bit SL_Highest ///< SL_High or max possible, whichever is greater }; /** \class SecureLayer qca_securelayer.h QtCrypto Abstract interface to a security layer SecureLayer is normally used between an application and a potentially insecure network. It provides secure communications over that network. The concept is that (after some initial setup), the application can write() some data to the SecureLayer implementation, and that data is encrypted (or otherwise protected, depending on the setup). The SecureLayer implementation then emits the readyReadOutgoing() signal, and the application uses readOutgoing() to retrieve the the encrypted data from the SecureLayer implementation. The encrypted data is then sent out on the network. When some encrypted data comes back from the network, the application does a writeIncoming() to the SecureLayer implementation. Some time later, the SecureLayer implementation may emit readyRead() to the application, which then read()s the decrypted data from the SecureLayer implementation. Note that sometimes data is sent or received between the SecureLayer implementation and the network without any data being sent between the application and the SecureLayer implementation. This is a result of the initial negotiation activities (which require network traffic to agree a configuration to use) and other overheads associated with the secure link. \ingroup UserAPI */ class QCA_EXPORT SecureLayer : public QObject { Q_OBJECT public: /** Constructor for an abstract secure communications layer \param parent the parent object for this object */ SecureLayer(QObject *parent = 0); /** Returns true if the layer has a meaningful "close". */ virtual bool isClosable() const; /** Returns the number of bytes available to be read() on the application side. */ virtual int bytesAvailable() const = 0; /** Returns the number of bytes available to be readOutgoing() on the network side. */ virtual int bytesOutgoingAvailable() const = 0; /** Close the link. Note that this may not be meaningful / possible for all implementations. \sa isClosable() for a test that verifies if the link can be %closed. */ virtual void close(); /** This method writes unencrypted (plain) data to the SecureLayer implementation. You normally call this function on the application side. \param a the source of the application-side data */ virtual void write(const QByteArray &a) = 0; /** This method reads decrypted (plain) data from the SecureLayer implementation. You normally call this function on the application side after receiving the readyRead() signal. */ virtual QByteArray read() = 0; /** This method accepts encoded (typically encrypted) data for processing. You normally call this function using data read from the network socket (e.g. using QTcpSocket::readAll()) after receiving a signal that indicates that the socket has data to read. \param a the ByteArray to take network-side data from */ virtual void writeIncoming(const QByteArray &a) = 0; /** This method provides encoded (typically encrypted) data. You normally call this function to get data to write out to the network socket (e.g. using QTcpSocket::write()) after receiving the readyReadOutgoing() signal. \param plainBytes the number of bytes that were read. */ virtual QByteArray readOutgoing(int *plainBytes = 0) = 0; /** This allows you to read data without having it decrypted first. This is intended to be used for protocols that close off the connection and return to plain text transfer. You do not normally need to use this function. */ virtual QByteArray readUnprocessed(); /** Convert encrypted bytes written to plain text bytes written \param encryptedBytes the number of bytes to convert */ virtual int convertBytesWritten(qint64 encryptedBytes) = 0; Q_SIGNALS: /** This signal is emitted when SecureLayer has decrypted (application side) data ready to be read. Typically you will connect this signal to a slot that reads the data (using read()). */ void readyRead(); /** This signal is emitted when SecureLayer has encrypted (network side) data ready to be read. Typically you will connect this signal to a slot that reads the data (using readOutgoing()) and writes it to a network socket. */ void readyReadOutgoing(); /** This signal is emitted when the SecureLayer connection is %closed. */ void closed(); /** This signal is emitted when an error is detected. You can determine the error type using errorCode(). */ void error(); private: Q_DISABLE_COPY(SecureLayer) }; /** \class TLSSession qca_securelayer.h QtCrypto Session token, used for TLS resuming \ingroup UserAPI */ class QCA_EXPORT TLSSession : public Algorithm { public: TLSSession(); /** Copy constructor \param from the session token to copy from */ TLSSession(const TLSSession &from); ~TLSSession(); /** Assignment operator \param from the session token to assign from */ TLSSession & operator=(const TLSSession &from); /** Test if the session token is valid */ bool isNull() const; }; /** \class TLS qca_securelayer.h QtCrypto Transport Layer Security / Secure Socket Layer Transport Layer Security (%TLS) is the current state-of-the-art in secure transport mechanisms over the internet. It can be used in a way where only one side of the link needs to authenticate to the other. This makes it very useful for servers to provide their identity to clients. Note that is is possible to use %TLS to authenticate both client and server. %TLS is a IETF standard (RFC2712 for TLS version 1.0, and RFC4346 for TLS version 1.1) based on earlier Netscape work on Secure Socket Layer (SSL version 2 and SSL version 3). New applications should use at least TLS 1.0, and SSL version 2 should be avoided due to known security problems. \ingroup UserAPI */ class QCA_EXPORT TLS : public SecureLayer, public Algorithm { Q_OBJECT public: /** Operating mode */ enum Mode { Stream, ///< stream mode Datagram ///< datagram mode }; /** Version of %TLS or SSL */ enum Version { TLS_v1, ///< Transport Layer Security, version 1 SSL_v3, ///< Secure Socket Layer, version 3 SSL_v2, ///< Secure Socket Layer, version 2 DTLS_v1 ///< Datagram Transport Layer Security, version 1 }; /** Type of error */ enum Error { ErrorSignerExpired, ///< local certificate is expired ErrorSignerInvalid, ///< local certificate is invalid in some way ErrorCertKeyMismatch, ///< certificate and private key don't match ErrorInit, ///< problem starting up %TLS ErrorHandshake, ///< problem during the negotiation ErrorCrypt ///< problem at anytime after }; /** Type of identity */ enum IdentityResult { Valid, ///< identity is verified HostMismatch, ///< valid cert provided, but wrong owner InvalidCertificate, ///< invalid cert NoCertificate ///< identity unknown }; /** Constructor for Transport Layer Security connection This produces a Stream (normal %TLS) rather than Datagram (DTLS) object. If you want to do DTLS, see below. \param parent the parent object for this object \param provider the name of the provider, if a specific provider is required */ explicit TLS(QObject *parent = 0, const QString &provider = QString()); /** Constructor for Transport Layer Security connection. This constructor can be used for both normal %TLS (set mode to TLS::Stream) or DTLS (set mode to TLS::Datagram). \param mode the connection Mode \param parent the parent object for this object \param provider the name of the provider, if a specific provider is required */ explicit TLS(Mode mode, QObject *parent = 0, const QString &provider = QString()); /** Destructor */ ~TLS(); /** Reset the connection */ void reset(); /** Get the list of cipher suites that are available for use. A cipher suite is a combination of key exchange, encryption and hashing algorithms that are agreed during the initial handshake between client and server. \param version the protocol Version that the cipher suites are required for \return list of the the names of the cipher suites supported. */ QStringList supportedCipherSuites(const Version &version = TLS_v1) const; /** The local certificate to use. This is the certificate that will be provided to the peer. This is almost always required on the server side (because the server has to provide a certificate to the client), and may be used on the client side. \param cert a chain of certificates that link the host certificate to a trusted root certificate. \param key the private key for the certificate chain */ void setCertificate(const CertificateChain &cert, const PrivateKey &key); /** \overload Allows setting a certificate from a KeyBundle. \param kb key bundle containing the local certificate and associated private key. */ void setCertificate(const KeyBundle &kb); /** Return the trusted certificates set for this object */ CertificateCollection trustedCertificates() const; /** Set up the set of trusted certificates that will be used to verify that the certificate provided is valid. Typically, this will be the collection of root certificates from the system, which you can get using QCA::systemStore(), however you may choose to pass whatever certificates match your assurance needs. \param trusted a bundle of trusted certificates. */ void setTrustedCertificates(const CertificateCollection &trusted); /** The security level required for this link \param s the level required for this link. */ void setConstraints(SecurityLevel s); /** \overload \param minSSF the minimum Security Strength Factor required for this link. \param maxSSF the maximum Security Strength Factor required for this link. */ void setConstraints(int minSSF, int maxSSF); /** \overload \param cipherSuiteList a list of the names of cipher suites that can be used for this link. \note the names are the same as the names in the applicable IETF RFCs (or Internet Drafts if there is no applicable RFC). */ void setConstraints(const QStringList &cipherSuiteList); /** Retrieve the list of allowed issuers by the server, if the server has provided them. Only DN types will be present. \code Certificate someCert = ... PrivateKey someKey = ... // see if the server will take our cert CertificateInfoOrdered issuerInfo = someCert.issuerInfoOrdered().dnOnly(); foreach(const CertificateInfoOrdered &info, tls->issuerList()) { if(info == issuerInfo) { // server will accept someCert, let's present it tls->setCertificate(someCert, someKey); break; } } \endcode */ QList issuerList() const; /** Sets the issuer list to present to the client. For use with servers only. Only DN types are allowed. \param issuers the list of valid issuers to be used. */ void setIssuerList(const QList &issuers); /** Resume a %TLS session using the given session object \param session the session state to use for resumption. */ void setSession(const TLSSession &session); /** Test if the link can use compression \return true if the link can use compression */ bool canCompress() const; /** Test if the link can specify a hostname (Server Name Indication) \return true if the link can specify a hostname */ bool canSetHostName() const; /** Returns true if compression is enabled This only indicates whether or not the object is configured to use compression, not whether or not the link is actually compressed. Use isCompressed() for that. */ bool compressionEnabled() const; /** Set the link to use compression \param b true if the link should use compression, or false to disable compression */ void setCompressionEnabled(bool b); /** Returns the host name specified or an empty string if no host name is specified. */ QString hostName() const; /** Start the %TLS/SSL connection as a client Typically, you'll want to perform RFC 2818 validation on the server's certificate, based on the hostname you're intending to connect to. Pass a value for \a host in order to have the validation for you. If you want to bypass this behavior and do the validation yourself, pass an empty string for \a host. If the host is an internationalized domain name, then it must be provided in unicode format, not in IDNA ACE/punycode format. \param host the hostname that you want to connect to \note The hostname will be used for Server Name Indication extension (see RFC 3546 Section 3.1) if supported by the backend provider. */ void startClient(const QString &host = QString()); /** Start the %TLS/SSL connection as a server. */ void startServer(); /** Resumes %TLS processing. Call this function after hostNameReceived(), certificateRequested() peerCertificateAvailable() or handshaken() is emitted. By requiring this function to be called in order to proceed, applications are given a chance to perform user interaction between steps in the %TLS process. */ void continueAfterStep(); /** test if the handshake is complete \return true if the handshake is complete \sa handshaken */ bool isHandshaken() const; /** test if the link is compressed \return true if the link is compressed */ bool isCompressed() const; /** The protocol version that is in use for this connection. */ Version version() const; /** The cipher suite that has been negotiated for this connection. The name returned here is the name used in the applicable RFC (or Internet Draft, where there is no RFC). */ QString cipherSuite() const; /** The number of effective bits of security being used for this connection. This can differ from the actual number of bits in the cipher for certain older "export ciphers" that are deliberately crippled. If you want that information, use cipherMaxBits(). */ int cipherBits() const; /** The number of bits of security that the cipher could use. This is normally the same as cipherBits(), but can be greater for older "export ciphers". */ int cipherMaxBits() const; /** The session object of the %TLS connection, which can be used for resuming. */ TLSSession session() const; /** This method returns the type of error that has occurred. You should only need to check this if the error() signal is emitted. */ Error errorCode() const; /** After the SSL/%TLS handshake is complete, this method allows you to determine if the other end of the connection (if the application is a client, this is the server; if the application is a server, this is the client) has a valid identity. Note that the security of %TLS/SSL depends on checking this. It is not enough to check that the certificate is valid - you must check that the certificate is valid for the entity that you are trying to communicate with. \note If this returns QCA::TLS::InvalidCertificate, you may wish to use peerCertificateValidity() to determine whether to proceed or not. */ IdentityResult peerIdentityResult() const; /** After the SSL/%TLS handshake is valid, this method allows you to check if the received certificate from the other end is valid. As noted in peerIdentityResult(), you also need to check that the certificate matches the entity you are trying to communicate with. */ Validity peerCertificateValidity() const; /** The CertificateChain for the local host certificate. */ CertificateChain localCertificateChain() const; /** The PrivateKey for the local host certificate. */ PrivateKey localPrivateKey() const; /** The CertificateChain from the peer (other end of the connection to the trusted root certificate). */ CertificateChain peerCertificateChain() const; // reimplemented virtual bool isClosable() const; virtual int bytesAvailable() const; virtual int bytesOutgoingAvailable() const; virtual void close(); virtual void write(const QByteArray &a); virtual QByteArray read(); virtual void writeIncoming(const QByteArray &a); virtual QByteArray readOutgoing(int *plainBytes = 0); virtual QByteArray readUnprocessed(); virtual int convertBytesWritten(qint64 encryptedBytes); /** Determine the number of packets available to be read on the application side. \note this is only used with DTLS. */ int packetsAvailable() const; /** Determine the number of packets available to be read on the network side. \note this is only used with DTLS. */ int packetsOutgoingAvailable() const; /** Return the currently configured maximum packet size \note this is only used with DTLS */ int packetMTU() const; /** Set the maximum packet size to use. \param size the number of bytes to set as the MTU. \note this is only used with DTLS. */ void setPacketMTU(int size) const; Q_SIGNALS: /** Emitted if a host name is set by the client. At this time, the server can inspect the hostName(). You must call continueAfterStep() in order for %TLS processing to resume after this signal is emitted. This signal is only emitted in server mode. \sa continueAfterStep */ void hostNameReceived(); /** Emitted when the server requests a certificate. At this time, the client can inspect the issuerList(). You must call continueAfterStep() in order for %TLS processing to resume after this signal is emitted. This signal is only emitted in client mode. \sa continueAfterStep */ void certificateRequested(); /** Emitted when a certificate is received from the peer. At this time, you may inspect peerIdentityResult(), peerCertificateValidity(), and peerCertificateChain(). You must call continueAfterStep() in order for %TLS processing to resume after this signal is emitted. \sa continueAfterStep */ void peerCertificateAvailable(); /** Emitted when the protocol handshake is complete. At this time, all available information about the %TLS session can be inspected. You must call continueAfterStep() in order for %TLS processing to resume after this signal is emitted. \sa continueAfterStep \sa isHandshaken */ void handshaken(); protected: /** Called when a connection is made to a particular signal \param signal the name of the signal that has been connected to. */ void connectNotify(const char *signal); /** Called when a connection is removed from a particular signal \param signal the name of the signal that has been disconnected from. */ void disconnectNotify(const char *signal); private: Q_DISABLE_COPY(TLS) class Private; friend class Private; Private *d; }; /** \class SASL qca_securelayer.h QtCrypto Simple Authentication and Security Layer protocol implementation This class implements the Simple Authenication and Security Layer protocol, which is described in RFC2222 - see http://www.ietf.org/rfc/rfc2222.txt. As the name suggests, %SASL provides authentication (eg, a "login" of some form), for a connection oriented protocol, and can also provide protection for the subsequent connection. The %SASL protocol is designed to be extensible, through a range of "mechanisms", where a mechanism is the actual authentication method. Example mechanisms include Anonymous, LOGIN, Kerberos V4, and GSSAPI. Mechanisms can be added (potentially without restarting the server application) by the system administrator. It is important to understand that %SASL is neither "network aware" nor "protocol aware". That means that %SASL does not understand how the client connects to the server, and %SASL does not understand the actual application protocol. \ingroup UserAPI */ class QCA_EXPORT SASL : public SecureLayer, public Algorithm { Q_OBJECT public: /** Possible errors that may occur when using %SASL */ enum Error { ErrorInit, ///< problem starting up %SASL ErrorHandshake, ///< problem during the authentication process ErrorCrypt ///< problem at anytime after }; /** Possible authentication error states */ enum AuthCondition { AuthFail, ///< Generic authentication failure NoMechanism, ///< No compatible/appropriate authentication mechanism BadProtocol, ///< Bad protocol or cancelled BadServer, ///< Server failed mutual authentication (client side only) BadAuth, ///< Authentication failure (server side only) NoAuthzid, ///< Authorization failure (server side only) TooWeak, ///< Mechanism too weak for this user (server side only) NeedEncrypt, ///< Encryption is needed in order to use mechanism (server side only) Expired, ///< Passphrase expired, has to be reset (server side only) Disabled, ///< Account is disabled (server side only) NoUser, ///< User not found (server side only) RemoteUnavailable ///< Remote service needed for auth is gone (server side only) }; /** Authentication requirement flag values */ enum AuthFlags { AuthFlagsNone = 0x00, AllowPlain = 0x01, AllowAnonymous = 0x02, RequireForwardSecrecy = 0x04, RequirePassCredentials = 0x08, RequireMutualAuth = 0x10, RequireAuthzidSupport = 0x20 // server-only }; /** Mode options for client side sending */ enum ClientSendMode { AllowClientSendFirst, DisableClientSendFirst }; /** Mode options for server side sending */ enum ServerSendMode { AllowServerSendLast, DisableServerSendLast }; /** \class Params qca_securelayer.h QtCrypto Parameter flags for the %SASL authentication This is used to indicate which parameters are needed by %SASL in order to complete the authentication process. \ingroup UserAPI */ class QCA_EXPORT Params { public: Params(); /** Standard constructor. The concept behind this is that you set each of the flags depending on which parameters are needed. \param user the username is required \param authzid the authorization identity is required \param pass the password is required \param realm the realm is required */ Params(bool user, bool authzid, bool pass, bool realm); /** Standard copy constructor \param from the Params object to copy */ Params(const Params &from); ~Params(); /** Standard assignment operator \param from the Params object to assign from */ Params & operator=(const Params &from); /** User is needed */ bool needUsername() const; /** An Authorization ID can be sent if desired */ bool canSendAuthzid() const; /** Password is needed */ bool needPassword() const; /** A Realm can be sent if desired */ bool canSendRealm() const; private: class Private; Private *d; }; /** Standard constructor \param parent the parent object for this %SASL connection \param provider if specified, the provider to use. If not specified, or specified as empty, then any provider is acceptable. */ explicit SASL(QObject *parent = 0, const QString &provider = QString()); ~SASL(); /** Reset the %SASL mechanism */ void reset(); /** Specify connection constraints %SASL supports a range of authentication requirements, and a range of security levels. This method allows you to specify the requirements for your connection. \param f the authentication requirements, which you typically build using a binary OR function (eg AllowPlain | AllowAnonymous) \param s the security level of the encryption, if used. See SecurityLevel for details of what each level provides. */ void setConstraints(AuthFlags f, SecurityLevel s = SL_None); /** \overload Unless you have a specific reason for directly specifying a strength factor, you probably should use the method above. \param f the authentication requirements, which you typically build using a binary OR function (eg AllowPlain | AllowAnonymous) \param minSSF the minimum security strength factor that is required \param maxSSF the maximum security strength factor that is required \note Security strength factors are a rough approximation to key length in the encryption function (eg if you are securing with plain DES, the security strength factor would be 56). */ void setConstraints(AuthFlags f, int minSSF, int maxSSF); /** Specify the local address. \param addr the address of the local part of the connection \param port the port number of the local part of the connection */ void setLocalAddress(const QString &addr, quint16 port); /** Specify the peer address. \param addr the address of the peer side of the connection \param port the port number of the peer side of the connection */ void setRemoteAddress(const QString &addr, quint16 port); /** Specify the id of the externally secured connection \param authid the id of the connection */ void setExternalAuthId(const QString &authid); /** Specify a security strength factor for an externally secured connection \param strength the security strength factor of the connection */ void setExternalSSF(int strength); /** Initialise the client side of the connection startClient must be called on the client side of the connection. clientStarted will be emitted when the operation is completed. \param service the name of the service \param host the client side host name \param mechlist the list of mechanisms which can be used \param mode the mode to use on the client side */ void startClient(const QString &service, const QString &host, const QStringList &mechlist, ClientSendMode mode = AllowClientSendFirst); /** Initialise the server side of the connection startServer must be called on the server side of the connection. serverStarted will be emitted when the operation is completed. \param service the name of the service \param host the server side host name \param realm the realm to use \param mode which mode to use on the server side */ void startServer(const QString &service, const QString &host, const QString &realm, ServerSendMode mode = DisableServerSendLast); /** Process the first step in server mode (server) Call this with the mechanism selected by the client. If there is initial client data, call the other version of this function instead. \param mech the mechanism to be used. */ void putServerFirstStep(const QString &mech); /** Process the first step in server mode (server) Call this with the mechanism selected by the client, and initial client data. If there is no initial client data, call the other version of this function instead. \param mech the mechanism to be used \param clientInit the initial data provided by the client side */ void putServerFirstStep(const QString &mech, const QByteArray &clientInit); /** Process an authentication step Call this with authentication data received from the network. The only exception is the first step in server mode, in which case putServerFirstStep must be called. \param stepData the authentication data from the network */ void putStep(const QByteArray &stepData); /** Return the mechanism selected (client) */ QString mechanism() const; /** Return the mechanism list (server) */ QStringList mechanismList() const; /** Return the realm list, if available (client) */ QStringList realmList() const; /** Return the security strength factor of the connection */ int ssf() const; /** Return the error code */ Error errorCode() const; /** Return the reason for authentication failure */ AuthCondition authCondition() const; /** Specify the username to use in authentication \param user the username to use */ void setUsername(const QString &user); /** Specify the authorization identity to use in authentication \param auth the authorization identity to use */ void setAuthzid(const QString &auth); /** Specify the password to use in authentication \param pass the password to use */ void setPassword(const SecureArray &pass); /** Specify the realm to use in authentication \param realm the realm to use */ void setRealm(const QString &realm); /** Continue negotiation after parameters have been set (client) */ void continueAfterParams(); /** Continue negotiation after auth ids have been checked (server) */ void continueAfterAuthCheck(); // reimplemented virtual int bytesAvailable() const; virtual int bytesOutgoingAvailable() const; virtual void write(const QByteArray &a); virtual QByteArray read(); virtual void writeIncoming(const QByteArray &a); virtual QByteArray readOutgoing(int *plainBytes = 0); virtual int convertBytesWritten(qint64 encryptedBytes); Q_SIGNALS: /** This signal is emitted when the client has been successfully started \param clientInit true if the client should send an initial response to the server \param clientInitData the initial response to send to the server. Do note that there is a difference in SASL between an empty initial response and no initial response, and so even if clientInitData is an empty array, you still need to send an initial response if clientInit is true. */ void clientStarted(bool clientInit, const QByteArray &clientInitData); /** This signal is emitted after the server has been successfully started */ void serverStarted(); /** This signal is emitted when there is data required to be sent over the network to complete the next step in the authentication process. \param stepData the data to send over the network */ void nextStep(const QByteArray &stepData); /** This signal is emitted when the client needs additional parameters After receiving this signal, the application should set the required parameter values appropriately and then call continueAfterParams(). \param params the parameters that are required by the client */ void needParams(const QCA::SASL::Params ¶ms); /** This signal is emitted when the server needs to perform the authentication check If the user and authzid are valid, call continueAfterAuthCheck(). \param user the user identification name \param authzid the user authorization name */ void authCheck(const QString &user, const QString &authzid); /** This signal is emitted when authentication is complete. */ void authenticated(); private: Q_DISABLE_COPY(SASL) class Private; friend class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca/include/QtCrypto/qca_cert.h0000644000175000017500000021456011305557613021272 0ustar janjan/* * qca_cert.h - Qt Cryptographic Architecture * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2004-2006 Brad Hards * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ /** \file qca_cert.h Header file for PGP key and X.509 certificate related classes \note You should not use this header directly from an application. You should just use \#include \ instead. */ #ifndef QCA_CERT_H #define QCA_CERT_H #include #include #include "qca_core.h" #include "qca_publickey.h" namespace QCA { class CertContext; class CSRContext; class CRLContext; class Certificate; class CRL; class CertificateCollection; class CertificateChain; /** Certificate Request Format */ enum CertificateRequestFormat { PKCS10, ///< standard PKCS#10 format SPKAC ///< Signed Public Key and Challenge (Netscape) format }; /** Known types of information stored in certificates This enumerator offers a convenient way to work with common types. */ enum CertificateInfoTypeKnown { CommonName, ///< The common name (eg person), id = "2.5.4.3" Email, ///< Email address, id = "GeneralName.rfc822Name" EmailLegacy, ///< PKCS#9 Email field, id = "1.2.840.113549.1.9.1" Organization, ///< An organisation (eg company), id = "2.5.4.10" OrganizationalUnit, ///< An part of an organisation (eg a division or branch), id = "2.5.4.11" Locality, ///< The locality (eg city, a shire, or part of a state), id = "2.5.4.7" IncorporationLocality, ///< The locality of incorporation (EV certificates), id = "1.3.6.1.4.1.311.60.2.1.1" State, ///< The state within the country, id = "2.5.4.8" IncorporationState, ///< The state of incorporation (EV certificates), id = "1.3.6.1.4.1.311.60.2.1.2" Country, ///< The country, id = "2.5.4.6" IncorporationCountry, ///< The country of incorporation (EV certificates), id = "1.3.6.1.4.1.311.60.2.1.3" URI, ///< Uniform Resource Identifier, id = "GeneralName.uniformResourceIdentifier" DNS, ///< DNS name, id = "GeneralName.dNSName" IPAddress, ///< IP address, id = "GeneralName.iPAddress" XMPP ///< XMPP address (see http://www.ietf.org/rfc/rfc3920.txt), id = "1.3.6.1.5.5.7.8.5" }; /** \class CertificateInfoType qca_cert.h QtCrypto Certificate information type This class represents a type of information being stored in a certificate. It can be created either using a known type (from the Known enumerator) or an identifier string (usually an OID). Types created either way are interchangeable. Types also have the notion of a Section. Some types may reside in the Distinguished Name field of a certificate, and some types may reside in the Subject Alternative Name field. This class is capable of representing a type from either section. In the general case, applications will want to use the CertificateInfoTypeKnown enumerator types. These are from RFC3280 (http://www.ietf.org/rfc/rfc3280.txt) except where shown. The entries for IncorporationLocality, IncorporationState and IncorporationCountry are the same as Locality, State and Country respectively, except that the Extended Validation (EV) certificate guidelines (published by the %Certificate Authority / Browser Forum, see http://www.cabforum.org) distinguish between the place of where the company does business (which is the Locality / State / Country combination) and the jurisdiction where the company is legally incorporated (the IncorporationLocality / IncorporationState / IncorporationCountry combination). \sa Certificate::subjectInfo() and Certificate::issuerInfo() \sa CRL::issuerInfo() \ingroup UserAPI */ class QCA_EXPORT CertificateInfoType { public: /** Section of the certificate that the information belongs in */ enum Section { DN, ///< Distinguished name (the primary name) AlternativeName ///< Alternative name }; /** Standard constructor */ CertificateInfoType(); /** Construct a new type The section will be derived by \a known. \param known the type as part of the CertificateInfoTypeKnown enumerator */ CertificateInfoType(CertificateInfoTypeKnown known); /** Construct a new type \param id the type as an identifier string (OID or internal) \param section the section this type belongs in \sa id */ CertificateInfoType(const QString &id, Section section); /** Standard copy constructor \param from the certificate information to copy from */ CertificateInfoType(const CertificateInfoType &from); ~CertificateInfoType(); /** Standard assignment operator \param from the certificate information to assign from */ CertificateInfoType & operator=(const CertificateInfoType &from); /** The section the type is part of */ Section section() const; /** The type as part of the CertificateInfoTypeKnown enumerator This function may return a value that does not exist in the enumerator. In that case, you may use id() to determine the type. */ CertificateInfoTypeKnown known() const; /** The type as an identifier string For types that have OIDs, this function returns an OID in string form. For types that do not have OIDs, this function returns an internal identifier string whose first character is not a digit (this allows you to tell the difference between an OID and an internal identifier). It is hereby stated that General Names (of the X.509 Subject Alternative Name) shall use the internal identifier format "GeneralName.[rfc field name]". For example, the rfc822Name field would have the identifier "GeneralName.rfc822Name". Applications should not store, use, or compare against internal identifiers unless the identifiers are explicitly documented (e.g. GeneralName). */ QString id() const; /** Comparison operator \param other the certificate information to compare with this certificate information. */ bool operator<(const CertificateInfoType &other) const; /** Comparison operator \param other the certificate information to compare with this certificate information. */ bool operator==(const CertificateInfoType &other) const; /** Inequality operator \param other the certificate information to compare with this certificate information. */ inline bool operator!=(const CertificateInfoType &other) const { return !(*this == other); } private: class Private; QSharedDataPointer d; }; /** \class CertificateInfoPair qca_cert.h QtCrypto One entry in a certificate information list \ingroup UserAPI */ class QCA_EXPORT CertificateInfoPair { public: /** Standard constructor */ CertificateInfoPair(); /** Construct a new pair \param type the type of information stored in this pair \param value the value of the information to be stored */ CertificateInfoPair(const CertificateInfoType &type, const QString &value); /** Standard copy constructor \param from the information pair to copy from */ CertificateInfoPair(const CertificateInfoPair &from); ~CertificateInfoPair(); /** Standard assignment operator \param from the information pair to assign from */ CertificateInfoPair & operator=(const CertificateInfoPair &from); /** The type of information stored in the pair */ CertificateInfoType type() const; /** The value of the information stored in the pair */ QString value() const; /** Comparison operator \param other the certificate information pair to compare with this certificate information pair. */ bool operator==(const CertificateInfoPair &other) const; /** Inequality operator \param other the certificate information pair to compare with this certificate information pair. */ inline bool operator!=(const CertificateInfoPair &other) const { return !(*this == other); } private: class Private; QSharedDataPointer d; }; /** Known types of certificate constraints This enumerator offers a convenient way to work with common types. */ enum ConstraintTypeKnown { // KeyUsage DigitalSignature, ///< %Certificate can be used to create digital signatures, id = "KeyUsage.digitalSignature" NonRepudiation, ///< %Certificate can be used for non-repudiation, id = "KeyUsage.nonRepudiation" KeyEncipherment, ///< %Certificate can be used for encrypting / decrypting keys, id = "KeyUsage.keyEncipherment" DataEncipherment, ///< %Certificate can be used for encrypting / decrypting data, id = "KeyUsage.dataEncipherment" KeyAgreement, ///< %Certificate can be used for key agreement, id = "KeyUsage.keyAgreement" KeyCertificateSign, ///< %Certificate can be used for key certificate signing, id = "KeyUsage.keyCertSign" CRLSign, ///< %Certificate can be used to sign %Certificate Revocation Lists, id = "KeyUsage.crlSign" EncipherOnly, ///< %Certificate can only be used for encryption, id = "KeyUsage.encipherOnly" DecipherOnly, ///< %Certificate can only be used for decryption, id = "KeyUsage.decipherOnly" // ExtKeyUsage ServerAuth, ///< %Certificate can be used for server authentication (e.g. web server), id = "1.3.6.1.5.5.7.3.1". This is an extended usage constraint. ClientAuth, ///< %Certificate can be used for client authentication (e.g. web browser), id = "1.3.6.1.5.5.7.3.2". This is an extended usage constraint. CodeSigning, ///< %Certificate can be used to sign code, id = "1.3.6.1.5.5.7.3.3". This is an extended usage constraint. EmailProtection, ///< %Certificate can be used to sign / encrypt email, id = "1.3.6.1.5.5.7.3.4". This is an extended usage constraint. IPSecEndSystem, ///< %Certificate can be used to authenticate a endpoint in IPSEC, id = "1.3.6.1.5.5.7.3.5". This is an extended usage constraint. IPSecTunnel, ///< %Certificate can be used to authenticate a tunnel in IPSEC, id = "1.3.6.1.5.5.7.3.6". This is an extended usage constraint. IPSecUser, ///< %Certificate can be used to authenticate a user in IPSEC, id = "1.3.6.1.5.5.7.3.7". This is an extended usage constraint. TimeStamping, ///< %Certificate can be used to create a "time stamp" signature, id = "1.3.6.1.5.5.7.3.8". This is an extended usage constraint. OCSPSigning ///< %Certificate can be used to sign an Online %Certificate Status Protocol (OCSP) assertion, id = "1.3.6.1.5.5.7.3.9". This is an extended usage constraint. }; /** \class ConstraintType qca_cert.h QtCrypto Certificate constraint X.509 certificates can be constrained in their application - that is, some certificates can only be used for certain purposes. This class is used to identify an approved purpose for a certificate. \note It is common for a certificate to have more than one purpose. \ingroup UserAPI */ class QCA_EXPORT ConstraintType { public: /** Section of the certificate that the constraint belongs in */ enum Section { KeyUsage, ///< Stored in the key usage section ExtendedKeyUsage ///< Stored in the extended key usage section }; /** Standard constructor */ ConstraintType(); /** Construct a new constraint The section will be derived by \a known. \param known the type as part of the ConstraintTypeKnown enumerator */ ConstraintType(ConstraintTypeKnown known); /** Construct a new constraint \param id the type as an identifier string (OID or internal) \param section the section this type belongs in \sa id */ ConstraintType(const QString &id, Section section); /** Standard copy constructor \param from the constraint type to copy from */ ConstraintType(const ConstraintType &from); ~ConstraintType(); /** Standard assignment operator \param from the constraint type to assign from */ ConstraintType & operator=(const ConstraintType &from); /** The section the constraint is part of */ Section section() const; /** The type as part of the ConstraintTypeKnown enumerator This function may return a value that does not exist in the enumerator. In that case, you may use id() to determine the type. */ ConstraintTypeKnown known() const; /** The type as an identifier string For types that have OIDs, this function returns an OID in string form. For types that do not have OIDs, this function returns an internal identifier string whose first character is not a digit (this allows you to tell the difference between an OID and an internal identifier). It is hereby stated that the KeyUsage bit fields shall use the internal identifier format "KeyUsage.[rfc field name]". For example, the keyEncipherment field would have the identifier "KeyUsage.keyEncipherment". Applications should not store, use, or compare against internal identifiers unless the identifiers are explicitly documented (e.g. KeyUsage). */ QString id() const; /** Comparison operator \param other the constraint type to compare with this constraint */ bool operator<(const ConstraintType &other) const; /** Comparison operator \param other the constraint type to compare with this constraint */ bool operator==(const ConstraintType &other) const; /** Inequality operator \param other the constraint type to compare with this constraint */ inline bool operator!=(const ConstraintType &other) const { return !(*this == other); } private: class Private; QSharedDataPointer d; }; /** Specify the intended usage of a certificate */ enum UsageMode { UsageAny = 0x00, ///< Any application, or unspecified UsageTLSServer = 0x01, ///< server side of a TLS or SSL connection UsageTLSClient = 0x02, ///< client side of a TLS or SSL connection UsageCodeSigning = 0x04, ///< code signing certificate UsageEmailProtection = 0x08, ///< email (S/MIME) certificate UsageTimeStamping = 0x10, ///< time stamping certificate UsageCRLSigning = 0x20 ///< certificate revocation list signing certificate }; /** The validity (or otherwise) of a certificate */ enum Validity { ValidityGood, ///< The certificate is valid ErrorRejected, ///< The root CA rejected the certificate purpose ErrorUntrusted, ///< The certificate is not trusted ErrorSignatureFailed, ///< The signature does not match ErrorInvalidCA, ///< The Certificate Authority is invalid ErrorInvalidPurpose, ///< The purpose does not match the intended usage ErrorSelfSigned, ///< The certificate is self-signed, and is not found in the list of trusted certificates ErrorRevoked, ///< The certificate has been revoked ErrorPathLengthExceeded, ///< The path length from the root CA to this certificate is too long ErrorExpired, ///< The certificate has expired, or is not yet valid (e.g. current time is earlier than notBefore time) ErrorExpiredCA, ///< The Certificate Authority has expired ErrorValidityUnknown = 64 ///< Validity is unknown }; /** The conditions to validate for a certificate */ enum ValidateFlags { ValidateAll = 0x00, // Verify all conditions ValidateRevoked = 0x01, // Verify the certificate was not revoked ValidateExpired = 0x02, // Verify the certificate has not expired ValidatePolicy = 0x04 // Verify the certificate can be used for a specified purpose }; /** Certificate properties type With this container, the information is not necessarily stored in the same sequence as the certificate format itself. Use this container if the order the information is/was stored does not matter for you (this is the case with most applications). Additionally, the EmailLegacy type should not be used with this container. Use Email instead. */ typedef QMultiMap CertificateInfo; /** \class CertificateInfoOrdered qca_cert.h QtCrypto Ordered certificate properties type This container stores the information in the same sequence as the certificate format itself. \ingroup UserAPI */ class CertificateInfoOrdered : public QList { public: /** Convert to RFC 1779 string format */ inline QString toString() const; /** Return a new CertificateInfoOrdered that only contains the Distinguished Name (DN) types found in this object. */ inline CertificateInfoOrdered dnOnly() const; }; /** Convert to RFC 1779 string format \param in the certificate info to convert */ QCA_EXPORT QString orderedToDNString(const CertificateInfoOrdered &in); /** Return a new CertificateInfoOrdered that only contains the Distinguished Name (DN) types found in the input object. \param in the certificate info to extract from */ QCA_EXPORT CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in); inline QString CertificateInfoOrdered::toString() const { return orderedToDNString(*this); } inline CertificateInfoOrdered CertificateInfoOrdered::dnOnly() const { return orderedDNOnly(*this); } /** %Certificate constraints type */ typedef QList Constraints; /** Create a list of unique friendly names among a list of certificates \param list the list of certificates for which a friendly name is required. */ QCA_EXPORT QStringList makeFriendlyNames(const QList &list); /** \class CertificateOptions qca_cert.h QtCrypto %Certificate options \note In SPKAC mode, all options are ignored except for challenge \ingroup UserAPI */ class QCA_EXPORT CertificateOptions { public: /** Create a Certificate options set \param format the format to create the certificate request in */ CertificateOptions(CertificateRequestFormat format = PKCS10); /** Standard copy constructor \param from the Certificate Options to copy into this object */ CertificateOptions(const CertificateOptions &from); ~CertificateOptions(); /** Standard assignment operator \param from the Certificate Options to copy into this object */ CertificateOptions & operator=(const CertificateOptions &from); /** test the format type for this certificate */ CertificateRequestFormat format() const; /** Specify the format for this certificate \param f the format to use */ void setFormat(CertificateRequestFormat f); /** Test if the certificate options object is valid \return true if the certificate options object is valid */ bool isValid() const; /** The challenge part of the certificate For CertificateRequest only \sa setChallenge */ QString challenge() const; /** Information on the subject of the certificate \sa setInfo */ CertificateInfo info() const; /** Information on the subject of the certificate, in the exact order the items will be written \sa setInfoOrdered */ CertificateInfoOrdered infoOrdered() const; /** List the constraints on this certificate */ Constraints constraints() const; /** list the policies on this certificate */ QStringList policies() const; /** list of URI locations for CRL files each URI refers to the same CRL file For Certificate creation only */ QStringList crlLocations() const; /** list of URI locations for issuer certificate files each URI refers to the same issuer file For Certificate creation only */ QStringList issuerLocations() const; /** list of URI locations for OCSP services For Certificate creation only */ QStringList ocspLocations() const; /** test if the certificate is a CA cert \sa setAsCA \sa setAsUser */ bool isCA() const; /** return the path limit on this certificate */ int pathLimit() const; /** The serial number for the certificate For Certificate creation only */ BigInteger serialNumber() const; /** the first time the certificate will be valid For Certificate creation only */ QDateTime notValidBefore() const; /** the last time the certificate is valid For Certificate creation only */ QDateTime notValidAfter() const; /** Specify the challenge associated with this certificate \param s the challenge string \sa challenge() */ void setChallenge(const QString &s); /** Specify information for the the subject associated with the certificate \param info the information for the subject \sa info() */ void setInfo(const CertificateInfo &info); /** Specify information for the the subject associated with the certificate \param info the information for the subject \sa info() */ void setInfoOrdered(const CertificateInfoOrdered &info); /** set the constraints on the certificate \param constraints the constraints to be used for the certificate */ void setConstraints(const Constraints &constraints); /** set the policies on the certificate \param policies the policies to be used for the certificate */ void setPolicies(const QStringList &policies); /** set the CRL locations of the certificate each location refers to the same CRL. \param locations a list of URIs to CRL files */ void setCRLLocations(const QStringList &locations); /** set the issuer certificate locations of the certificate each location refers to the same issuer file. \param locations a list of URIs to issuer certificate files */ void setIssuerLocations(const QStringList &locations); /** set the OCSP service locations of the certificate \param locations a list of URIs to OCSP services */ void setOCSPLocations(const QStringList &locations); /** set the certificate to be a CA cert \param pathLimit the number of intermediate certificates allowable */ void setAsCA(int pathLimit = 8); // value from Botan /** set the certificate to be a user cert (this is the default) */ void setAsUser(); /** Set the serial number property on this certificate \param i the serial number to use */ void setSerialNumber(const BigInteger &i); /** Set the validity period for the certificate \param start the first time this certificate becomes valid \param end the last time this certificate is valid */ void setValidityPeriod(const QDateTime &start, const QDateTime &end); private: class Private; Private *d; }; /** \class Certificate qca_cert.h QtCrypto Public Key (X.509) certificate This class contains one X.509 certificate \ingroup UserAPI */ class QCA_EXPORT Certificate : public Algorithm { public: /** Create an empty Certificate */ Certificate(); /** Create a Certificate from a PEM encoded file \param fileName the name (and path, if required) of the file that contains the PEM encoded certificate */ Certificate(const QString &fileName); /** Create a Certificate with specified options and a specified private key \param opts the options to use \param key the private key for this certificate \param provider the provider to use to create this key, if a particular provider is required */ Certificate(const CertificateOptions &opts, const PrivateKey &key, const QString &provider = QString()); /** Standard copy constructor \param from the certificate to copy from */ Certificate(const Certificate &from); ~Certificate(); /** Standard assignment operator \param from the Certificate to assign from */ Certificate & operator=(const Certificate &from); /** Test if the certificate is empty (null) \return true if the certificate is null */ bool isNull() const; /** The earliest date that the certificate is valid */ QDateTime notValidBefore() const; /** The latest date that the certificate is valid */ QDateTime notValidAfter() const; /** Properties of the subject of the certificate, as a QMultiMap This is the method that provides information on the subject organisation, common name, DNS name, and so on. The list of information types (i.e. the key to the multi-map) is a CertificateInfoType. The values are a list of QString. An example of how you can iterate over the list is: \code foreach( QString dns, info.values(QCA::DNS) ) { std::cout << " " << qPrintable(dns) << std::endl; } \endcode */ CertificateInfo subjectInfo() const; /** Properties of the subject of the certificate, as an ordered list (QList of CertificateInfoPair). This allows access to the certificate information in the same order as they appear in a certificate. Each pair in the list has a type and a value. For example: \code CertificateInfoOrdered info = cert.subjectInfoOrdered(); // info[0].type == CommonName // info[0].value == "example.com" \endcode \sa subjectInfo for an unordered version \sa issuerInfoOrdered for the ordered information on the issuer \sa CertificateInfoPair for the elements in the list */ CertificateInfoOrdered subjectInfoOrdered() const; /** Properties of the issuer of the certificate \sa subjectInfo for how the return value works. */ CertificateInfo issuerInfo() const; /** Properties of the issuer of the certificate, as an ordered list (QList of CertificateInfoPair). This allows access to the certificate information in the same order as they appear in a certificate. Each pair in the list has a type and a value. \sa issuerInfo for an unordered version \sa subjectInfoOrdered for the ordered information on the subject \sa CertificateInfoPair for the elements in the list */ CertificateInfoOrdered issuerInfoOrdered() const; /** The constraints that apply to this certificate */ Constraints constraints() const; /** The policies that apply to this certificate Policies are specified as strings containing OIDs */ QStringList policies() const; /** List of URI locations for CRL files Each URI refers to the same CRL file */ QStringList crlLocations() const; /** List of URI locations for issuer certificate files Each URI refers to the same issuer file */ QStringList issuerLocations() const; /** List of URI locations for OCSP services */ QStringList ocspLocations() const; /** The common name of the subject of the certificate Common names are normally the name of a person, company or organisation */ QString commonName() const; /** The serial number of the certificate */ BigInteger serialNumber() const; /** The public key associated with the subject of the certificate */ PublicKey subjectPublicKey() const; /** Test if the Certificate is valid as a Certificate Authority \return true if the Certificate is valid as a Certificate Authority */ bool isCA() const; /** Test if the Certificate is self-signed \return true if the certificate is self-signed */ bool isSelfSigned() const; /** Test if the Certificate has signed another Certificate object and is therefore the issuer \param other the certificate to test \return true if this certificate is the issuer of the argument */ bool isIssuerOf(const Certificate &other) const; /** The upper bound of the number of links in the certificate chain, if any */ int pathLimit() const; /** The signature algorithm used for the signature on this certificate */ SignatureAlgorithm signatureAlgorithm() const; /** The key identifier associated with the subject */ QByteArray subjectKeyId() const; /** The key identifier associated with the issuer */ QByteArray issuerKeyId() const; /** Check the validity of a certificate \param trusted a collection of trusted certificates \param untrusted a collection of additional certificates, not necessarily trusted \param u the use required for the certificate \param vf the conditions to validate \note This function may block */ Validity validate(const CertificateCollection &trusted, const CertificateCollection &untrusted, UsageMode u = UsageAny, ValidateFlags vf = ValidateAll) const; /** Export the Certificate into a DER format */ QByteArray toDER() const; /** Export the Certificate into a PEM format */ QString toPEM() const; /** Export the Certificate into PEM format in a file \param fileName the name of the file to use */ bool toPEMFile(const QString &fileName) const; /** Import the certificate from DER \param a the array containing the certificate in DER format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the Certificate corresponding to the certificate in the provided array */ static Certificate fromDER(const QByteArray &a, ConvertResult *result = 0, const QString &provider = QString()); /** Import the certificate from PEM format \param s the string containing the certificate in PEM format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the Certificate corresponding to the certificate in the provided string */ static Certificate fromPEM(const QString &s, ConvertResult *result = 0, const QString &provider = QString()); /** Import the certificate from a file \param fileName the name (and path, if required) of the file containing the certificate in PEM format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the Certificate corresponding to the certificate in the provided string */ static Certificate fromPEMFile(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); /** Test if the subject of the certificate matches a specified host name This will return true (indicating a match), if the specified host name meets the RFC 2818 validation rules with this certificate. If the host is an internationalized domain name, then it must be provided in unicode format, not in IDNA ACE/punycode format. \param host the name of the host to compare to */ bool matchesHostName(const QString &host) const; /** Test for equality of two certificates \param a the certificate to compare this certificate with \return true if the two certificates are the same */ bool operator==(const Certificate &a) const; /** Inequality operator \param other the certificate to compare this certificate with */ inline bool operator!=(const Certificate &other) const { return !(*this == other); } /** \internal \param c context (internal) */ void change(CertContext *c); private: class Private; friend class Private; QSharedDataPointer d; friend class CertificateChain; Validity chain_validate(const CertificateChain &chain, const CertificateCollection &trusted, const QList &untrusted_crls, UsageMode u, ValidateFlags vf) const; CertificateChain chain_complete(const CertificateChain &chain, const QList &issuers, Validity *result) const; }; /** \class CertificateChain qca_cert.h QtCrypto A chain of related Certificates CertificateChain is a list (a QList) of certificates that are related by the signature from one to another. If Certificate C signs Certificate B, and Certificate B signs Certificate A, then C, B and A form a chain. The normal use of a CertificateChain is from a end-user Certificate (called the primary, equivalent to QList::first()) through some intermediate Certificates to some other Certificate (QList::last()), which might be a root Certificate Authority, but does not need to be. You can build up the chain using normal QList operations, such as QList::append(). \sa QCA::CertificateCollection for an alternative way to represent a group of Certificates that do not necessarily have a chained relationship. \ingroup UserAPI */ class CertificateChain : public QList { public: /** Create an empty certificate chain */ inline CertificateChain() {} /** Create a certificate chain, starting at the specified certificate \param primary the end-user certificate that forms one end of the chain */ inline CertificateChain(const Certificate &primary) { append(primary); } /** Return the primary (end-user) Certificate */ inline const Certificate & primary() const { return first(); } /** Check the validity of a certificate chain \param trusted a collection of trusted certificates \param untrusted_crls a list of additional CRLs, not necessarily trusted \param u the use required for the primary certificate \param vf the conditions to validate \note This function may block \sa Certificate::validate() */ inline Validity validate(const CertificateCollection &trusted, const QList &untrusted_crls = QList(), UsageMode u = UsageAny, ValidateFlags vf = ValidateAll) const; /** Complete a certificate chain for the primary certificate, using the rest of the certificates in the chain object, as well as those in \a issuers, as possible issuers in the chain. If there are issuers missing, then the chain might be incomplete (at the worst case, if no issuers exist for the primary certificate, then the resulting chain will consist of just the primary certificate). Use the \a result argument to find out if there was a problem during completion. A result of ValidityGood means the chain was completed successfully. The newly constructed CertificateChain is returned. If the certificate chain is empty, then this will return an empty CertificateChain object. \param issuers a pool of issuers to draw from as necessary \param result the result of the completion operation \note This function may block \sa validate */ inline CertificateChain complete(const QList &issuers = QList(), Validity *result = 0) const; }; inline Validity CertificateChain::validate(const CertificateCollection &trusted, const QList &untrusted_crls, UsageMode u, ValidateFlags vf) const { if(isEmpty()) return ErrorValidityUnknown; return first().chain_validate(*this, trusted, untrusted_crls, u, vf); } inline CertificateChain CertificateChain::complete(const QList &issuers, Validity *result) const { if(isEmpty()) return CertificateChain(); return first().chain_complete(*this, issuers, result); } /** \class CertificateRequest qca_cert.h QtCrypto %Certificate Request A CertificateRequest is a unsigned request for a Certificate \ingroup UserAPI */ class QCA_EXPORT CertificateRequest : public Algorithm { public: /** Create an empty certificate request */ CertificateRequest(); /** Create a certificate request based on the contents of a file \param fileName the file (and path, if necessary) containing a PEM encoded certificate request */ CertificateRequest(const QString &fileName); /** Create a certificate request based on specified options \param opts the options to use in the certificate request \param key the private key that matches the certificate being requested \param provider the provider to use, if a specific provider is required */ CertificateRequest(const CertificateOptions &opts, const PrivateKey &key, const QString &provider = QString()); /** Standard copy constructor \param from the request to copy from */ CertificateRequest(const CertificateRequest &from); ~CertificateRequest(); /** Standard assignment operator \param from the request to assign from */ CertificateRequest & operator=(const CertificateRequest &from); /** test if the certificate request is empty \return true if the certificate request is empty, otherwise false */ bool isNull() const; /** Test if the certificate request can use a specified format \param f the format to test for \param provider the provider to use, if a specific provider is required \return true if the certificate request can use the specified format */ static bool canUseFormat(CertificateRequestFormat f, const QString &provider = QString()); /** the format that this Certificate request is in */ CertificateRequestFormat format() const; /** Information on the subject of the certificate being requested \note this only applies to PKCS#10 format certificate requests \sa subjectInfoOrdered for a version that maintains order in the subject information. */ CertificateInfo subjectInfo() const; /** Information on the subject of the certificate being requested, as an ordered list (QList of CertificateInfoPair). \note this only applies to PKCS#10 format certificate requests \sa subjectInfo for a version that does not maintain order, but allows access based on a multimap. \sa CertificateInfoPair for the elements in the list */ CertificateInfoOrdered subjectInfoOrdered() const; /** The constraints that apply to this certificate request \note this only applies to PKCS#10 format certificate requests */ Constraints constraints() const; /** The policies that apply to this certificate request \note this only applies to PKCS#10 format certificate requests */ QStringList policies() const; /** The public key belonging to the issuer */ PublicKey subjectPublicKey() const; /** Test if this Certificate Request is for a Certificate Authority certificate \note this only applies to PKCS#10 format certificate requests */ bool isCA() const; /** The path limit for the certificate in this Certificate Request \note this only applies to PKCS#10 format certificate requests */ int pathLimit() const; /** The challenge associated with this certificate request */ QString challenge() const; /** The algorithm used to make the signature on this certificate request */ SignatureAlgorithm signatureAlgorithm() const; /** Test for equality of two certificate requests \param csr the certificate request to be compared to this certificate request \return true if the two certificate requests are the same */ bool operator==(const CertificateRequest &csr) const; /** Inequality operator \param other the certificate request to be compared to this certificate request */ inline bool operator!=(const CertificateRequest &other) const { return !(*this == other); } /** Export the Certificate Request into a DER format \note this only applies to PKCS#10 format certificate requests */ QByteArray toDER() const; /** Export the Certificate Request into a PEM format \note this only applies to PKCS#10 format certificate requests */ QString toPEM() const; /** Export the Certificate into PEM format in a file \param fileName the name of the file to use \note this only applies to PKCS#10 format certificate requests */ bool toPEMFile(const QString &fileName) const; /** Import the certificate request from DER \param a the array containing the certificate request in DER format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CertificateRequest corresponding to the certificate request in the provided array \note this only applies to PKCS#10 format certificate requests */ static CertificateRequest fromDER(const QByteArray &a, ConvertResult *result = 0, const QString &provider = QString()); /** Import the certificate request from PEM format \param s the string containing the certificate request in PEM format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CertificateRequest corresponding to the certificate request in the provided string \note this only applies to PKCS#10 format certificate requests */ static CertificateRequest fromPEM(const QString &s, ConvertResult *result = 0, const QString &provider = QString()); /** Import the certificate request from a file \param fileName the name (and path, if required) of the file containing the certificate request in PEM format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CertificateRequest corresponding to the certificate request in the provided string \note this only applies to PKCS#10 format certificate requests */ static CertificateRequest fromPEMFile(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); /** Export the CertificateRequest to a string \return the string corresponding to the certificate request \note this only applies to SPKAC format certificate requests */ QString toString() const; /** Import the CertificateRequest from a string \param s the string containing to the certificate request \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CertificateRequest corresponding to the certificate request in the provided string \note this only applies to SPKAC format certificate requests */ static CertificateRequest fromString(const QString &s, ConvertResult *result = 0, const QString &provider = QString()); /** \internal \param c context (internal) */ void change(CSRContext *c); private: class Private; friend class Private; QSharedDataPointer d; }; /** \class CRLEntry qca_cert.h QtCrypto Part of a CRL representing a single certificate \ingroup UserAPI */ class QCA_EXPORT CRLEntry { public: /** The reason why the certificate has been revoked */ enum Reason { Unspecified, ///< reason is unknown KeyCompromise, ///< private key has been compromised CACompromise, ///< certificate authority has been compromised AffiliationChanged, Superseded, ///< certificate has been superseded CessationOfOperation, CertificateHold, ///< certificate is on hold RemoveFromCRL, ///< certificate was previously in a CRL, but is now valid PrivilegeWithdrawn, AACompromise ///< attribute authority has been compromised }; /** create an empty CRL entry */ CRLEntry(); /** create a CRL entry \param c the certificate to revoke \param r the reason that the certificate is being revoked */ explicit CRLEntry(const Certificate &c, Reason r = Unspecified); /** create a CRL entry \param serial the serial number of the Certificate being revoked \param time the time the Certificate was revoked (or will be revoked) \param r the reason that the certificate is being revoked */ CRLEntry(const BigInteger serial, const QDateTime &time, Reason r = Unspecified); /** Copy constructor \param from the CRLEntry to copy from */ CRLEntry(const CRLEntry &from); ~CRLEntry(); /** Standard assignment operator \param from the CRLEntry to copy from */ CRLEntry & operator=(const CRLEntry &from); /** The serial number of the certificate that is the subject of this CRL entry */ BigInteger serialNumber() const; /** The time this CRL entry was created */ QDateTime time() const; /** Test if this CRL entry is empty */ bool isNull() const; /** The reason that this CRL entry was created Alternatively, you might like to think of this as the reason that the subject certificate has been revoked */ Reason reason() const; /** Test if one CRL entry is "less than" another CRL entries are compared based on their serial number \param a the CRL entry to be compared to this CRL entry. */ bool operator<(const CRLEntry &a) const; /** Test for equality of two CRL Entries \param a the CRL entry to be compared to this CRL entry. \return true if the two certificates are the same */ bool operator==(const CRLEntry &a) const; /** Inequality operator \param other the CRL entry to be compared to this CRL entry. */ inline bool operator!=(const CRLEntry &other) const { return !(*this == other); } private: BigInteger _serial; QDateTime _time; Reason _reason; class Private; Private *d; }; /** \class CRL qca_cert.h QtCrypto %Certificate Revocation List A %CRL is a list of certificates that are special in some way. The normal reason for including a certificate on a %CRL is that the certificate should no longer be used. For example, if a key is compromised, then the associated certificate may no longer provides appropriate security. There are other reasons why a certificate may be placed on a %CRL, as shown in the CRLEntry::Reason enumeration. \sa CertificateCollection for a way to handle Certificates and CRLs as a single entity. \sa CRLEntry for the %CRL segment representing a single Certificate. \ingroup UserAPI */ class QCA_EXPORT CRL : public Algorithm { public: CRL(); /** Standard copy constructor \param from the revocation list to copy from */ CRL(const CRL &from); ~CRL(); /** Standard assignment operator \param from the revocation list to assign from */ CRL & operator=(const CRL &from); /** Test if the CRL is empty \return true if the CRL is entry, otherwise return false */ bool isNull() const; /** Information on the issuer of the CRL as a QMultiMap. \sa issuerInfoOrdered for a version that maintains the order of information fields as per the underlying CRL. */ CertificateInfo issuerInfo() const; /** Information on the issuer of the CRL as an ordered list (QList of CertificateInfoPair). \sa issuerInfo for a version that allows lookup based on a multimap. \sa CertificateInfoPair for the elements in the list */ CertificateInfoOrdered issuerInfoOrdered() const; /** The CRL serial number. Note that serial numbers are a CRL extension, and not all certificates have one. \return the CRL serial number, or -1 if there is no serial number */ int number() const; /** the time that this CRL became (or becomes) valid */ QDateTime thisUpdate() const; /** the time that this CRL will be obsoleted you should obtain an updated CRL at this time */ QDateTime nextUpdate() const; /** a list of the revoked certificates in this CRL */ QList revoked() const; /** The signature algorithm used for the signature on this CRL */ SignatureAlgorithm signatureAlgorithm() const; /** The key identification of the CRL issuer */ QByteArray issuerKeyId() const; /** Test for equality of two %Certificate Revocation Lists \param a the CRL to be compared to this CRL \return true if the two CRLs are the same */ bool operator==(const CRL &a) const; /** Inequality operator \param other the CRL to be compared to this CRL */ inline bool operator!=(const CRL &other) const { return !(*this == other); } /** Export the %Certificate Revocation List (CRL) in DER format \return an array containing the CRL in DER format */ QByteArray toDER() const; /** Export the %Certificate Revocation List (CRL) in PEM format \return a string containing the CRL in PEM format */ QString toPEM() const; /** Export the %Certificate Revocation List (CRL) into PEM format in a file \param fileName the name of the file to use */ bool toPEMFile(const QString &fileName) const; /** Import a DER encoded %Certificate Revocation List (CRL) \param a the array containing the CRL in DER format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CRL corresponding to the contents of the array */ static CRL fromDER(const QByteArray &a, ConvertResult *result = 0, const QString &provider = QString()); /** Import a PEM encoded %Certificate Revocation List (CRL) \param s the string containing the CRL in PEM format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CRL corresponding to the contents of the string */ static CRL fromPEM(const QString &s, ConvertResult *result = 0, const QString &provider = QString()); /** Import a PEM encoded %Certificate Revocation List (CRL) from a file \param fileName the name (and path, if required) of the file containing the certificate in PEM format \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CRL in the file */ static CRL fromPEMFile(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); /** \internal \param c context (internal) */ void change(CRLContext *c); private: class Private; friend class Private; QSharedDataPointer d; }; /** \class CertificateCollection qca_cert.h QtCrypto Bundle of Certificates and CRLs CertificateCollection provides a bundle of Certificates and Certificate Revocation Lists (CRLs), not necessarily related. \sa QCA::CertificateChain for a representation of a chain of Certificates related by signatures. \ingroup UserAPI */ class QCA_EXPORT CertificateCollection { public: /** Create an empty Certificate / CRL collection */ CertificateCollection(); /** Standard copy constructor \param from the CertificateCollection to copy from */ CertificateCollection(const CertificateCollection &from); ~CertificateCollection(); /** Standard assignment operator \param from the CertificateCollection to copy from */ CertificateCollection & operator=(const CertificateCollection &from); /** Append a Certificate to this collection \param cert the Certificate to add to this CertificateCollection */ void addCertificate(const Certificate &cert); /** Append a CRL to this collection \param crl the certificate revokation list to add to this CertificateCollection */ void addCRL(const CRL &crl); /** The Certificates in this collection */ QList certificates() const; /** The CRLs in this collection */ QList crls() const; /** Add another CertificateCollection to this collection \param other the CertificateCollection to add to this collection */ void append(const CertificateCollection &other); /** Add another CertificateCollection to this collection \param other the CertificateCollection to add to this collection */ CertificateCollection operator+(const CertificateCollection &other) const; /** Add another CertificateCollection to this collection \param other the CertificateCollection to add to this collection */ CertificateCollection & operator+=(const CertificateCollection &other); /** test if the CertificateCollection can be imported and exported to PKCS#7 format \param provider the provider to use, if a specific provider is required \return true if the CertificateCollection can be imported and exported to PKCS#7 format */ static bool canUsePKCS7(const QString &provider = QString()); /** export the CertificateCollection to a plain text file \param fileName the name (and path, if required) to write the contents of the CertificateCollection to \return true if the export succeeded, otherwise false */ bool toFlatTextFile(const QString &fileName); /** export the CertificateCollection to a PKCS#7 file \param fileName the name (and path, if required) to write the contents of the CertificateCollection to \param provider the provider to use, if a specific provider is required \return true if the export succeeded, otherwise false */ bool toPKCS7File(const QString &fileName, const QString &provider = QString()); /** import a CertificateCollection from a text file \param fileName the name (and path, if required) to read the certificate collection from \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CertificateCollection corresponding to the contents of the file specified in fileName */ static CertificateCollection fromFlatTextFile(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); /** import a CertificateCollection from a PKCS#7 file \param fileName the name (and path, if required) to read the certificate collection from \param result a pointer to a ConvertResult, which if not-null will be set to the conversion status \param provider the provider to use, if a specific provider is required \return the CertificateCollection corresponding to the contents of the file specified in fileName */ static CertificateCollection fromPKCS7File(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); private: class Private; QSharedDataPointer d; }; /** \class CertificateAuthority qca_cert.h QtCrypto A %Certificate Authority is used to generate Certificates and %Certificate Revocation Lists (CRLs). \ingroup UserAPI */ class QCA_EXPORT CertificateAuthority : public Algorithm { public: /** Create a new %Certificate Authority \param cert the CA certificate \param key the private key associated with the CA certificate \param provider the provider to use, if a specific provider is required */ CertificateAuthority(const Certificate &cert, const PrivateKey &key, const QString &provider); /** Copy constructor \param from the CertificateAuthority to copy from */ CertificateAuthority(const CertificateAuthority &from); ~CertificateAuthority(); /** Standard assignment operator \param from the CertificateAuthority to copy from */ CertificateAuthority & operator=(const CertificateAuthority &from); /** The Certificate belonging to the %CertificateAuthority This is the Certificate that was passed as an argument to the constructor */ Certificate certificate() const; /** Create a new Certificate by signing the provider CertificateRequest \param req the CertificateRequest to sign \param notValidAfter the last date that the Certificate will be valid */ Certificate signRequest(const CertificateRequest &req, const QDateTime ¬ValidAfter) const; /** Create a new Certificate \param key the Public Key to use to create the Certificate \param opts the options to use for the new Certificate */ Certificate createCertificate(const PublicKey &key, const CertificateOptions &opts) const; /** Create a new Certificate Revocation List (CRL) \param nextUpdate the date that the CRL will be updated \return an empty CRL */ CRL createCRL(const QDateTime &nextUpdate) const; /** Update the CRL to include new entries \param crl the CRL to update \param entries the entries to add to the CRL \param nextUpdate the date that this CRL will be updated \return the update CRL */ CRL updateCRL(const CRL &crl, const QList &entries, const QDateTime &nextUpdate) const; private: class Private; Private *d; }; /** \class KeyBundle qca_cert.h QtCrypto Certificate chain and private key pair KeyBundle is essentially a convience class that holds a certificate chain and an associated private key. This class has a number of methods that make it particularly suitable for accessing a PKCS12 (.p12) format file, however it can be used as just a container for a Certificate, its associated PrivateKey and optionally additional X.509 Certificate that form a chain. For more information on PKCS12 "Personal Information Exchange Syntax Standard", see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf. \ingroup UserAPI */ class QCA_EXPORT KeyBundle { public: /** Create an empty KeyBundle */ KeyBundle(); /** Create a KeyBundle from a PKCS12 (.p12) encoded file This constructor requires appropriate plugin (provider) support. You must check for the "pkcs12" feature before using this constructor. \param fileName the name of the file to read from \param passphrase the passphrase that is applicable to the file \sa fromFile for a more flexible version of the same capability. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ explicit KeyBundle(const QString &fileName, const SecureArray &passphrase = SecureArray()); /** Standard copy constructor \param from the KeyBundle to use as source */ KeyBundle(const KeyBundle &from); ~KeyBundle(); /** Standard assignment operator \param from the KeyBundle to use as source */ KeyBundle & operator=(const KeyBundle &from); /** Test if this key is empty (null) */ bool isNull() const; /** The name associated with this key. This is also known as the "friendly name", and if present, is typically suitable to be displayed to the user. \sa setName */ QString name() const; /** The public certificate part of this bundle \sa setCertificateChainAndKey */ CertificateChain certificateChain() const; /** The private key part of this bundle \sa setCertificateChainAndKey */ PrivateKey privateKey() const; /** Specify the name of this bundle \param s the name to use */ void setName(const QString &s); /** Set the public certificate and private key \param c the CertificateChain containing the public part of the Bundle \param key the private key part of the Bundle \sa privateKey, certificateChain for getters */ void setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key); /** Export the key bundle to an array in PKCS12 format. This method requires appropriate plugin (provider) support - you must check for the "pkcs12" feature, as shown below. \code if( QCA::isSupported("pkcs12") ) { // can use I/O byteArray = bundle.toArray( "pass phrase" ); } else { // not possible to use I/O } \endcode \param passphrase the passphrase to use to protect the bundle \param provider the provider to use, if a specific provider is required */ QByteArray toArray(const SecureArray &passphrase, const QString &provider = QString()) const; /** Export the key bundle to a file in PKCS12 (.p12) format This method requires appropriate plugin (provider) support - you must check for the "pkcs12" feature, as shown below. \code if( QCA::isSupported("pkcs12") ) { // can use I/O bool result = bundle.toFile( filename, "pass phrase" ); } else { // not possible to use I/O } \endcode \param fileName the name of the file to save to \param passphrase the passphrase to use to protect the bundle \param provider the provider to use, if a specific provider is required */ bool toFile(const QString &fileName, const SecureArray &passphrase, const QString &provider = QString()) const; /** Import the key bundle from an array in PKCS12 format This method requires appropriate plugin (provider) support - you must check for the "pkcs12" feature, as shown below. \code if( QCA::isSupported("pkcs12") ) { // can use I/O bundle = QCA::KeyBundle::fromArray( array, "pass phrase" ); } else { // not possible to use I/O } \endcode \param a the array to import from \param passphrase the passphrase for the encoded bundle \param result pointer to the result of the import process \param provider the provider to use, if a specific provider is required \sa QCA::KeyLoader for an asynchronous loader approach. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ static KeyBundle fromArray(const QByteArray &a, const SecureArray &passphrase = SecureArray(), ConvertResult *result = 0, const QString &provider = QString()); /** Import the key bundle from a file in PKCS12 (.p12) format This method requires appropriate plugin (provider) support - you must check for the "pkcs12" feature, as shown below. \code if( QCA::isSupported("pkcs12") ) { // can use I/O bundle = QCA::KeyBundle::fromFile( filename, "pass phrase" ); } else { // not possible to use I/O } \endcode \param fileName the name of the file to read from \param passphrase the passphrase for the encoded bundle \param result pointer to the result of the import process \param provider the provider to use, if a specific provider is required \sa QCA::KeyLoader for an asynchronous loader approach. \note This synchronous operation may require event handling, and so it must not be called from the same thread as an EventHandler. */ static KeyBundle fromFile(const QString &fileName, const SecureArray &passphrase = SecureArray(), ConvertResult *result = 0, const QString &provider = QString()); private: class Private; QSharedDataPointer d; }; /** \class PGPKey qca_cert.h QtCrypto Pretty Good Privacy key This holds either a reference to an item in a real PGP keyring, or a standalone item created using the from*() functions. Note that with the latter method, the key is of no use besides being informational. The key must be in a keyring (that is, inKeyring() == true) to actually do crypto with it. \ingroup UserAPI */ class QCA_EXPORT PGPKey : public Algorithm { public: /** Create an empty PGP key */ PGPKey(); /** Create a PGP key from an encoded file \param fileName the name (and path, if required) of the file that the PGP key is to be loaded from. \sa fromFile for a version that allows better error checking / validation \sa toFile for a method to write out the key. */ PGPKey(const QString &fileName); /** Standard copy constructor \param from the PGPKey to use as the source */ PGPKey(const PGPKey &from); ~PGPKey(); /** Standard assignment operator \param from the PGPKey to use as the source */ PGPKey & operator=(const PGPKey &from); /** Test if the PGP key is empty (null) \return true if the PGP key is null */ bool isNull() const; /** The Key identification for the PGP key */ QString keyId() const; /** The primary user identification for the key */ QString primaryUserId() const; /** The list of all user identifications associated with the key */ QStringList userIds() const; /** Test if the PGP key is the secret key \return true if the PGP key is the secret key */ bool isSecret() const; /** The creation date for the key */ QDateTime creationDate() const; /** The expiration date for the key */ QDateTime expirationDate() const; /** The key fingerpint This will return the PGP fingerprint as a string. It comprises 40 hex digits, without spaces. */ QString fingerprint() const; /** Test if this key is in a keyring \return true if the key is in a keyring \note keys that are not in a keyring cannot be used for encryption, decryption, signing or verification */ bool inKeyring() const; /** Test if the key is trusted \return true if the key is trusted */ bool isTrusted() const; /** Export the key to an array. This will export the key in a binary format (that is, not in an "ascii armoured" form). \sa fromArray for a static import method. \sa toString for an "ascii armoured" export method. */ QByteArray toArray() const; /** Export the key to a string This will export the key in an "ascii armoured" form. \sa fromString for a static import method. \sa toArray for a binary format export method. */ QString toString() const; /** Export the key to a file \param fileName the name of the file to save the key to */ bool toFile(const QString &fileName) const; /** Import the key from an array \param a the array to import from \param result if not null, this will be set to the result of the import process \param provider the provider to use, if a particular provider is required */ static PGPKey fromArray(const QByteArray &a, ConvertResult *result = 0, const QString &provider = QString()); /** Import the key from a string \param s the string to import from \param result if not null, this will be set to the result of the import process \param provider the provider to use, if a particular provider is required */ static PGPKey fromString(const QString &s, ConvertResult *result = 0, const QString &provider = QString()); /** Import the key from a file \param fileName string containing the name of the file to import from \param result if not null, this will be set to the result of the import process \param provider the provider to use, if a particular provider is required */ static PGPKey fromFile(const QString &fileName, ConvertResult *result = 0, const QString &provider = QString()); private: class Private; Private *d; }; /** \class KeyLoader qca_cert.h QtCrypto Asynchronous private key loader GUI applications generally must use KeyLoader to load private keys. This is because the synchronous private key loading functions, for example QCA::PrivateKey::fromPEMFile(), cannot be used within the same thread as an EventHandler, and most GUI applications will use EventHandler from the main thread. KeyLoader does not have this problem. It can be used from any thread, including the same thread as EventHandler. The KeyLoader class allows you to asynchronously load stand-alone private keys (QCA::PrivateKey) or private keys with a certificate (QCA::KeyBundle) with a signal that advises of completion. To use this class to load a PrivateKey, you create a KeyLoader object then use one of the loadPrivateKeyFrom...() functions, depending on the format for your key. These functions return immediately. When you get the finished() signal, you can check that the loading operation succeeded (using convertResult()) and then obtain the PrivateKey using the privateKey() function. The same process applies for loading a KeyBundle, except that you use either loadKeyBundleFromFile() or loadKeyBundleFromArray() instead of the loadPrivateKeyFrom...() function, and use keyBundle() instead of privateKey(). The loader may need a passphrase to complete the loading of the key or key bundle. You should use the QCA::EventHandler class to ensure that you deal with this correctly. \note %QCA also provides synchronous private key loading using QCA::PrivateKey::fromPEMFile(), QCA::PrivateKey::fromPEM() and QCA::PrivateKey::fromDER(). %QCA provides synchronous key bundle loading using QCA::KeyBundle::fromArray() and QCA::KeyBundle::fromFile(). \ingroup UserAPI */ class QCA_EXPORT KeyLoader : public QObject { Q_OBJECT public: /** Create a KeyLoader object. \param parent the parent object for this object */ KeyLoader(QObject *parent = 0); ~KeyLoader(); /** Initiate an asynchronous loading of a PrivateKey from a PEM format file. This function will return immediately. \param fileName the name of the file (and path, if necessary) to load the key from */ void loadPrivateKeyFromPEMFile(const QString &fileName); /** Initiate an asynchronous loading of a PrivateKey from a PEM format string. This function will return immediately. \param s the string containing the PEM formatted key */ void loadPrivateKeyFromPEM(const QString &s); /** Initiate an asynchronous loading of a PrivateKey from a DER format array. This function will return immediately. \param a the array containing the DER formatted key */ void loadPrivateKeyFromDER(const SecureArray &a); /** Initiate an asynchronous loading of a KeyBundle from a file This function will return immediately. \param fileName the name of the file (and path, if necessary) to load the key bundle from */ void loadKeyBundleFromFile(const QString &fileName); /** Initiate an asynchronous loading of a KeyBundle from an array This function will return immediately. \param a the array containing the key bundle */ void loadKeyBundleFromArray(const QByteArray &a); /** The result of the loading process. This is not valid until the finished() signal has been emitted. */ ConvertResult convertResult() const; /** The private key that has been loaded. This is only valid if loadPrivateKeyFromPEMFile(), loadPrivateKeyFromPEM() or loadPrivateKeyFromDER() has been used, the load has completed (that is, finished() has been emitted), and the conversion succeeded (that is, convertResult() returned ConvertGood). */ PrivateKey privateKey() const; /** The key bundle that has been loaded. This is only valid if loadKeyBundleFromFile() or loadKeyBundleFromArray() has been used, the load has completed (that is, finished() has been emitted), and the conversion succeeded (that is, convertResult() returned ConvertGood). */ KeyBundle keyBundle() const; Q_SIGNALS: /** Signal that is emitted when the load process has completed. \note The load process may not have completed successfully - check the result of convertResult() to confirm this before using the privateKey() or keyBundle() results. */ void finished(); private: Q_DISABLE_COPY(KeyLoader) class Private; friend class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca-gnupg.pri0000644000175000017500000000045311305557613015754 0ustar janjan# DEFINES += GPG_DEBUG windows:LIBS += -ladvapi32 GPG_BASE = $$PWD/qca-gnupg GPGPROC_BASE = $$GPG_BASE/gpgproc include($$GPGPROC_BASE/gpgproc.pri) INCLUDEPATH += $$GPGPROC_BASE INCLUDEPATH += $$GPG_BASE HEADERS += \ $$GPG_BASE/gpgop.h SOURCES += \ $$GPG_BASE/gpgop.cpp \ $$GPG_BASE/qca-gnupg.cpp psi-0.14/third-party/qca/qca.pri0000644000175000017500000000017711305557613014641 0ustar janjanINCLUDEPATH += $$PWD/qca/include/QtCrypto LIBS += -L$$PWD -lqca_psi windows:LIBS += -lcrypt32 mac:LIBS += -framework Security psi-0.14/third-party/qca/qca-gnupg/0000755000175000017500000000000011305557613015236 5ustar janjanpsi-0.14/third-party/qca/qca-gnupg/gpgop.h0000644000175000017500000001176011305557613016530 0ustar janjan/* * Copyright (C) 2003-2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #ifndef GPGOP_H #define GPGOP_H #include #include "qpipe.h" namespace gpgQCAPlugin { class GpgOp : public QObject { Q_OBJECT public: enum Type { Check, // --version SecretKeyringFile, // --list-secret-keys PublicKeyringFile, // --list-public-keys SecretKeys, // --fixed-list-mode --with-colons --list-secret-keys PublicKeys, // --fixed-list-mode --with-colons --list-public-keys Encrypt, // --encrypt Decrypt, // --decrypt Sign, // --sign SignAndEncrypt, // --sign --encrypt SignClearsign, // --clearsign SignDetached, // --detach-sign Verify, // --verify VerifyDetached, // --verify Import, // --import Export, // --export DeleteKey // --delete-key }; enum VerifyResult { VerifyGood, // good sig VerifyBad, // bad sig VerifyNoKey // we don't have signer's public key }; enum Error { ErrorProcess, // startup, process, or ipc error ErrorPassphrase, // passphrase was either wrong or not provided ErrorFormat, // input format was bad ErrorSignerExpired, // signing key is expired ErrorEncryptExpired, // encrypting key is expired ErrorEncryptUntrusted, // encrypting key is untrusted ErrorEncryptInvalid, // encrypting key is invalid in some way ErrorDecryptNoKey, // missing decrypt key ErrorUnknown // other error }; class Event { public: enum Type { None, ReadyRead, BytesWritten, Finished, NeedPassphrase, NeedCard, ReadyReadDiagnosticText }; Type type; int written; // BytesWritten QString keyId; // NeedPassphrase Event() : type(None), written(0) {} }; class KeyItem { public: enum Type { RSA, DSA, ElGamal, Unknown }; enum Caps { Encrypt = 0x01, Sign = 0x02, Certify = 0x04, Auth = 0x08 }; QString id; Type type; int bits; QDateTime creationDate; QDateTime expirationDate; int caps; // flags OR'd together QString fingerprint; KeyItem() : type(Unknown), bits(0), caps(0) {} }; class Key { public: QList keyItems; // first item is primary QStringList userIds; bool isTrusted; Key() : isTrusted(false) {} }; typedef QList KeyList; explicit GpgOp(const QString &bin, QObject *parent = 0); ~GpgOp(); void reset(); bool isActive() const; Type op() const; void setAsciiFormat(bool b); void setDisableAgent(bool b); void setAlwaysTrust(bool b); void setKeyrings(const QString &pubfile, const QString &secfile); // for keylists and import void doCheck(); void doSecretKeyringFile(); void doPublicKeyringFile(); void doSecretKeys(); void doPublicKeys(); void doEncrypt(const QStringList &recip_ids); void doDecrypt(); void doSign(const QString &signer_id); void doSignAndEncrypt(const QString &signer_id, const QStringList &recip_ids); void doSignClearsign(const QString &signer_id); void doSignDetached(const QString &signer_id); void doVerify(); void doVerifyDetached(const QByteArray &sig); void doImport(const QByteArray &in); void doExport(const QString &key_id); void doDeleteKey(const QString &key_fingerprint); #ifdef QPIPE_SECURE void submitPassphrase(const QCA::SecureArray &a); #else void submitPassphrase(const QByteArray &a); #endif void cardOkay(); // for encrypt, decrypt, sign, verify, export QByteArray read(); void write(const QByteArray &in); void endWrite(); QString readDiagnosticText(); // for synchronous operation Event waitForEvent(int msecs = -1); // results bool success() const; Error errorCode() const; KeyList keys() const; // Keys QString keyringFile() const; // KeyringFile QString encryptedToId() const; // Decrypt (for ErrorDecryptNoKey) bool wasSigned() const; // Decrypt QString signerId() const; // Verify QDateTime timestamp() const; // Verify VerifyResult verifyResult() const; // Verify Q_SIGNALS: void readyRead(); void bytesWritten(int bytes); void finished(); void needPassphrase(const QString &keyId); void needCard(); void readyReadDiagnosticText(); private: class Private; friend class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca-gnupg/gpgproc/0000755000175000017500000000000011305557613016677 5ustar janjanpsi-0.14/third-party/qca/qca-gnupg/gpgproc/sprocess.cpp0000644000175000017500000000273111305557613021247 0ustar janjan/* * Copyright (C) 2003-2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #include "sprocess.h" #ifdef Q_OS_UNIX # include # include #endif namespace gpgQCAPlugin { //---------------------------------------------------------------------------- // SProcess //---------------------------------------------------------------------------- SProcess::SProcess(QObject *parent) :QProcess(parent) { } SProcess::~SProcess() { } #ifdef Q_OS_UNIX void SProcess::setInheritPipeList(const QList &list) { pipeList = list; } void SProcess::setupChildProcess() { // set the pipes to be inheritable for(int n = 0; n < pipeList.count(); ++n) ::fcntl(pipeList[n], F_SETFD, (::fcntl(pipeList[n], F_GETFD) & ~FD_CLOEXEC)); } #endif } psi-0.14/third-party/qca/qca-gnupg/gpgproc/sprocess.h0000644000175000017500000000224311305557613020712 0ustar janjan/* * Copyright (C) 2003-2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #ifndef SPROCESS_H #define SPROCESS_H #include #include namespace gpgQCAPlugin { class SProcess : public QProcess { Q_OBJECT public: SProcess(QObject *parent = 0); ~SProcess(); #ifdef Q_OS_UNIX void setInheritPipeList(const QList &); protected: virtual void setupChildProcess(); private: QList pipeList; #endif }; } #endif psi-0.14/third-party/qca/qca-gnupg/gpgproc/README0000644000175000017500000000056611305557613017566 0ustar janjanGPGProc launches a single instance of GPG and provides a friendly API to work with all six possible pipe channels. Theoretically, it should be possible to build any GPG front end with it, even though qca-gnupg uses it for only a handful of operations. If you are writing a Qt-based GPG front end, please use this class. GPGProc works on both Windows and Unix platforms. psi-0.14/third-party/qca/qca-gnupg/gpgproc/gpgproc.pri0000644000175000017500000000015211305557613021052 0ustar janjanHEADERS += \ $$PWD/sprocess.h \ $$PWD/gpgproc.h SOURCES += \ $$PWD/sprocess.cpp \ $$PWD/gpgproc.cpp psi-0.14/third-party/qca/qca-gnupg/gpgproc/gpgproc.h0000644000175000017500000000612411305557613020514 0ustar janjan/* * Copyright (C) 2003-2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #ifndef GPGPROC_H #define GPGPROC_H #include "qpipe.h" class QTimer; namespace gpgQCAPlugin { // FIXME: Even though deleting an object during a metacall event is supposed // to be legal with Qt, it is unfortunately buggy (at least before Qt 4.4). // This function performs the following steps: // obj->disconnect(owner); // to prevent future signals to owner // obj->setParent(0); // to prevent delete if parent is deleted // obj->deleteLater(); // now we can forget about the object void releaseAndDeleteLater(QObject *owner, QObject *obj); class SafeTimer : public QObject { Q_OBJECT public: SafeTimer(QObject *parent = 0); ~SafeTimer(); int interval() const; bool isActive() const; bool isSingleShot() const; void setInterval(int msec); void setSingleShot(bool singleShot); int timerId() const; public slots: void start(int msec); void start(); void stop(); signals: void timeout(); private: QTimer *timer; }; // GPGProc - executes gpg and provides access to all 6 channels. NormalMode // enables stdout, stderr, and stdin. ExtendedMode has those 3 plus status // aux, and command. The aux channel is connected to the '-&?' argument. // The debug() signal, as well as stderr, can be used for diagnostic text. class GPGProc : public QObject { Q_OBJECT public: enum Error { FailedToStart, UnexpectedExit, ErrorWrite }; enum Mode { NormalMode, ExtendedMode }; GPGProc(QObject *parent = 0); ~GPGProc(); void reset(); bool isActive() const; void start(const QString &bin, const QStringList &args, Mode m = ExtendedMode); QByteArray readStdout(); QByteArray readStderr(); QStringList readStatusLines(); void writeStdin(const QByteArray &a); void writeAux(const QByteArray &a); #ifdef QPIPE_SECURE void writeCommand(const QCA::SecureArray &a); #else void writeCommand(const QByteArray &a); #endif void closeStdin(); void closeAux(); void closeCommand(); Q_SIGNALS: void error(gpgQCAPlugin::GPGProc::Error error); void finished(int exitCode); void readyReadStdout(); void readyReadStderr(); void readyReadStatusLines(); void bytesWrittenStdin(int bytes); void bytesWrittenAux(int bytes); void bytesWrittenCommand(int bytes); void debug(const QString &str); // not signal-safe private: class Private; friend class Private; Private *d; }; } #endif psi-0.14/third-party/qca/qca-gnupg/gpgproc/gpgproc.cpp0000644000175000017500000004370011305557613021050 0ustar janjan/* * Copyright (C) 2003-2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #include "gpgproc.h" #include "sprocess.h" #ifdef Q_OS_MAC #define QT_PIPE_HACK #endif #define QPROC_SIGNAL_RELAY using namespace QCA; namespace gpgQCAPlugin { void releaseAndDeleteLater(QObject *owner, QObject *obj) { obj->disconnect(owner); obj->setParent(0); obj->deleteLater(); } //---------------------------------------------------------------------------- // SafeTimer //---------------------------------------------------------------------------- SafeTimer::SafeTimer(QObject *parent) : QObject(parent) { timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SIGNAL(timeout())); } SafeTimer::~SafeTimer() { releaseAndDeleteLater(this, timer); } int SafeTimer::interval() const { return timer->interval(); } bool SafeTimer::isActive() const { return timer->isActive(); } bool SafeTimer::isSingleShot() const { return timer->isSingleShot(); } void SafeTimer::setInterval(int msec) { timer->setInterval(msec); } void SafeTimer::setSingleShot(bool singleShot) { timer->setSingleShot(singleShot); } int SafeTimer::timerId() const { return timer->timerId(); } void SafeTimer::start(int msec) { timer->start(msec); } void SafeTimer::start() { timer->start(); } void SafeTimer::stop() { timer->stop(); } //---------------------------------------------------------------------------- // QProcessSignalRelay //---------------------------------------------------------------------------- class QProcessSignalRelay : public QObject { Q_OBJECT public: QProcessSignalRelay(QProcess *proc, QObject *parent = 0) :QObject(parent) { qRegisterMetaType("QProcess::ProcessError"); connect(proc, SIGNAL(started()), SLOT(proc_started()), Qt::QueuedConnection); connect(proc, SIGNAL(readyReadStandardOutput()), SLOT(proc_readyReadStandardOutput()), Qt::QueuedConnection); connect(proc, SIGNAL(readyReadStandardError()), SLOT(proc_readyReadStandardError()), Qt::QueuedConnection); connect(proc, SIGNAL(bytesWritten(qint64)), SLOT(proc_bytesWritten(qint64)), Qt::QueuedConnection); connect(proc, SIGNAL(finished(int)), SLOT(proc_finished(int)), Qt::QueuedConnection); connect(proc, SIGNAL(error(QProcess::ProcessError)), SLOT(proc_error(QProcess::ProcessError)), Qt::QueuedConnection); } signals: void started(); void readyReadStandardOutput(); void readyReadStandardError(); void bytesWritten(qint64); void finished(int); void error(QProcess::ProcessError); public slots: void proc_started() { emit started(); } void proc_readyReadStandardOutput() { emit readyReadStandardOutput(); } void proc_readyReadStandardError() { emit readyReadStandardError(); } void proc_bytesWritten(qint64 x) { emit bytesWritten(x); } void proc_finished(int x) { emit finished(x); } void proc_error(QProcess::ProcessError x) { emit error(x); } }; //---------------------------------------------------------------------------- // GPGProc //---------------------------------------------------------------------------- enum ResetMode { ResetSession = 0, ResetSessionAndData = 1, ResetAll = 2 }; class GPGProc::Private : public QObject { Q_OBJECT public: GPGProc *q; QString bin; QStringList args; GPGProc::Mode mode; SProcess *proc; #ifdef QPROC_SIGNAL_RELAY QProcessSignalRelay *proc_relay; #endif QPipe pipeAux, pipeCommand, pipeStatus; QByteArray statusBuf; QStringList statusLines; GPGProc::Error error; int exitCode; SafeTimer startTrigger, doneTrigger; QByteArray pre_stdin, pre_aux; #ifdef QPIPE_SECURE SecureArray pre_command; #else QByteArray pre_command; #endif bool pre_stdin_close, pre_aux_close, pre_command_close; bool need_status, fin_process, fin_process_success, fin_status; QByteArray leftover_stdout; QByteArray leftover_stderr; Private(GPGProc *_q) : QObject(_q), q(_q), pipeAux(this), pipeCommand(this), pipeStatus(this), startTrigger(this), doneTrigger(this) { qRegisterMetaType("gpgQCAPlugin::GPGProc::Error"); proc = 0; #ifdef QPROC_SIGNAL_RELAY proc_relay = 0; #endif startTrigger.setSingleShot(true); doneTrigger.setSingleShot(true); connect(&pipeAux.writeEnd(), SIGNAL(bytesWritten(int)), SLOT(aux_written(int))); connect(&pipeAux.writeEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(aux_error(QCA::QPipeEnd::Error))); connect(&pipeCommand.writeEnd(), SIGNAL(bytesWritten(int)), SLOT(command_written(int))); connect(&pipeCommand.writeEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(command_error(QCA::QPipeEnd::Error))); connect(&pipeStatus.readEnd(), SIGNAL(readyRead()), SLOT(status_read())); connect(&pipeStatus.readEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(status_error(QCA::QPipeEnd::Error))); connect(&startTrigger, SIGNAL(timeout()), SLOT(doStart())); connect(&doneTrigger, SIGNAL(timeout()), SLOT(doTryDone())); reset(ResetSessionAndData); } ~Private() { reset(ResetSession); } void closePipes() { #ifdef QT_PIPE_HACK pipeAux.readEnd().reset(); pipeCommand.readEnd().reset(); pipeStatus.writeEnd().reset(); #endif pipeAux.reset(); pipeCommand.reset(); pipeStatus.reset(); } void reset(ResetMode mode) { #ifndef QT_PIPE_HACK closePipes(); #endif if(proc) { proc->disconnect(this); if(proc->state() != QProcess::NotRunning) proc->terminate(); proc->setParent(0); #ifdef QPROC_SIGNAL_RELAY releaseAndDeleteLater(this, proc_relay); proc_relay = 0; delete proc; // should be safe to do thanks to relay #else proc->deleteLater(); #endif proc = 0; } #ifdef QT_PIPE_HACK closePipes(); #endif startTrigger.stop(); doneTrigger.stop(); pre_stdin.clear(); pre_aux.clear(); pre_command.clear(); pre_stdin_close = false; pre_aux_close = false; pre_command_close = false; need_status = false; fin_process = false; fin_status = false; if(mode >= ResetSessionAndData) { statusBuf.clear(); statusLines.clear(); leftover_stdout.clear(); leftover_stderr.clear(); error = GPGProc::FailedToStart; exitCode = -1; } } bool setupPipes(bool makeAux) { if(makeAux && !pipeAux.create()) { closePipes(); emit q->debug("Error creating pipeAux"); return false; } #ifdef QPIPE_SECURE if(!pipeCommand.create(true)) // secure #else if(!pipeCommand.create()) #endif { closePipes(); emit q->debug("Error creating pipeCommand"); return false; } if(!pipeStatus.create()) { closePipes(); emit q->debug("Error creating pipeStatus"); return false; } return true; } void setupArguments() { QStringList fullargs; fullargs += "--no-tty"; if(mode == ExtendedMode) { fullargs += "--enable-special-filenames"; fullargs += "--status-fd"; fullargs += QString::number(pipeStatus.writeEnd().idAsInt()); fullargs += "--command-fd"; fullargs += QString::number(pipeCommand.readEnd().idAsInt()); } for(int n = 0; n < args.count(); ++n) { QString a = args[n]; if(mode == ExtendedMode && a == "-&?") fullargs += QString("-&") + QString::number(pipeAux.readEnd().idAsInt()); else fullargs += a; } QString fullcmd = fullargs.join(" "); emit q->debug(QString("Running: [") + bin + ' ' + fullcmd + ']'); args = fullargs; } public slots: void doStart() { #ifdef Q_OS_WIN // Note: for unix, inheritability is set in SProcess if(pipeAux.readEnd().isValid()) pipeAux.readEnd().setInheritable(true); if(pipeCommand.readEnd().isValid()) pipeCommand.readEnd().setInheritable(true); if(pipeStatus.writeEnd().isValid()) pipeStatus.writeEnd().setInheritable(true); #endif setupArguments(); proc->start(bin, args); // FIXME: From reading the source to Qt on both windows // and unix platforms, we know that fork/CreateProcess // are called in start. However this is not guaranteed // from an API perspective. We should probably call // QProcess::waitForStarted() to synchronously ensure // fork/CreateProcess are called before closing these // pipes. pipeAux.readEnd().close(); pipeCommand.readEnd().close(); pipeStatus.writeEnd().close(); } void aux_written(int x) { emit q->bytesWrittenAux(x); } void aux_error(QCA::QPipeEnd::Error) { emit q->debug("Aux: Pipe error"); reset(ResetSession); emit q->error(GPGProc::ErrorWrite); } void command_written(int x) { emit q->bytesWrittenCommand(x); } void command_error(QCA::QPipeEnd::Error) { emit q->debug("Command: Pipe error"); reset(ResetSession); emit q->error(GPGProc::ErrorWrite); } void status_read() { if(readAndProcessStatusData()) emit q->readyReadStatusLines(); } void status_error(QCA::QPipeEnd::Error e) { if(e == QPipeEnd::ErrorEOF) emit q->debug("Status: Closed (EOF)"); else emit q->debug("Status: Closed (gone)"); fin_status = true; doTryDone(); } void proc_started() { emit q->debug("Process started"); // Note: we don't close these here anymore. instead we // do it just after calling proc->start(). // close these, we don't need them /*pipeAux.readEnd().close(); pipeCommand.readEnd().close(); pipeStatus.writeEnd().close();*/ // do the pre* stuff if(!pre_stdin.isEmpty()) { proc->write(pre_stdin); pre_stdin.clear(); } if(!pre_aux.isEmpty()) { pipeAux.writeEnd().write(pre_aux); pre_aux.clear(); } if(!pre_command.isEmpty()) { #ifdef QPIPE_SECURE pipeCommand.writeEnd().writeSecure(pre_command); #else pipeCommand.writeEnd().write(pre_command); #endif pre_command.clear(); } if(pre_stdin_close) proc->closeWriteChannel(); if(pre_aux_close) pipeAux.writeEnd().close(); if(pre_command_close) pipeCommand.writeEnd().close(); } void proc_readyReadStandardOutput() { emit q->readyReadStdout(); } void proc_readyReadStandardError() { emit q->readyReadStderr(); } void proc_bytesWritten(qint64 lx) { int x = (int)lx; emit q->bytesWrittenStdin(x); } void proc_finished(int x) { emit q->debug(QString("Process finished: %1").arg(x)); exitCode = x; fin_process = true; fin_process_success = true; if(need_status && !fin_status) { pipeStatus.readEnd().finalize(); fin_status = true; if(readAndProcessStatusData()) { doneTrigger.start(); emit q->readyReadStatusLines(); return; } } doTryDone(); } void proc_error(QProcess::ProcessError x) { QMap errmap; errmap[QProcess::FailedToStart] = "FailedToStart"; errmap[QProcess::Crashed] = "Crashed"; errmap[QProcess::Timedout] = "Timedout"; errmap[QProcess::WriteError] = "WriteError"; errmap[QProcess::ReadError] = "ReadError"; errmap[QProcess::UnknownError] = "UnknownError"; emit q->debug(QString("Process error: %1").arg(errmap[x])); if(x == QProcess::FailedToStart) error = GPGProc::FailedToStart; else if(x == QProcess::WriteError) error = GPGProc::ErrorWrite; else error = GPGProc::UnexpectedExit; fin_process = true; fin_process_success = false; #ifdef QT_PIPE_HACK // If the process fails to start, then the ends of the pipes // intended for the child process are still open. Some Mac // users experience a lockup if we close our ends of the pipes // when the child's ends are still open. If we ensure the // child's ends are closed, we prevent this lockup. I have no // idea why the problem even happens or why this fix should // work. pipeAux.readEnd().reset(); pipeCommand.readEnd().reset(); pipeStatus.writeEnd().reset(); #endif if(need_status && !fin_status) { pipeStatus.readEnd().finalize(); fin_status = true; if(readAndProcessStatusData()) { doneTrigger.start(); emit q->readyReadStatusLines(); return; } } doTryDone(); } void doTryDone() { if(!fin_process) return; if(need_status && !fin_status) return; emit q->debug("Done"); // get leftover data proc->setReadChannel(QProcess::StandardOutput); leftover_stdout = proc->readAll(); proc->setReadChannel(QProcess::StandardError); leftover_stderr = proc->readAll(); reset(ResetSession); if(fin_process_success) emit q->finished(exitCode); else emit q->error(error); } private: bool readAndProcessStatusData() { QByteArray buf = pipeStatus.readEnd().read(); if(buf.isEmpty()) return false; return processStatusData(buf); } // return true if there are newly parsed lines available bool processStatusData(const QByteArray &buf) { statusBuf.append(buf); // extract all lines QStringList list; while(1) { int n = statusBuf.indexOf('\n'); if(n == -1) break; // extract the string from statusbuf ++n; char *p = (char *)statusBuf.data(); QByteArray cs(p, n); int newsize = statusBuf.size() - n; memmove(p, p + n, newsize); statusBuf.resize(newsize); // convert to string without newline QString str = QString::fromUtf8(cs); str.truncate(str.length() - 1); // ensure it has a proper header if(str.left(9) != "[GNUPG:] ") continue; // take it off str = str.mid(9); // add to the list list += str; } if(list.isEmpty()) return false; statusLines += list; return true; } }; GPGProc::GPGProc(QObject *parent) :QObject(parent) { d = new Private(this); } GPGProc::~GPGProc() { delete d; } void GPGProc::reset() { d->reset(ResetAll); } bool GPGProc::isActive() const { return (d->proc ? true : false); } void GPGProc::start(const QString &bin, const QStringList &args, Mode mode) { if(isActive()) d->reset(ResetSessionAndData); if(mode == ExtendedMode) { if(!d->setupPipes(args.contains("-&?"))) { d->error = FailedToStart; // emit later QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(gpgQCAPlugin::GPGProc::Error, d->error)); return; } d->need_status = true; emit debug("Pipe setup complete"); } d->proc = new SProcess(d); #ifdef Q_OS_UNIX QList plist; if(d->pipeAux.readEnd().isValid()) plist += d->pipeAux.readEnd().id(); if(d->pipeCommand.readEnd().isValid()) plist += d->pipeCommand.readEnd().id(); if(d->pipeStatus.writeEnd().isValid()) plist += d->pipeStatus.writeEnd().id(); d->proc->setInheritPipeList(plist); #endif // enable the pipes we want if(d->pipeAux.writeEnd().isValid()) d->pipeAux.writeEnd().enable(); if(d->pipeCommand.writeEnd().isValid()) d->pipeCommand.writeEnd().enable(); if(d->pipeStatus.readEnd().isValid()) d->pipeStatus.readEnd().enable(); #ifdef QPROC_SIGNAL_RELAY d->proc_relay = new QProcessSignalRelay(d->proc, d); connect(d->proc_relay, SIGNAL(started()), d, SLOT(proc_started())); connect(d->proc_relay, SIGNAL(readyReadStandardOutput()), d, SLOT(proc_readyReadStandardOutput())); connect(d->proc_relay, SIGNAL(readyReadStandardError()), d, SLOT(proc_readyReadStandardError())); connect(d->proc_relay, SIGNAL(bytesWritten(qint64)), d, SLOT(proc_bytesWritten(qint64))); connect(d->proc_relay, SIGNAL(finished(int)), d, SLOT(proc_finished(int))); connect(d->proc_relay, SIGNAL(error(QProcess::ProcessError)), d, SLOT(proc_error(QProcess::ProcessError))); #else connect(d->proc, SIGNAL(started()), d, SLOT(proc_started())); connect(d->proc, SIGNAL(readyReadStandardOutput()), d, SLOT(proc_readyReadStandardOutput())); connect(d->proc, SIGNAL(readyReadStandardError()), d, SLOT(proc_readyReadStandardError())); connect(d->proc, SIGNAL(bytesWritten(qint64)), d, SLOT(proc_bytesWritten(qint64))); connect(d->proc, SIGNAL(finished(int)), d, SLOT(proc_finished(int))); connect(d->proc, SIGNAL(error(QProcess::ProcessError)), d, SLOT(proc_error(QProcess::ProcessError))); #endif d->bin = bin; d->args = args; d->mode = mode; d->startTrigger.start(); } QByteArray GPGProc::readStdout() { if(d->proc) { d->proc->setReadChannel(QProcess::StandardOutput); return d->proc->readAll(); } else { QByteArray a = d->leftover_stdout; d->leftover_stdout.clear(); return a; } } QByteArray GPGProc::readStderr() { if(d->proc) { d->proc->setReadChannel(QProcess::StandardError); return d->proc->readAll(); } else { QByteArray a = d->leftover_stderr; d->leftover_stderr.clear(); return a; } } QStringList GPGProc::readStatusLines() { QStringList out = d->statusLines; d->statusLines.clear(); return out; } void GPGProc::writeStdin(const QByteArray &a) { if(!d->proc || a.isEmpty()) return; if(d->proc->state() == QProcess::Running) d->proc->write(a); else d->pre_stdin += a; } void GPGProc::writeAux(const QByteArray &a) { if(!d->proc || a.isEmpty()) return; if(d->proc->state() == QProcess::Running) d->pipeAux.writeEnd().write(a); else d->pre_aux += a; } #ifdef QPIPE_SECURE void GPGProc::writeCommand(const SecureArray &a) #else void GPGProc::writeCommand(const QByteArray &a) #endif { if(!d->proc || a.isEmpty()) return; if(d->proc->state() == QProcess::Running) #ifdef QPIPE_SECURE d->pipeCommand.writeEnd().writeSecure(a); #else d->pipeCommand.writeEnd().write(a); #endif else d->pre_command += a; } void GPGProc::closeStdin() { if(!d->proc) return; if(d->proc->state() == QProcess::Running) d->proc->closeWriteChannel(); else d->pre_stdin_close = true; } void GPGProc::closeAux() { if(!d->proc) return; if(d->proc->state() == QProcess::Running) d->pipeAux.writeEnd().close(); else d->pre_aux_close = true; } void GPGProc::closeCommand() { if(!d->proc) return; if(d->proc->state() == QProcess::Running) d->pipeCommand.writeEnd().close(); else d->pre_command_close = true; } } #include "gpgproc.moc" psi-0.14/third-party/qca/qca-gnupg/qca-gnupg.cpp0000644000175000017500000010507511305557613017634 0ustar janjan/* * Copyright (C) 2003-2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #ifdef Q_OS_MAC #include #endif #ifdef Q_OS_WIN # include #endif #include "gpgop.h" // for SafeTimer and release function #include "gpgproc.h" using namespace QCA; namespace gpgQCAPlugin { #ifdef Q_OS_LINUX static int qVersionInt() { static int out = -1; if(out == -1) { QString str = QString::fromLatin1(qVersion()); QStringList parts = str.split('.', QString::KeepEmptyParts); if(parts.count() != 3) { out = 0; return out; } out = 0; for(int n = 0; n < 3; ++n) { bool ok; int x = parts[n].toInt(&ok); if(ok && x >= 0 && x <= 0xff) { out <<= 8; out += x; } else { out = 0; return out; } } } return out; } static bool qt_buggy_fsw() { // fixed in 4.3.5 and 4.4.1 int ver = qVersionInt(); int majmin = ver >> 8; if(majmin < 0x0403) return true; else if(majmin == 0x0403 && ver < 0x040305) return true; else if(majmin == 0x0404 && ver < 0x040401) return true; return false; } #else static bool qt_buggy_fsw() { return false; } #endif // begin ugly hack for qca 2.0.0 with broken dirwatch support // hacks: // 1) we must construct with a valid file to watch. passing an empty // string doesn't work. this means we can't create the objects in // advance. instead we'll use new/delete as necessary. // 2) there's a wrong internal connect() statement in the qca source. // assuming fixed internals for qca 2.0.0, we can fix that connect from // here... #include // some structures below to give accessible interface to qca 2.0.0 internals class DirWatch2 : public QObject { Q_OBJECT public: explicit DirWatch2(const QString &dir = QString(), QObject *parent = 0) { Q_UNUSED(dir); Q_UNUSED(parent); } ~DirWatch2() { } QString dirName() const { return QString(); } void setDirName(const QString &dir) { Q_UNUSED(dir); } Q_SIGNALS: void changed(); public: Q_DISABLE_COPY(DirWatch2) class Private; friend class Private; Private *d; }; /*class FileWatch2 : public QObject { Q_OBJECT public: explicit FileWatch2(const QString &file = QString(), QObject *parent = 0) { Q_UNUSED(file); Q_UNUSED(parent); } ~FileWatch2() { } QString fileName() const { return QString(); } void setFileName(const QString &file) { Q_UNUSED(file); } Q_SIGNALS: void changed(); public: Q_DISABLE_COPY(FileWatch2) class Private; friend class Private; Private *d; };*/ class QFileSystemWatcherRelay2 : public QObject { Q_OBJECT public: }; class DirWatch2::Private : public QObject { Q_OBJECT public: DirWatch2 *q; QFileSystemWatcher *watcher; QFileSystemWatcherRelay2 *watcher_relay; QString dirName; private slots: void watcher_changed(const QString &path) { Q_UNUSED(path); } }; /*class FileWatch2::Private : public QObject { Q_OBJECT public: FileWatch2 *q; QFileSystemWatcher *watcher; QFileSystemWatcherRelay2 *watcher_relay; QString fileName; private slots: void watcher_changed(const QString &path) { Q_UNUSED(path); } };*/ static void hack_fix(DirWatch *dw) { DirWatch2 *dw2 = reinterpret_cast(dw); QObject::connect(dw2->d->watcher_relay, SIGNAL(directoryChanged(const QString &)), dw2->d, SLOT(watcher_changed(const QString &))); fprintf(stderr, "qca-gnupg: patching DirWatch to fix failed connect\n"); } // end ugly hack #ifdef Q_OS_WIN static QString find_reg_gpgProgram() { HKEY root; root = HKEY_CURRENT_USER; HKEY hkey; const char *path = "Software\\GNU\\GnuPG"; if(RegOpenKeyExA(HKEY_CURRENT_USER, path, 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) { if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) return QString(); } char szValue[256]; DWORD dwLen = 256; if(RegQueryValueExA(hkey, "gpgProgram", NULL, NULL, (LPBYTE)szValue, &dwLen) != ERROR_SUCCESS) { RegCloseKey(hkey); return QString(); } RegCloseKey(hkey); return QString::fromLatin1(szValue); } #endif static QString find_bin() { QString bin = "gpg"; #ifdef Q_OS_WIN QString s = find_reg_gpgProgram(); if(!s.isNull()) bin = s; #endif #ifdef Q_OS_MAC // mac-gpg QFileInfo fi("/usr/local/bin/gpg"); if(fi.exists()) bin = fi.filePath(); #endif return bin; } static QString escape_string(const QString &in) { QString out; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') out += "\\\\"; else if(in[n] == ':') out += "\\c"; else out += in[n]; } return out; } static QString unescape_string(const QString &in) { QString out; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') { if(n + 1 < in.length()) { if(in[n + 1] == '\\') out += '\\'; else if(in[n + 1] == 'c') out += ':'; ++n; } } else out += in[n]; } return out; } static void gpg_waitForFinished(GpgOp *gpg) { while(1) { GpgOp::Event e = gpg->waitForEvent(-1); if(e.type == GpgOp::Event::Finished) break; } } Q_GLOBAL_STATIC(QMutex, ksl_mutex) class MyKeyStoreList; static MyKeyStoreList *keyStoreList = 0; static void gpg_keyStoreLog(const QString &str); class MyPGPKeyContext : public PGPKeyContext { public: PGPKeyContextProps _props; // keys loaded externally (not from the keyring) need to have these // values cached, since we can't extract them later QByteArray cacheExportBinary; QString cacheExportAscii; MyPGPKeyContext(Provider *p) : PGPKeyContext(p) { // zero out the props _props.isSecret = false; _props.inKeyring = true; _props.isTrusted = false; } virtual Provider::Context *clone() const { return new MyPGPKeyContext(*this); } void set(const GpgOp::Key &i, bool isSecret, bool inKeyring, bool isTrusted) { const GpgOp::KeyItem &ki = i.keyItems.first(); _props.keyId = ki.id; _props.userIds = i.userIds; _props.isSecret = isSecret; _props.creationDate = ki.creationDate; _props.expirationDate = ki.expirationDate; _props.fingerprint = ki.fingerprint.toLower(); _props.inKeyring = inKeyring; _props.isTrusted = isTrusted; } virtual const PGPKeyContextProps *props() const { return &_props; } virtual QByteArray toBinary() const { if(_props.inKeyring) { GpgOp gpg(find_bin()); gpg.setAsciiFormat(false); gpg.doExport(_props.keyId); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) return QByteArray(); return gpg.read(); } else return cacheExportBinary; } virtual QString toAscii() const { if(_props.inKeyring) { GpgOp gpg(find_bin()); gpg.setAsciiFormat(true); gpg.doExport(_props.keyId); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) return QString(); return QString::fromLocal8Bit(gpg.read()); } else return cacheExportAscii; } static void cleanup_temp_keyring(const QString &name) { QFile::remove(name); QFile::remove(name + '~'); // remove possible backup file } virtual ConvertResult fromBinary(const QByteArray &a) { GpgOp::Key key; bool sec = false; // temporary keyrings QString pubname, secname; QTemporaryFile pubtmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg")); if(!pubtmp.open()) return ErrorDecode; QTemporaryFile sectmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg")); if(!sectmp.open()) return ErrorDecode; pubname = pubtmp.fileName(); secname = sectmp.fileName(); // we turn off autoRemove so that we can close the files // without them getting deleted pubtmp.setAutoRemove(false); sectmp.setAutoRemove(false); pubtmp.close(); sectmp.close(); // import key into temporary keyring GpgOp gpg(find_bin()); gpg.setKeyrings(pubname, secname); gpg.doImport(a); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); // comment this out. apparently gpg will report failure for // an import if there are trust issues, even though the // key actually did get imported /*if(!gpg.success()) { cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); return ErrorDecode; }*/ // now extract the key from gpg like normal // is it a public key? gpg.doPublicKeys(); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) { cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); return ErrorDecode; } GpgOp::KeyList pubkeys = gpg.keys(); if(!pubkeys.isEmpty()) { key = pubkeys.first(); } else { // is it a secret key? gpg.doSecretKeys(); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) { cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); return ErrorDecode; } GpgOp::KeyList seckeys = gpg.keys(); if(!seckeys.isEmpty()) { key = seckeys.first(); sec = true; } else { // no keys found cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); return ErrorDecode; } } // export binary/ascii and cache gpg.setAsciiFormat(false); gpg.doExport(key.keyItems.first().id); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) { cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); return ErrorDecode; } cacheExportBinary = gpg.read(); gpg.setAsciiFormat(true); gpg.doExport(key.keyItems.first().id); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) { cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); return ErrorDecode; } cacheExportAscii = QString::fromLocal8Bit(gpg.read()); // all done cleanup_temp_keyring(pubname); cleanup_temp_keyring(secname); set(key, sec, false, false); return ConvertGood; } virtual ConvertResult fromAscii(const QString &s) { // GnuPG does ascii/binary detection for imports, so for // simplicity we consider an ascii import to just be a // binary import that happens to be comprised of ascii return fromBinary(s.toLocal8Bit()); } }; class MyKeyStoreEntry : public KeyStoreEntryContext { public: KeyStoreEntry::Type item_type; PGPKey pub, sec; QString _storeId, _storeName; MyKeyStoreEntry(const PGPKey &_pub, const PGPKey &_sec, Provider *p) : KeyStoreEntryContext(p) { pub = _pub; sec = _sec; if(!sec.isNull()) item_type = KeyStoreEntry::TypePGPSecretKey; else item_type = KeyStoreEntry::TypePGPPublicKey; } MyKeyStoreEntry(const MyKeyStoreEntry &from) : KeyStoreEntryContext(from) { } ~MyKeyStoreEntry() { } virtual Provider::Context *clone() const { return new MyKeyStoreEntry(*this); } virtual KeyStoreEntry::Type type() const { return item_type; } virtual QString name() const { return pub.primaryUserId(); } virtual QString id() const { return pub.keyId(); } virtual QString storeId() const { return _storeId; } virtual QString storeName() const { return _storeName; } virtual PGPKey pgpSecretKey() const { return sec; } virtual PGPKey pgpPublicKey() const { return pub; } virtual QString serialize() const { // we only serialize the key id. this means the keyring // must be available to restore the data QStringList out; out += escape_string("qca-gnupg-1"); out += escape_string(pub.keyId()); return out.join(":"); } }; // since keyring files are often modified by creating a new copy and // overwriting the original file, this messes up Qt's file watching // capability since the original file goes away. to work around this // problem, we'll watch the directories containing the keyring files // instead of watching the actual files themselves. // // FIXME: qca 2.0.1 FileWatch has this logic already, so we can probably // simplify this class. class RingWatch : public QObject { Q_OBJECT public: class DirItem { public: DirWatch *dirWatch; SafeTimer *changeTimer; }; class FileItem { public: DirWatch *dirWatch; QString fileName; bool exists; qint64 size; QDateTime lastModified; }; QList dirs; QList files; RingWatch(QObject *parent = 0) : QObject(parent) { } ~RingWatch() { clear(); } void add(const QString &filePath) { QFileInfo fi(filePath); QString path = fi.absolutePath(); // watching this path already? DirWatch *dirWatch = 0; foreach(const DirItem &di, dirs) { if(di.dirWatch->dirName() == path) { dirWatch = di.dirWatch; break; } } // if not, make a watcher if(!dirWatch) { //printf("creating dirwatch for [%s]\n", qPrintable(path)); DirItem di; di.dirWatch = new DirWatch(path, this); connect(di.dirWatch, SIGNAL(changed()), SLOT(dirChanged())); if(qcaVersion() == 0x020000) hack_fix(di.dirWatch); di.changeTimer = new SafeTimer(this); di.changeTimer->setSingleShot(true); connect(di.changeTimer, SIGNAL(timeout()), SLOT(handleChanged())); dirWatch = di.dirWatch; dirs += di; } FileItem i; i.dirWatch = dirWatch; i.fileName = fi.fileName(); i.exists = fi.exists(); if(i.exists) { i.size = fi.size(); i.lastModified = fi.lastModified(); } files += i; //printf("watching [%s] in [%s]\n", qPrintable(fi.fileName()), qPrintable(i.dirWatch->dirName())); } void clear() { files.clear(); foreach(const DirItem &di, dirs) { delete di.changeTimer; delete di.dirWatch; } dirs.clear(); } signals: void changed(const QString &filePath); private slots: void dirChanged() { DirWatch *dirWatch = (DirWatch *)sender(); int at = -1; for(int n = 0; n < dirs.count(); ++n) { if(dirs[n].dirWatch == dirWatch) { at = n; break; } } if(at == -1) return; // we get a ton of change notifications for the dir when // something happens.. let's collect them and only // report after 100ms if(!dirs[at].changeTimer->isActive()) dirs[at].changeTimer->start(100); } void handleChanged() { SafeTimer *t = (SafeTimer *)sender(); int at = -1; for(int n = 0; n < dirs.count(); ++n) { if(dirs[n].changeTimer == t) { at = n; break; } } if(at == -1) return; DirWatch *dirWatch = dirs[at].dirWatch; QString dir = dirWatch->dirName(); // see which files changed QStringList changeList; for(int n = 0; n < files.count(); ++n) { FileItem &i = files[n]; QString filePath = dir + '/' + i.fileName; QFileInfo fi(filePath); // if the file didn't exist, and still doesn't, skip if(!i.exists && !fi.exists()) continue; // size/lastModified should only get checked here if // the file existed and still exists if(fi.exists() != i.exists || fi.size() != i.size || fi.lastModified() != i.lastModified) { changeList += filePath; i.exists = fi.exists(); if(i.exists) { i.size = fi.size(); i.lastModified = fi.lastModified(); } } } foreach(const QString &s, changeList) emit changed(s); } }; class MyKeyStoreList : public KeyStoreListContext { Q_OBJECT public: int init_step; bool initialized; GpgOp gpg; GpgOp::KeyList pubkeys, seckeys; QString pubring, secring; bool pubdirty, secdirty; RingWatch ringWatch; QMutex ringMutex; MyKeyStoreList(Provider *p) : KeyStoreListContext(p), initialized(false), gpg(find_bin(), this), pubdirty(false), secdirty(false), ringWatch(this) { QMutexLocker locker(ksl_mutex()); keyStoreList = this; connect(&gpg, SIGNAL(finished()), SLOT(gpg_finished())); connect(&ringWatch, SIGNAL(changed(const QString &)), SLOT(ring_changed(const QString &))); } ~MyKeyStoreList() { QMutexLocker locker(ksl_mutex()); keyStoreList = 0; } virtual Provider::Context *clone() const { return 0; } static MyKeyStoreList *instance() { QMutexLocker locker(ksl_mutex()); return keyStoreList; } void ext_keyStoreLog(const QString &str) { if(str.isEmpty()) return; // FIXME: collect and emit in one pass QMetaObject::invokeMethod(this, "diagnosticText", Qt::QueuedConnection, Q_ARG(QString, str)); } virtual void start() { // kick start our init procedure: // ensure gpg is installed // obtain keyring file names for monitoring // cache initial keyrings init_step = 0; gpg.doCheck(); } virtual QList keyStores() { // we just support one fixed keyring, if any QList list; if(initialized) list += 0; return list; } virtual KeyStore::Type type(int) const { return KeyStore::PGPKeyring; } virtual QString storeId(int) const { return "qca-gnupg"; } virtual QString name(int) const { return "GnuPG Keyring"; } virtual QList entryTypes(int) const { QList list; list += KeyStoreEntry::TypePGPSecretKey; list += KeyStoreEntry::TypePGPPublicKey; return list; } virtual QList entryList(int) { QMutexLocker locker(&ringMutex); QList out; foreach(const GpgOp::Key &pkey, pubkeys) { PGPKey pub, sec; QString id = pkey.keyItems.first().id; MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); // not secret, in keyring kc->set(pkey, false, true, pkey.isTrusted); pub.change(kc); // optional sec = getSecKey(id, pkey.userIds); MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider()); c->_storeId = storeId(0); c->_storeName = name(0); out.append(c); } return out; } virtual KeyStoreEntryContext *entry(int, const QString &entryId) { QMutexLocker locker(&ringMutex); PGPKey pub = getPubKey(entryId); if(pub.isNull()) return 0; // optional PGPKey sec = getSecKey(entryId, static_cast(pub.context())->_props.userIds); MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider()); c->_storeId = storeId(0); c->_storeName = name(0); return c; } virtual KeyStoreEntryContext *entryPassive(const QString &serialized) { QMutexLocker locker(&ringMutex); QStringList parts = serialized.split(':'); if(parts.count() < 2) return 0; if(unescape_string(parts[0]) != "qca-gnupg-1") return 0; QString entryId = unescape_string(parts[1]); if(entryId.isEmpty()) return 0; PGPKey pub = getPubKey(entryId); if(pub.isNull()) return 0; // optional PGPKey sec = getSecKey(entryId, static_cast(pub.context())->_props.userIds); MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider()); c->_storeId = storeId(0); c->_storeName = name(0); return c; } // TODO: cache should reflect this change immediately virtual QString writeEntry(int, const PGPKey &key) { const MyPGPKeyContext *kc = static_cast(key.context()); QByteArray buf = kc->toBinary(); GpgOp gpg(find_bin()); gpg.doImport(buf); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); if(!gpg.success()) return QString(); return kc->_props.keyId; } // TODO: cache should reflect this change immediately virtual bool removeEntry(int, const QString &entryId) { ringMutex.lock(); PGPKey pub = getPubKey(entryId); ringMutex.unlock(); const MyPGPKeyContext *kc = static_cast(pub.context()); QString fingerprint = kc->_props.fingerprint; GpgOp gpg(find_bin()); gpg.doDeleteKey(fingerprint); gpg_waitForFinished(&gpg); gpg_keyStoreLog(gpg.readDiagnosticText()); return gpg.success(); } // internal PGPKey getPubKey(const QString &keyId) const { int at = -1; for(int n = 0; n < pubkeys.count(); ++n) { if(pubkeys[n].keyItems.first().id == keyId) { at = n; break; } } if(at == -1) return PGPKey(); const GpgOp::Key &pkey = pubkeys[at]; PGPKey pub; MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); // not secret, in keyring kc->set(pkey, false, true, pkey.isTrusted); pub.change(kc); return pub; } // internal PGPKey getSecKey(const QString &keyId, const QStringList &userIdsOverride) const { Q_UNUSED(userIdsOverride); int at = -1; for(int n = 0; n < seckeys.count(); ++n) { if(seckeys[n].keyItems.first().id == keyId) { at = n; break; } } if(at == -1) return PGPKey(); const GpgOp::Key &skey = seckeys[at]; PGPKey sec; MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); // secret, in keyring, trusted kc->set(skey, true, true, true); //kc->_props.userIds = userIdsOverride; sec.change(kc); return sec; } PGPKey publicKeyFromId(const QString &keyId) { QMutexLocker locker(&ringMutex); int at = -1; for(int n = 0; n < pubkeys.count(); ++n) { const GpgOp::Key &pkey = pubkeys[n]; for(int k = 0; k < pkey.keyItems.count(); ++k) { const GpgOp::KeyItem &ki = pkey.keyItems[k]; if(ki.id == keyId) { at = n; break; } } if(at != -1) break; } if(at == -1) return PGPKey(); const GpgOp::Key &pkey = pubkeys[at]; PGPKey pub; MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); // not secret, in keyring kc->set(pkey, false, true, pkey.isTrusted); pub.change(kc); return pub; } PGPKey secretKeyFromId(const QString &keyId) { QMutexLocker locker(&ringMutex); int at = -1; for(int n = 0; n < seckeys.count(); ++n) { const GpgOp::Key &skey = seckeys[n]; for(int k = 0; k < skey.keyItems.count(); ++k) { const GpgOp::KeyItem &ki = skey.keyItems[k]; if(ki.id == keyId) { at = n; break; } } if(at != -1) break; } if(at == -1) return PGPKey(); const GpgOp::Key &skey = seckeys[at]; PGPKey sec; MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); // secret, in keyring, trusted kc->set(skey, true, true, true); sec.change(kc); return sec; } private slots: void gpg_finished() { gpg_keyStoreLog(gpg.readDiagnosticText()); if(!initialized) { // any steps that fail during init, just give up completely if(!gpg.success()) { ringWatch.clear(); emit busyEnd(); return; } // check if(init_step == 0) { // obtain keyring file names for monitoring init_step = 1; gpg.doSecretKeyringFile(); } // secret keyring filename else if(init_step == 1) { secring = QFileInfo(gpg.keyringFile()).canonicalFilePath(); if(qt_buggy_fsw()) fprintf(stderr, "qca-gnupg: disabling keyring monitoring in Qt version < 4.3.5 or 4.4.1\n"); if(!secring.isEmpty()) { if(!qt_buggy_fsw()) ringWatch.add(secring); } // obtain keyring file names for monitoring init_step = 2; gpg.doPublicKeyringFile(); } // public keyring filename else if(init_step == 2) { pubring = QFileInfo(gpg.keyringFile()).canonicalFilePath(); if(!pubring.isEmpty()) { if(!qt_buggy_fsw()) ringWatch.add(pubring); } // cache initial keyrings init_step = 3; gpg.doSecretKeys(); } else if(init_step == 3) { ringMutex.lock(); seckeys = gpg.keys(); ringMutex.unlock(); // cache initial keyrings init_step = 4; gpg.doPublicKeys(); } else if(init_step == 4) { ringMutex.lock(); pubkeys = gpg.keys(); ringMutex.unlock(); initialized = true; handleDirtyRings(); emit busyEnd(); } } else { if(!gpg.success()) return; GpgOp::Type op = gpg.op(); if(op == GpgOp::SecretKeys) { ringMutex.lock(); seckeys = gpg.keys(); ringMutex.unlock(); secdirty = false; } else if(op == GpgOp::PublicKeys) { ringMutex.lock(); pubkeys = gpg.keys(); ringMutex.unlock(); pubdirty = false; } if(!secdirty && !pubdirty) { emit storeUpdated(0); return; } handleDirtyRings(); } } void ring_changed(const QString &filePath) { ext_keyStoreLog(QString("ring_changed: [%1]\n").arg(filePath)); if(filePath == secring) sec_changed(); else if(filePath == pubring) pub_changed(); } private: void pub_changed() { pubdirty = true; handleDirtyRings(); } void sec_changed() { secdirty = true; handleDirtyRings(); } void handleDirtyRings() { if(!initialized || gpg.isActive()) return; if(secdirty) gpg.doSecretKeys(); else if(pubdirty) gpg.doPublicKeys(); } }; static void gpg_keyStoreLog(const QString &str) { MyKeyStoreList *ksl = MyKeyStoreList::instance(); if(ksl) ksl->ext_keyStoreLog(str); } static PGPKey publicKeyFromId(const QString &id) { MyKeyStoreList *ksl = MyKeyStoreList::instance(); if(!ksl) return PGPKey(); return ksl->publicKeyFromId(id); } static PGPKey secretKeyFromId(const QString &id) { MyKeyStoreList *ksl = MyKeyStoreList::instance(); if(!ksl) return PGPKey(); return ksl->secretKeyFromId(id); } class MyOpenPGPContext : public SMSContext { public: MyOpenPGPContext(Provider *p) : SMSContext(p, "openpgp") { // TODO } virtual Provider::Context *clone() const { return 0; } virtual MessageContext *createMessage(); }; class MyMessageContext : public MessageContext { Q_OBJECT public: MyOpenPGPContext *sms; QString signerId; QStringList recipIds; Operation op; SecureMessage::SignMode signMode; SecureMessage::Format format; QByteArray in, out, sig; int wrote; bool ok, wasSigned; GpgOp::Error op_err; SecureMessageSignature signer; GpgOp gpg; bool _finished; QString dtext; PasswordAsker asker; TokenAsker tokenAsker; MyMessageContext(MyOpenPGPContext *_sms, Provider *p) : MessageContext(p, "pgpmsg"), gpg(find_bin()) { sms = _sms; wrote = 0; ok = false; wasSigned = false; connect(&gpg, SIGNAL(readyRead()), SLOT(gpg_readyRead())); connect(&gpg, SIGNAL(bytesWritten(int)), SLOT(gpg_bytesWritten(int))); connect(&gpg, SIGNAL(finished()), SLOT(gpg_finished())); connect(&gpg, SIGNAL(needPassphrase(const QString &)), SLOT(gpg_needPassphrase(const QString &))); connect(&gpg, SIGNAL(needCard()), SLOT(gpg_needCard())); connect(&gpg, SIGNAL(readyReadDiagnosticText()), SLOT(gpg_readyReadDiagnosticText())); connect(&asker, SIGNAL(responseReady()), SLOT(asker_responseReady())); connect(&tokenAsker, SIGNAL(responseReady()), SLOT(tokenAsker_responseReady())); } virtual Provider::Context *clone() const { return 0; } virtual bool canSignMultiple() const { return false; } virtual SecureMessage::Type type() const { return SecureMessage::OpenPGP; } virtual void reset() { wrote = 0; ok = false; wasSigned = false; } virtual void setupEncrypt(const SecureMessageKeyList &keys) { recipIds.clear(); for(int n = 0; n < keys.count(); ++n) recipIds += keys[n].pgpPublicKey().keyId(); } virtual void setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool, bool) { signerId = keys.first().pgpSecretKey().keyId(); signMode = m; } virtual void setupVerify(const QByteArray &detachedSig) { sig = detachedSig; } virtual void start(SecureMessage::Format f, Operation op) { _finished = false; format = f; this->op = op; if(getProperty("pgp-always-trust").toBool()) gpg.setAlwaysTrust(true); if(format == SecureMessage::Ascii) gpg.setAsciiFormat(true); else gpg.setAsciiFormat(false); if(op == Encrypt) { gpg.doEncrypt(recipIds); } else if(op == Decrypt) { gpg.doDecrypt(); } else if(op == Sign) { if(signMode == SecureMessage::Message) { gpg.doSign(signerId); } else if(signMode == SecureMessage::Clearsign) { gpg.doSignClearsign(signerId); } else // SecureMessage::Detached { gpg.doSignDetached(signerId); } } else if(op == Verify) { if(!sig.isEmpty()) gpg.doVerifyDetached(sig); else gpg.doDecrypt(); } else if(op == SignAndEncrypt) { gpg.doSignAndEncrypt(signerId, recipIds); } } virtual void update(const QByteArray &in) { gpg.write(in); //this->in.append(in); } virtual QByteArray read() { QByteArray a = out; out.clear(); return a; } virtual int written() { int x = wrote; wrote = 0; return x; } virtual void end() { gpg.endWrite(); } void seterror() { gpg.reset(); _finished = true; ok = false; op_err = GpgOp::ErrorUnknown; } void complete() { _finished = true; dtext = gpg.readDiagnosticText(); ok = gpg.success(); if(ok) { if(op == Sign && signMode == SecureMessage::Detached) sig = gpg.read(); else out = gpg.read(); } if(ok) { if(gpg.wasSigned()) { QString signerId = gpg.signerId(); QDateTime ts = gpg.timestamp(); GpgOp::VerifyResult vr = gpg.verifyResult(); SecureMessageSignature::IdentityResult ir; Validity v; if(vr == GpgOp::VerifyGood) { ir = SecureMessageSignature::Valid; v = ValidityGood; } else if(vr == GpgOp::VerifyBad) { ir = SecureMessageSignature::InvalidSignature; v = ValidityGood; // good key, bad sig } else // GpgOp::VerifyNoKey { ir = SecureMessageSignature::NoKey; v = ErrorValidityUnknown; } SecureMessageKey key; PGPKey pub = publicKeyFromId(signerId); if(pub.isNull()) { MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); kc->_props.keyId = signerId; pub.change(kc); } key.setPGPPublicKey(pub); signer = SecureMessageSignature(ir, v, key, ts); wasSigned = true; } } else op_err = gpg.errorCode(); } virtual bool finished() const { return _finished; } virtual bool waitForFinished(int msecs) { // FIXME Q_UNUSED(msecs); while(1) { // TODO: handle token prompt events GpgOp::Event e = gpg.waitForEvent(-1); if(e.type == GpgOp::Event::NeedPassphrase) { // TODO QString keyId; PGPKey sec = secretKeyFromId(e.keyId); if(!sec.isNull()) keyId = sec.keyId(); else keyId = e.keyId; QStringList out; out += escape_string("qca-gnupg-1"); out += escape_string(keyId); QString serialized = out.join(":"); KeyStoreEntry kse; KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized); if(c) kse.change(c); asker.ask(Event::StylePassphrase, KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), kse, 0); asker.waitForResponse(); if(!asker.accepted()) { seterror(); return true; } gpg.submitPassphrase(asker.password()); } else if(e.type == GpgOp::Event::NeedCard) { tokenAsker.ask(KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), KeyStoreEntry(), 0); if(!tokenAsker.accepted()) { seterror(); return true; } gpg.cardOkay(); } else if(e.type == GpgOp::Event::Finished) break; } complete(); return true; } virtual bool success() const { return ok; } virtual SecureMessage::Error errorCode() const { SecureMessage::Error e = SecureMessage::ErrorUnknown; if(op_err == GpgOp::ErrorProcess) e = SecureMessage::ErrorUnknown; else if(op_err == GpgOp::ErrorPassphrase) e = SecureMessage::ErrorPassphrase; else if(op_err == GpgOp::ErrorFormat) e = SecureMessage::ErrorFormat; else if(op_err == GpgOp::ErrorSignerExpired) e = SecureMessage::ErrorSignerExpired; else if(op_err == GpgOp::ErrorEncryptExpired) e = SecureMessage::ErrorEncryptExpired; else if(op_err == GpgOp::ErrorEncryptUntrusted) e = SecureMessage::ErrorEncryptUntrusted; else if(op_err == GpgOp::ErrorEncryptInvalid) e = SecureMessage::ErrorEncryptInvalid; else if(op_err == GpgOp::ErrorDecryptNoKey) e = SecureMessage::ErrorUnknown; else if(op_err == GpgOp::ErrorUnknown) e = SecureMessage::ErrorUnknown; return e; } virtual QByteArray signature() const { return sig; } virtual QString hashName() const { // TODO return "sha1"; } virtual SecureMessageSignatureList signers() const { SecureMessageSignatureList list; if(ok && wasSigned) list += signer; return list; } virtual QString diagnosticText() const { return dtext; } private slots: void gpg_readyRead() { emit updated(); } void gpg_bytesWritten(int bytes) { wrote += bytes; } void gpg_finished() { complete(); emit updated(); } void gpg_needPassphrase(const QString &in_keyId) { // FIXME: copied from above, clean up later QString keyId; PGPKey sec = secretKeyFromId(in_keyId); if(!sec.isNull()) keyId = sec.keyId(); else keyId = in_keyId; //emit keyStoreList->storeNeedPassphrase(0, 0, keyId); QStringList out; out += escape_string("qca-gnupg-1"); out += escape_string(keyId); QString serialized = out.join(":"); KeyStoreEntry kse; KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized); if(c) kse.change(c); asker.ask(Event::StylePassphrase, KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), kse, 0); } void gpg_needCard() { tokenAsker.ask(KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), KeyStoreEntry(), 0); } void gpg_readyReadDiagnosticText() { // TODO ? } void asker_responseReady() { if(!asker.accepted()) { seterror(); emit updated(); return; } SecureArray a = asker.password(); gpg.submitPassphrase(a); } void tokenAsker_responseReady() { if(!tokenAsker.accepted()) { seterror(); emit updated(); return; } gpg.cardOkay(); } }; MessageContext *MyOpenPGPContext::createMessage() { return new MyMessageContext(this, provider()); } } using namespace gpgQCAPlugin; class gnupgProvider : public QCA::Provider { public: virtual void init() { } virtual int qcaVersion() const { return QCA_VERSION; } virtual QString name() const { return "qca-gnupg"; } virtual QStringList features() const { QStringList list; list += "pgpkey"; list += "openpgp"; list += "keystorelist"; return list; } virtual Context *createContext(const QString &type) { if(type == "pgpkey") return new MyPGPKeyContext(this); else if(type == "openpgp") return new MyOpenPGPContext(this); else if(type == "keystorelist") return new MyKeyStoreList(this); else return 0; } }; class gnupgPlugin : public QObject, public QCAPlugin { Q_OBJECT Q_INTERFACES(QCAPlugin) public: virtual QCA::Provider *createProvider() { return new gnupgProvider; } }; #include "qca-gnupg.moc" Q_EXPORT_PLUGIN2(qca_gnupg, gnupgPlugin) psi-0.14/third-party/qca/qca-gnupg/gpgop.cpp0000644000175000017500000007650011305557613017066 0ustar janjan/* * Copyright (C) 2003-2005 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */ #include "gpgop.h" #include "gpgproc.h" #include namespace gpgQCAPlugin { //---------------------------------------------------------------------------- // LineConverter //---------------------------------------------------------------------------- class LineConverter { public: enum Mode { Read, Write }; void setup(Mode m) { state = Normal; mode = m; #ifdef Q_OS_WIN write_conv = true; #else write_conv = false; #endif prebytes = 0; list.clear(); } QByteArray update(const QByteArray &buf) { if(mode == Read) { QByteArray out; if(state == Normal) { out = buf; } else { out.resize(buf.size() + 1); out[0] = '\r'; memcpy(out.data() + 1, buf.data(), buf.size()); } int n = 0; while(1) { n = out.indexOf('\r', n); // not found if(n == -1) { break; } // found, not last character if(n < (buf.size() - 1)) { if(out[n + 1] == '\n') { // clip out the '\r' memmove(out.data() + n, out.data() + n + 1, out.size() - n - 1); out.resize(out.size() - 1); } } // found, last character else { state = Partial; break; } ++n; } return out; } else { if(write_conv) { QByteArray out; int prev = 0; int at = 0; while(1) { int n = buf.indexOf('\n', at); if(n == -1) break; int chunksize = n - at; int oldsize = out.size(); out.resize(oldsize + chunksize + 2); memcpy(out.data() + oldsize, buf.data() + at, chunksize); memcpy(out.data() + oldsize + chunksize, "\r\n", 2); list.append(prebytes + n + 1 - prev); prebytes = 0; prev = n; at = n + 1; } if(at < buf.size()) { int chunksize = buf.size() - at; int oldsize = out.size(); out.resize(oldsize + chunksize); memcpy(out.data() + oldsize, buf.data() + at, chunksize); } prebytes += buf.size() - prev; return out; } else return buf; } } QByteArray final() { if(mode == Read) { QByteArray out; if(state == Partial) { out.resize(1); out[0] = '\r'; } return out; } else { return QByteArray(); } } QByteArray process(const QByteArray &buf) { return update(buf) + final(); } int writtenToActual(int bytes) { if(write_conv) { int n = 0; int counter = bytes; while(counter > 0) { if(!list.isEmpty() && bytes >= list.first()) { ++n; counter -= list.takeFirst(); } else { if(list.isEmpty()) prebytes -= counter; else list.first() -= counter; if(prebytes < 0) { bytes += prebytes; prebytes = 0; } break; } } return bytes - n; } else return bytes; } private: enum State { Normal, Partial }; Mode mode; State state; bool write_conv; public: int prebytes; QList list; }; //---------------------------------------------------------------------------- // GpgAction //---------------------------------------------------------------------------- static QDateTime getTimestamp(const QString &s) { if(s.isEmpty()) return QDateTime(); if(s.contains('T')) { return QDateTime::fromString(s, Qt::ISODate); } else { QDateTime dt; dt.setTime_t(s.toInt()); return dt; } } static QByteArray getCString(const QByteArray &a) { QByteArray out; // convert the "backslash" C-string syntax for(int n = 0; n < a.size(); ++n) { if(a[n] == '\\' && n + 1 < a.size()) { ++n; unsigned char c = (unsigned char)a[n]; if(c == '\\') { out += '\\'; } else if(c == 'x' && n + 2 < a.size()) { ++n; QByteArray hex = a.mid(n, 2); ++n; // only skip one, loop will skip the next bool ok; uint val = hex.toInt(&ok, 16); if(ok) { out += (unsigned char)val; } else { out += "\\x"; out += hex; } } } else { out += a[n]; } } return out; } static bool stringToKeyList(const QString &outstr, GpgOp::KeyList *_keylist, QString *_keyring) { GpgOp::KeyList keyList; QStringList lines = outstr.split('\n'); if(lines.count() < 1) return false; QStringList::ConstIterator it = lines.begin(); // first line is keyring file QString keyring = *(it++); // if the second line isn't a divider, we are dealing // with a new version of gnupg that doesn't give us // the keyring file on gpg --list-keys --with-colons if(it == lines.end() || (*it).isEmpty() || (*it).at(0) != '-') { // first line wasn't the keyring name... keyring.clear(); // ...so read the first line again it--; } else { // this was the divider line - skip it it++; } for(; it != lines.end(); ++it) { QStringList f = (*it).split(':'); if(f.count() < 1) continue; QString type = f[0]; bool key = false; // key or not bool primary = false; // primary key or sub key bool sec = false; // private key or not if(type == "pub") { key = true; primary = true; } else if(type == "sec") { key = true; primary = true; sec = true; } else if(type == "sub") { key = true; } else if(type == "ssb") { key = true; sec = true; } if(key) { if(primary) { keyList += GpgOp::Key(); QString trust = f[1]; if(trust == "f" || trust == "u") keyList.last().isTrusted = true; } int key_type = f[3].toInt(); QString caps = f[11]; GpgOp::KeyItem item; item.bits = f[2].toInt(); if(key_type == 1) item.type = GpgOp::KeyItem::RSA; else if(key_type == 16) item.type = GpgOp::KeyItem::ElGamal; else if(key_type == 17) item.type = GpgOp::KeyItem::DSA; else item.type = GpgOp::KeyItem::Unknown; item.id = f[4]; item.creationDate = getTimestamp(f[5]); item.expirationDate = getTimestamp(f[6]); if(caps.contains('e')) item.caps |= GpgOp::KeyItem::Encrypt; if(caps.contains('s')) item.caps |= GpgOp::KeyItem::Sign; if(caps.contains('c')) item.caps |= GpgOp::KeyItem::Certify; if(caps.contains('a')) item.caps |= GpgOp::KeyItem::Auth; keyList.last().keyItems += item; } else if(type == "uid") { QByteArray uid = getCString(f[9].toLatin1()); keyList.last().userIds.append(QString::fromUtf8(uid)); } else if(type == "fpr") { QString s = f[9]; keyList.last().keyItems.last().fingerprint = s; } } if(_keylist) *_keylist = keyList; if(_keyring) *_keyring = keyring; return true; } static bool findKeyringFilename(const QString &outstr, QString *_keyring) { QStringList lines = outstr.split('\n'); if(lines.count() < 1) return false; *_keyring = lines[0]; return true; } class GpgAction : public QObject { Q_OBJECT public: class Input { public: QString bin; GpgOp::Type op; bool opt_ascii, opt_noagent, opt_alwaystrust; QString opt_pubfile, opt_secfile; QStringList recip_ids; QString signer_id; QByteArray sig; QByteArray inkey; QString export_key_id; QString delete_key_fingerprint; Input() : opt_ascii(false), opt_noagent(false), opt_alwaystrust(false) {} }; class Output { public: bool success; GpgOp::Error errorCode; GpgOp::KeyList keys; QString keyringFile; QString encryptedToId; bool wasSigned; QString signerId; QDateTime timestamp; GpgOp::VerifyResult verifyResult; Output() : success(false), errorCode(GpgOp::ErrorUnknown), wasSigned(false) {} }; Input input; Output output; GPGProc proc; bool collectOutput, allowInput; LineConverter readConv, writeConv; bool readText, writeText; QByteArray buf_stdout, buf_stderr; bool useAux; QString passphraseKeyId; bool signing, signPartDone, decryptGood, signGood; GpgOp::Error curError; bool badPassphrase; bool need_submitPassphrase, need_cardOkay; QString diagnosticText; SafeTimer dtextTimer; #ifdef GPG_PROFILE QTime timer; #endif GpgAction(QObject *parent = 0) : QObject(parent), proc(this), dtextTimer(this) { dtextTimer.setSingleShot(true); connect(&proc, SIGNAL(error(gpgQCAPlugin::GPGProc::Error)), SLOT(proc_error(gpgQCAPlugin::GPGProc::Error))); connect(&proc, SIGNAL(finished(int)), SLOT(proc_finished(int))); connect(&proc, SIGNAL(readyReadStdout()), SLOT(proc_readyReadStdout())); connect(&proc, SIGNAL(readyReadStderr()), SLOT(proc_readyReadStderr())); connect(&proc, SIGNAL(readyReadStatusLines()), SLOT(proc_readyReadStatusLines())); connect(&proc, SIGNAL(bytesWrittenStdin(int)), SLOT(proc_bytesWrittenStdin(int))); connect(&proc, SIGNAL(bytesWrittenAux(int)), SLOT(proc_bytesWrittenAux(int))); connect(&proc, SIGNAL(bytesWrittenCommand(int)), SLOT(proc_bytesWrittenCommand(int))); connect(&proc, SIGNAL(debug(const QString &)), SLOT(proc_debug(const QString &))); connect(&dtextTimer, SIGNAL(timeout()), SLOT(t_dtext())); reset(); } ~GpgAction() { reset(); } void reset() { collectOutput = true; allowInput = false; readConv.setup(LineConverter::Read); writeConv.setup(LineConverter::Write); readText = false; writeText = false; useAux = false; passphraseKeyId = QString(); signing = false; signPartDone = false; decryptGood = false; signGood = false; curError = GpgOp::ErrorUnknown; badPassphrase = false; need_submitPassphrase = false; need_cardOkay = false; diagnosticText = QString(); dtextTimer.stop(); output = Output(); proc.reset(); } void start() { reset(); QStringList args; bool extra = false; if(input.opt_ascii) args += "--armor"; if(input.opt_noagent) args += "--no-use-agent"; if(input.opt_alwaystrust) args += "--always-trust"; if(!input.opt_pubfile.isEmpty() && !input.opt_secfile.isEmpty()) { args += "--no-default-keyring"; args += "--keyring"; args += input.opt_pubfile; args += "--secret-keyring"; args += input.opt_secfile; } switch(input.op) { case GpgOp::Check: { args += "--version"; readText = true; break; } case GpgOp::SecretKeyringFile: { args += "--list-secret-keys"; readText = true; break; } case GpgOp::PublicKeyringFile: { args += "--list-public-keys"; readText = true; break; } case GpgOp::SecretKeys: { args += "--fixed-list-mode"; args += "--with-colons"; args += "--with-fingerprint"; args += "--with-fingerprint"; args += "--list-secret-keys"; readText = true; break; } case GpgOp::PublicKeys: { args += "--fixed-list-mode"; args += "--with-colons"; args += "--with-fingerprint"; args += "--with-fingerprint"; args += "--list-public-keys"; readText = true; break; } case GpgOp::Encrypt: { args += "--encrypt"; // recipients for(QStringList::ConstIterator it = input.recip_ids.begin(); it != input.recip_ids.end(); ++it) { args += "--recipient"; args += QString("0x") + *it; } extra = true; collectOutput = false; allowInput = true; if(input.opt_ascii) readText = true; break; } case GpgOp::Decrypt: { args += "--decrypt"; extra = true; collectOutput = false; allowInput = true; if(input.opt_ascii) writeText = true; break; } case GpgOp::Sign: { args += "--default-key"; args += QString("0x") + input.signer_id; args += "--sign"; extra = true; collectOutput = false; allowInput = true; if(input.opt_ascii) readText = true; signing = true; break; } case GpgOp::SignAndEncrypt: { args += "--default-key"; args += QString("0x") + input.signer_id; args += "--sign"; args += "--encrypt"; // recipients for(QStringList::ConstIterator it = input.recip_ids.begin(); it != input.recip_ids.end(); ++it) { args += "--recipient"; args += QString("0x") + *it; } extra = true; collectOutput = false; allowInput = true; if(input.opt_ascii) readText = true; signing = true; break; } case GpgOp::SignClearsign: { args += "--default-key"; args += QString("0x") + input.signer_id; args += "--clearsign"; extra = true; collectOutput = false; allowInput = true; if(input.opt_ascii) readText = true; signing = true; break; } case GpgOp::SignDetached: { args += "--default-key"; args += QString("0x") + input.signer_id; args += "--detach-sign"; extra = true; collectOutput = false; allowInput = true; if(input.opt_ascii) readText = true; signing = true; break; } case GpgOp::Verify: { args += "--verify"; args += "-"; //krazy:exclude=doublequote_chars extra = true; allowInput = true; if(input.opt_ascii) writeText = true; break; } case GpgOp::VerifyDetached: { args += "--verify"; args += "-"; //krazy:exclude=doublequote_chars args += "-&?"; extra = true; allowInput = true; useAux = true; break; } case GpgOp::Import: { args += "--import"; readText = true; if(input.opt_ascii) writeText = true; break; } case GpgOp::Export: { args += "--export"; args += QString("0x") + input.export_key_id; collectOutput = false; if(input.opt_ascii) readText = true; break; } case GpgOp::DeleteKey: { args += "--batch"; args += "--delete-key"; args += QString("0x") + input.delete_key_fingerprint; break; } } #ifdef GPG_PROFILE timer.start(); printf("<< launch >>\n"); #endif proc.start(input.bin, args, extra ? GPGProc::ExtendedMode : GPGProc::NormalMode); // detached sig if(input.op == GpgOp::VerifyDetached) { QByteArray a = input.sig; if(input.opt_ascii) { LineConverter conv; conv.setup(LineConverter::Write); a = conv.process(a); } proc.writeStdin(a); proc.closeStdin(); } // import if(input.op == GpgOp::Import) { QByteArray a = input.inkey; if(writeText) { LineConverter conv; conv.setup(LineConverter::Write); a = conv.process(a); } proc.writeStdin(a); proc.closeStdin(); } } #ifdef QPIPE_SECURE void submitPassphrase(const QCA::SecureArray &a) #else void submitPassphrase(const QByteArray &a) #endif { if(!need_submitPassphrase) return; need_submitPassphrase = false; #ifdef QPIPE_SECURE QCA::SecureArray b; #else QByteArray b; #endif // filter out newlines, since that's the delimiter used // to indicate a submitted passphrase b.resize(a.size()); int at = 0; for(int n = 0; n < a.size(); ++n) { if(a[n] != '\n') b[at++] = a[n]; } b.resize(at); // append newline b.resize(b.size() + 1); b[b.size() - 1] = '\n'; proc.writeCommand(b); } public slots: QByteArray read() { if(collectOutput) return QByteArray(); QByteArray a = proc.readStdout(); if(readText) a = readConv.update(a); if(!proc.isActive()) a += readConv.final(); return a; } void write(const QByteArray &in) { if(!allowInput) return; QByteArray a = in; if(writeText) a = writeConv.update(in); if(useAux) proc.writeAux(a); else proc.writeStdin(a); } void endWrite() { if(!allowInput) return; if(useAux) proc.closeAux(); else proc.closeStdin(); } void cardOkay() { if(need_cardOkay) { need_cardOkay = false; submitCommand("\n"); } } QString readDiagnosticText() { QString s = diagnosticText; diagnosticText = QString(); return s; } signals: void readyRead(); void bytesWritten(int bytes); void finished(); void needPassphrase(const QString &keyId); void needCard(); void readyReadDiagnosticText(); private: void submitCommand(const QByteArray &a) { proc.writeCommand(a); } // since str is taken as a value, it is ok to use the same variable for 'rest' QString nextArg(QString str, QString *rest = 0) { QString out; int n = str.indexOf(' '); if(n == -1) { if(rest) *rest = QString(); return str; } else { if(rest) *rest = str.mid(n + 1); return str.mid(0, n); } } void processStatusLine(const QString &line) { diagnosticText += QString("{") + line + "}\n"; ensureDTextEmit(); if(!proc.isActive()) return; QString s, rest; s = nextArg(line, &rest); if(s == "NODATA") { // only set this if it'll make it better if(curError == GpgOp::ErrorUnknown) curError = GpgOp::ErrorFormat; } else if(s == "UNEXPECTED") { if(curError == GpgOp::ErrorUnknown) curError = GpgOp::ErrorFormat; } else if(s == "KEYEXPIRED") { if(curError == GpgOp::ErrorUnknown) { if(input.op == GpgOp::SignAndEncrypt) { if(!signPartDone) curError = GpgOp::ErrorSignerExpired; else curError = GpgOp::ErrorEncryptExpired; } else { if(signing) curError = GpgOp::ErrorSignerExpired; else curError = GpgOp::ErrorEncryptExpired; } } } else if(s == "INV_RECP") { int r = nextArg(rest).toInt(); if(curError == GpgOp::ErrorUnknown) { if(r == 10) curError = GpgOp::ErrorEncryptUntrusted; else curError = GpgOp::ErrorEncryptInvalid; } } else if(s == "NO_SECKEY") { output.encryptedToId = nextArg(rest); if(curError == GpgOp::ErrorUnknown) curError = GpgOp::ErrorDecryptNoKey; } else if(s == "DECRYPTION_OKAY") { decryptGood = true; // message could be encrypted with several keys if(curError == GpgOp::ErrorDecryptNoKey) curError = GpgOp::ErrorUnknown; } else if(s == "SIG_CREATED") { signGood = true; } else if(s == "USERID_HINT") { passphraseKeyId = nextArg(rest); } else if(s == "GET_HIDDEN") { QString arg = nextArg(rest); if(arg == "passphrase.enter" || arg == "passphrase.pin.ask") { need_submitPassphrase = true; // for signal-safety, emit later QMetaObject::invokeMethod(this, "needPassphrase", Qt::QueuedConnection, Q_ARG(QString, passphraseKeyId)); } } else if(s == "GET_LINE") { QString arg = nextArg(rest); if(arg == "cardctrl.insert_card.okay") { need_cardOkay = true; QMetaObject::invokeMethod(this, "needCard", Qt::QueuedConnection); } } else if(s == "GET_BOOL") { QString arg = nextArg(rest); if(arg == "untrusted_key.override") submitCommand("no\n"); } else if(s == "GOOD_PASSPHRASE") { badPassphrase = false; // a trick to determine what KEYEXPIRED should apply to signPartDone = true; } else if(s == "BAD_PASSPHRASE") { badPassphrase = true; } else if(s == "GOODSIG") { output.wasSigned = true; output.signerId = nextArg(rest); output.verifyResult = GpgOp::VerifyGood; } else if(s == "BADSIG") { output.wasSigned = true; output.signerId = nextArg(rest); output.verifyResult = GpgOp::VerifyBad; } else if(s == "ERRSIG") { output.wasSigned = true; QStringList list = rest.split(' ', QString::SkipEmptyParts); output.signerId = list[0]; output.timestamp = getTimestamp(list[4]); output.verifyResult = GpgOp::VerifyNoKey; } else if(s == "VALIDSIG") { QStringList list = rest.split(' ', QString::SkipEmptyParts); output.timestamp = getTimestamp(list[2]); } } void processResult(int code) { #ifdef GPG_PROFILE printf("<< launch: %d >>\n", timer.elapsed()); #endif // put stdout and stderr into QStrings QString outstr = QString::fromLatin1(buf_stdout); QString errstr = QString::fromLatin1(buf_stderr); if(collectOutput) diagnosticText += QString("stdout: [%1]\n").arg(outstr); diagnosticText += QString("stderr: [%1]\n").arg(errstr); ensureDTextEmit(); if(badPassphrase) { output.errorCode = GpgOp::ErrorPassphrase; } else if(curError != GpgOp::ErrorUnknown) { output.errorCode = curError; } else if(code == 0) { if(input.op == GpgOp::SecretKeyringFile || input.op == GpgOp::PublicKeyringFile) { if(findKeyringFilename(outstr, &output.keyringFile)) output.success = true; } else if(input.op == GpgOp::SecretKeys || input.op == GpgOp::PublicKeys) { if(stringToKeyList(outstr, &output.keys, &output.keyringFile)) output.success = true; } else output.success = true; } else { // decrypt and sign success based on status only. // this is mainly because gpg uses fatal return // values if there is trouble with gpg-agent, even // though the operation otherwise works. if(input.op == GpgOp::Decrypt && decryptGood) output.success = true; if(signing && signGood) output.success = true; // gpg will indicate failure for bad sigs, but we don't // consider this to be operation failure. bool signedMakesItGood = false; if(input.op == GpgOp::Verify || input.op == GpgOp::VerifyDetached) signedMakesItGood = true; if(signedMakesItGood && output.wasSigned) output.success = true; } emit finished(); } void ensureDTextEmit() { if(!dtextTimer.isActive()) dtextTimer.start(); } private slots: void t_dtext() { emit readyReadDiagnosticText(); } void proc_error(gpgQCAPlugin::GPGProc::Error e) { QString str; if(e == GPGProc::FailedToStart) str = "FailedToStart"; else if(e == GPGProc::UnexpectedExit) str = "UnexpectedExit"; else if(e == GPGProc::ErrorWrite) str = "ErrorWrite"; diagnosticText += QString("GPG Process Error: %1\n").arg(str); ensureDTextEmit(); output.errorCode = GpgOp::ErrorProcess; emit finished(); } void proc_finished(int exitCode) { diagnosticText += QString("GPG Process Finished: exitStatus=%1\n").arg(exitCode); ensureDTextEmit(); processResult(exitCode); } void proc_readyReadStdout() { if(collectOutput) { QByteArray a = proc.readStdout(); if(readText) a = readConv.update(a); buf_stdout.append(a); } else emit readyRead(); } void proc_readyReadStderr() { buf_stderr.append(proc.readStderr()); } void proc_readyReadStatusLines() { QStringList lines = proc.readStatusLines(); for(int n = 0; n < lines.count(); ++n) processStatusLine(lines[n]); } void proc_bytesWrittenStdin(int bytes) { if(!useAux) { int actual = writeConv.writtenToActual(bytes); emit bytesWritten(actual); } } void proc_bytesWrittenAux(int bytes) { if(useAux) { int actual = writeConv.writtenToActual(bytes); emit bytesWritten(actual); } } void proc_bytesWrittenCommand(int) { // don't care about this } void proc_debug(const QString &str) { diagnosticText += "GPGProc: " + str + '\n'; ensureDTextEmit(); } }; //---------------------------------------------------------------------------- // GpgOp //---------------------------------------------------------------------------- enum ResetMode { ResetSession = 0, ResetSessionAndData = 1, ResetAll = 2 }; class GpgOp::Private : public QObject { Q_OBJECT public: QCA::Synchronizer sync; GpgOp *q; GpgAction *act; QString bin; GpgOp::Type op; GpgAction::Output output; QByteArray result; QString diagnosticText; QList eventList; bool waiting; bool opt_ascii, opt_noagent, opt_alwaystrust; QString opt_pubfile, opt_secfile; #ifdef GPG_PROFILE QTime timer; #endif Private(GpgOp *_q) : QObject(_q), sync(_q), q(_q) { act = 0; waiting = false; reset(ResetAll); } ~Private() { reset(ResetAll); } void reset(ResetMode mode) { if(act) { releaseAndDeleteLater(this, act); act = 0; } if(mode >= ResetSessionAndData) { output = GpgAction::Output(); result.clear(); diagnosticText = QString(); eventList.clear(); } if(mode >= ResetAll) { opt_ascii = false; opt_noagent = false; opt_alwaystrust = false; opt_pubfile = QString(); opt_secfile = QString(); } } void make_act(GpgOp::Type _op) { reset(ResetSessionAndData); op = _op; act = new GpgAction(this); connect(act, SIGNAL(readyRead()), SLOT(act_readyRead())); connect(act, SIGNAL(bytesWritten(int)), SLOT(act_bytesWritten(int))); connect(act, SIGNAL(needPassphrase(const QString &)), SLOT(act_needPassphrase(const QString &))); connect(act, SIGNAL(needCard()), SLOT(act_needCard())); connect(act, SIGNAL(finished()), SLOT(act_finished())); connect(act, SIGNAL(readyReadDiagnosticText()), SLOT(act_readyReadDiagnosticText())); act->input.bin = bin; act->input.op = op; act->input.opt_ascii = opt_ascii; act->input.opt_noagent = opt_noagent; act->input.opt_alwaystrust = opt_alwaystrust; act->input.opt_pubfile = opt_pubfile; act->input.opt_secfile = opt_secfile; } void eventReady(const GpgOp::Event &e) { eventList += e; sync.conditionMet(); } void eventReady(GpgOp::Event::Type type) { GpgOp::Event e; e.type = type; eventReady(e); } void eventReady(GpgOp::Event::Type type, int written) { GpgOp::Event e; e.type = type; e.written = written; eventReady(e); } void eventReady(GpgOp::Event::Type type, const QString &keyId) { GpgOp::Event e; e.type = type; e.keyId = keyId; eventReady(e); } public slots: void act_readyRead() { if(waiting) eventReady(GpgOp::Event::ReadyRead); else emit q->readyRead(); } void act_bytesWritten(int bytes) { if(waiting) eventReady(GpgOp::Event::BytesWritten, bytes); else emit q->bytesWritten(bytes); } void act_needPassphrase(const QString &keyId) { if(waiting) eventReady(GpgOp::Event::NeedPassphrase, keyId); else emit q->needPassphrase(keyId); } void act_needCard() { if(waiting) eventReady(GpgOp::Event::NeedCard); else emit q->needCard(); } void act_readyReadDiagnosticText() { QString s = act->readDiagnosticText(); //printf("dtext ready: [%s]\n", qPrintable(s)); diagnosticText += s; if(waiting) eventReady(GpgOp::Event::ReadyReadDiagnosticText); else emit q->readyReadDiagnosticText(); } void act_finished() { #ifdef GPG_PROFILE if(op == GpgOp::Encrypt) printf("<< doEncrypt: %d >>\n", timer.elapsed()); #endif result = act->read(); diagnosticText += act->readDiagnosticText(); output = act->output; QMap errmap; errmap[GpgOp::ErrorProcess] = "ErrorProcess"; errmap[GpgOp::ErrorPassphrase] = "ErrorPassphrase"; errmap[GpgOp::ErrorFormat] = "ErrorFormat"; errmap[GpgOp::ErrorSignerExpired] = "ErrorSignerExpired"; errmap[GpgOp::ErrorEncryptExpired] = "ErrorEncryptExpired"; errmap[GpgOp::ErrorEncryptUntrusted] = "ErrorEncryptUntrusted"; errmap[GpgOp::ErrorEncryptInvalid] = "ErrorEncryptInvalid"; errmap[GpgOp::ErrorDecryptNoKey] = "ErrorDecryptNoKey"; errmap[GpgOp::ErrorUnknown] = "ErrorUnknown"; if(output.success) diagnosticText += "GpgAction success\n"; else diagnosticText += QString("GpgAction error: %1\n").arg(errmap[output.errorCode]); if(output.wasSigned) { QString s; if(output.verifyResult == GpgOp::VerifyGood) s = "VerifyGood"; else if(output.verifyResult == GpgOp::VerifyBad) s = "VerifyBad"; else s = "VerifyNoKey"; diagnosticText += QString("wasSigned: verifyResult: %1\n").arg(s); } //printf("diagnosticText:\n%s", qPrintable(diagnosticText)); reset(ResetSession); if(waiting) eventReady(GpgOp::Event::Finished); else emit q->finished(); } }; GpgOp::GpgOp(const QString &bin, QObject *parent) :QObject(parent) { d = new Private(this); d->bin = bin; } GpgOp::~GpgOp() { delete d; } void GpgOp::reset() { d->reset(ResetAll); } bool GpgOp::isActive() const { return (d->act ? true : false); } GpgOp::Type GpgOp::op() const { return d->op; } void GpgOp::setAsciiFormat(bool b) { d->opt_ascii = b; } void GpgOp::setDisableAgent(bool b) { d->opt_noagent = b; } void GpgOp::setAlwaysTrust(bool b) { d->opt_alwaystrust = b; } void GpgOp::setKeyrings(const QString &pubfile, const QString &secfile) { d->opt_pubfile = pubfile; d->opt_secfile = secfile; } void GpgOp::doCheck() { d->make_act(Check); d->act->start(); } void GpgOp::doSecretKeyringFile() { d->make_act(SecretKeyringFile); d->act->start(); } void GpgOp::doPublicKeyringFile() { d->make_act(PublicKeyringFile); d->act->start(); } void GpgOp::doSecretKeys() { d->make_act(SecretKeys); d->act->start(); } void GpgOp::doPublicKeys() { d->make_act(PublicKeys); d->act->start(); } void GpgOp::doEncrypt(const QStringList &recip_ids) { #ifdef GPG_PROFILE d->timer.start(); printf("<< doEncrypt >>\n"); #endif d->make_act(Encrypt); d->act->input.recip_ids = recip_ids; d->act->start(); } void GpgOp::doDecrypt() { d->make_act(Decrypt); d->act->start(); } void GpgOp::doSign(const QString &signer_id) { d->make_act(Sign); d->act->input.signer_id = signer_id; d->act->start(); } void GpgOp::doSignAndEncrypt(const QString &signer_id, const QStringList &recip_ids) { d->make_act(SignAndEncrypt); d->act->input.signer_id = signer_id; d->act->input.recip_ids = recip_ids; d->act->start(); } void GpgOp::doSignClearsign(const QString &signer_id) { d->make_act(SignClearsign); d->act->input.signer_id = signer_id; d->act->start(); } void GpgOp::doSignDetached(const QString &signer_id) { d->make_act(SignDetached); d->act->input.signer_id = signer_id; d->act->start(); } void GpgOp::doVerify() { d->make_act(Verify); d->act->start(); } void GpgOp::doVerifyDetached(const QByteArray &sig) { d->make_act(VerifyDetached); d->act->input.sig = sig; d->act->start(); } void GpgOp::doImport(const QByteArray &in) { d->make_act(Import); d->act->input.inkey = in; d->act->start(); } void GpgOp::doExport(const QString &key_id) { d->make_act(Export); d->act->input.export_key_id = key_id; d->act->start(); } void GpgOp::doDeleteKey(const QString &key_fingerprint) { d->make_act(DeleteKey); d->act->input.delete_key_fingerprint = key_fingerprint; d->act->start(); } #ifdef QPIPE_SECURE void GpgOp::submitPassphrase(const QCA::SecureArray &a) #else void GpgOp::submitPassphrase(const QByteArray &a) #endif { d->act->submitPassphrase(a); } void GpgOp::cardOkay() { d->act->cardOkay(); } QByteArray GpgOp::read() { if(d->act) { return d->act->read(); } else { QByteArray a = d->result; d->result.clear(); return a; } } void GpgOp::write(const QByteArray &in) { d->act->write(in); } void GpgOp::endWrite() { d->act->endWrite(); } QString GpgOp::readDiagnosticText() { QString s = d->diagnosticText; d->diagnosticText = QString(); return s; } GpgOp::Event GpgOp::waitForEvent(int msecs) { if(!d->eventList.isEmpty()) return d->eventList.takeFirst(); if(!d->act) return GpgOp::Event(); d->waiting = true; d->sync.waitForCondition(msecs); d->waiting = false; return d->eventList.takeFirst(); } bool GpgOp::success() const { return d->output.success; } GpgOp::Error GpgOp::errorCode() const { return d->output.errorCode; } GpgOp::KeyList GpgOp::keys() const { return d->output.keys; } QString GpgOp::keyringFile() const { return d->output.keyringFile; } QString GpgOp::encryptedToId() const { return d->output.encryptedToId; } bool GpgOp::wasSigned() const { return d->output.wasSigned; } QString GpgOp::signerId() const { return d->output.signerId; } QDateTime GpgOp::timestamp() const { return d->output.timestamp; } GpgOp::VerifyResult GpgOp::verifyResult() const { return d->output.verifyResult; } } #include "gpgop.moc" psi-0.14/third-party/qca/qca-cyrus-sasl/0000755000175000017500000000000011305557613016223 5ustar janjanpsi-0.14/third-party/qca/qca-cyrus-sasl/qca-cyrus-sasl.cpp0000644000175000017500000004736511305557613021615 0ustar janjan/* * qca-sasl.cpp - SASL plugin for QCA * Copyright (C) 2003-2007 Justin Karneges * Copyright (C) 2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #include #include #include #include extern "C" { #include } #include #include #include #define SASL_BUFSIZE 8192 #define SASL_APP "qca" using namespace QCA; namespace saslQCAPlugin { class saslProvider : public Provider { public: saslProvider(); void init(); ~saslProvider(); int qcaVersion() const; QString name() const; QString credit() const; QStringList features() const; Context *createContext(const QString &type); bool client_init; bool server_init; QString appname; }; //---------------------------------------------------------------------------- // SASLParams //---------------------------------------------------------------------------- class SASLParams { public: class SParams { public: bool user, authzid, pass, realm; }; SASLParams() { reset(); } void reset() { resetNeed(); resetHave(); foreach(char *result, results) delete result; results.clear(); } void resetNeed() { need.user = false; need.authzid = false; need.pass = false; need.realm = false; } void resetHave() { have.user = false; have.authzid = false; have.pass = false; have.realm = false; } void setUsername(const QString &s) { have.user = true; user = s; } void setAuthzid(const QString &s) { have.authzid = true; authzid = s; } void setPassword(const SecureArray &s) { have.pass = true; pass = QString::fromUtf8(s.toByteArray()); } void setRealm(const QString &s) { have.realm = true; realm = s; } void applyInteract(sasl_interact_t *needp) { for(int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) { if(needp[n].id == SASL_CB_AUTHNAME) need.user = true; // yes, I know these if(needp[n].id == SASL_CB_USER) need.authzid = true; // look backwards if(needp[n].id == SASL_CB_PASS) need.pass = true; if(needp[n].id == SASL_CB_GETREALM) need.realm = true; } } void extractHave(sasl_interact_t *needp) { for(int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) { if(needp[n].id == SASL_CB_AUTHNAME && have.user) setValue(&needp[n], user); if(needp[n].id == SASL_CB_USER && have.authzid) setValue(&needp[n], authzid); if(needp[n].id == SASL_CB_PASS && have.pass) setValue(&needp[n], pass); if(needp[n].id == SASL_CB_GETREALM && have.realm) setValue(&needp[n], realm); } } bool missingAny() const { if((need.user && !have.user) /*|| (need.authzid && !have.authzid)*/ || (need.pass && !have.pass) /*|| (need.realm && !have.realm)*/) return true; return false; } SParams missing() const { SParams np = need; if(have.user) np.user = false; if(have.authzid) np.authzid = false; if(have.pass) np.pass = false; if(have.realm) np.realm = false; return np; } void setValue(sasl_interact_t *i, const QString &s) { if(i->result) return; QByteArray cs = s.toUtf8(); int len = cs.length(); char *p = new char[len+1]; memcpy(p, cs.data(), len); p[len] = 0; i->result = p; i->len = len; // record this results.append(p); } QList results; SParams need; SParams have; QString user, authzid, pass, realm; }; static QByteArray makeByteArray(const void *in, unsigned int len) { QByteArray buf(len, 0); memcpy(buf.data(), in, len); return buf; } static QString addrString(const SASLContext::HostPort &hp) { return (hp.addr + ';' + QString::number(hp.port)); } //---------------------------------------------------------------------------- // saslContext //---------------------------------------------------------------------------- class saslContext : public SASLContext { saslProvider *g; // core props QString service, host; QString localAddr, remoteAddr; // security props int secflags; int ssf_min, ssf_max; QString ext_authid; int ext_ssf; sasl_conn_t *con; sasl_interact_t *need; int maxoutbuf; sasl_callback_t *callbacks; // state bool servermode; int step; bool in_sendFirst; QByteArray in_buf; QString in_mech; bool in_useClientInit; QByteArray in_clientInit; QString out_mech; // bool out_useClientInit; // QByteArray out_clientInit; QByteArray out_buf; SASLParams params; QString sc_username, sc_authzid; bool ca_flag, ca_done, ca_skip; int last_r; int result_ssf; Result result_result; bool result_haveClientInit; QStringList result_mechlist; SASL::AuthCondition result_authCondition; QByteArray result_to_net; QByteArray result_plain; int result_encoded; private: void resetState() { if(con) { sasl_dispose(&con); con = 0; } need = 0; if(callbacks) { delete callbacks; callbacks = 0; } localAddr = ""; remoteAddr = ""; maxoutbuf = 128; sc_username = ""; sc_authzid = ""; result_authCondition = SASL::AuthFail; result_haveClientInit = false; result_mechlist.clear(); result_plain.clear(); result_plain.clear(); result_plain.clear(); result_ssf = 0; } void resetParams() { params.reset(); secflags = 0; ssf_min = 0; ssf_max = 0; ext_authid = ""; ext_ssf = 0; } bool setsecprops() { sasl_security_properties_t secprops; secprops.min_ssf = ssf_min; secprops.max_ssf = ssf_max; secprops.maxbufsize = SASL_BUFSIZE; secprops.property_names = NULL; secprops.property_values = NULL; secprops.security_flags = secflags; int r = sasl_setprop(con, SASL_SEC_PROPS, &secprops); if(r != SASL_OK) return false; if(!ext_authid.isEmpty()) { const char *authid = ext_authid.toLatin1().data(); sasl_ssf_t ssf = ext_ssf; r = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf); if(r != SASL_OK) return false; r = sasl_setprop(con, SASL_AUTH_EXTERNAL, &authid); if(r != SASL_OK) return false; } return true; } void setAuthCondition(int r) { //qDebug() << "authcondition: " << r; SASL::AuthCondition x; switch(r) { // common case SASL_NOMECH: x = SASL::NoMechanism; break; case SASL_BADPROT: x = SASL::BadProtocol; break; // client case SASL_BADSERV: x = SASL::BadServer; break; // server case SASL_BADAUTH: x = SASL::BadAuth; break; case SASL_NOAUTHZ: x = SASL::NoAuthzid; break; case SASL_TOOWEAK: x = SASL::TooWeak; break; case SASL_ENCRYPT: x = SASL::NeedEncrypt; break; case SASL_EXPIRED: x = SASL::Expired; break; case SASL_DISABLED: x = SASL::Disabled; break; case SASL_NOUSER: x = SASL::NoUser; break; case SASL_UNAVAIL: x = SASL::RemoteUnavailable; break; default: x = SASL::AuthFail; break; } result_authCondition = x; } void getssfparams() { const void *maybe_sff; if( SASL_OK == sasl_getprop( con, SASL_SSF, &maybe_sff ) ) result_ssf = *(const int*)maybe_sff; const void *maybe_maxoutbuf; if (SASL_OK == sasl_getprop( con, SASL_MAXOUTBUF, &maybe_maxoutbuf ) ) maxoutbuf = *(const int*)maybe_maxoutbuf; } static int scb_checkauth(sasl_conn_t *, void *context, const char *requested_user, unsigned, const char *auth_identity, unsigned, const char *, unsigned, struct propctx *) { saslContext *that = (saslContext *)context; that->sc_username = auth_identity; // yeah yeah, it looks that->sc_authzid = requested_user; // backwards, but it is right that->ca_flag = true; return SASL_OK; } void clientTryAgain() { result_haveClientInit = false; if(step == 0) { const char *clientout, *m; unsigned int clientoutlen; need = 0; QString list = result_mechlist.join(" "); int r; while(1) { if(need) params.extractHave(need); if(in_sendFirst) r = sasl_client_start(con, list.toLatin1().data(), &need, &clientout, &clientoutlen, &m); else r = sasl_client_start(con, list.toLatin1().data(), &need, NULL, NULL, &m); if(r != SASL_INTERACT) break; params.applyInteract(need); if(params.missingAny()) { out_mech = m; result_result = Params; return; } } if(r != SASL_OK && r != SASL_CONTINUE) { setAuthCondition(r); result_result = Error; return; } out_mech = m; if(in_sendFirst && clientout) { out_buf = makeByteArray(clientout, clientoutlen); result_haveClientInit = true; } ++step; if(r == SASL_OK) { getssfparams(); result_result = Success; return; } result_result = Continue; return; } else { const char *clientout; unsigned int clientoutlen; int r; while(1) { if(need) params.extractHave(need); //printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", in_buf.data(), in_buf.size()); r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen); //printf("returned: %d\n", r); if(r != SASL_INTERACT) break; params.applyInteract(need); if(params.missingAny()) { result_result = Params; return; } } if(r != SASL_OK && r != SASL_CONTINUE) { setAuthCondition(r); result_result = Error; return; } out_buf = makeByteArray(clientout, clientoutlen); if(r == SASL_OK) { getssfparams(); result_result = Success; return; } result_result = Continue; return; } } void serverTryAgain() { if(step == 0) { if(!ca_skip) { const char *clientin = 0; unsigned int clientinlen = 0; if(in_useClientInit) { clientin = in_clientInit.data(); clientinlen = in_clientInit.size(); } const char *serverout; unsigned int serveroutlen; ca_flag = false; int r = sasl_server_start(con, in_mech.toLatin1().data(), clientin, clientinlen, &serverout, &serveroutlen); if(r != SASL_OK && r != SASL_CONTINUE) { setAuthCondition(r); result_result = Error; return; } out_buf = makeByteArray(serverout, serveroutlen); last_r = r; if(ca_flag && !ca_done) { ca_done = true; ca_skip = true; result_result = AuthCheck; return; } } ca_skip = false; ++step; if(last_r == SASL_OK) { getssfparams(); result_result = Success; return; } result_result = Continue; return; } else { if(!ca_skip) { const char *serverout; unsigned int serveroutlen; int r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen); if(r != SASL_OK && r != SASL_CONTINUE) { setAuthCondition(r); result_result = Error; return; } if(r == SASL_OK) out_buf.resize(0); else out_buf = makeByteArray(serverout, serveroutlen); last_r = r; if(ca_flag && !ca_done) { ca_done = true; ca_skip = true; result_result = AuthCheck; return; } } ca_skip = false; if(last_r == SASL_OK) { getssfparams(); result_result = Success; return; } result_result = Continue; return; } } bool sasl_endecode(const QByteArray &in, QByteArray *out, bool enc) { // no security if(result_ssf == 0) { *out = in; return true; } int at = 0; out->resize(0); while(1) { int size = in.size() - at; if(size == 0) break; if(size > maxoutbuf) size = maxoutbuf; const char *outbuf; unsigned len; int r; if(enc) r = sasl_encode(con, in.data() + at, size, &outbuf, &len); else r = sasl_decode(con, in.data() + at, size, &outbuf, &len); if(r != SASL_OK) return false; int oldsize = out->size(); out->resize(oldsize + len); memcpy(out->data() + oldsize, outbuf, len); at += size; } return true; } void doResultsReady() { QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); } public: saslContext(saslProvider *_g) : SASLContext(_g) { result_result = Success; g = _g; con = 0; callbacks = 0; reset(); } ~saslContext() { reset(); } virtual Provider::Context *clone() const { return 0; } virtual Result result() const { return result_result; } virtual void reset() { resetState(); resetParams(); } virtual void setup(const QString &_service, const QString &_host, const HostPort *local, const HostPort *remote, const QString &ext_id, int _ext_ssf) { service = _service; host = _host; localAddr = local ? addrString(*local) : ""; remoteAddr = remote ? addrString(*remote) : ""; ext_authid = ext_id; ext_ssf = _ext_ssf; } virtual int ssf() const { return result_ssf; } virtual void startClient(const QStringList &mechlist, bool allowClientSendFirst) { resetState(); in_sendFirst = allowClientSendFirst; if(!g->client_init) { sasl_client_init(NULL); g->client_init = true; } callbacks = new sasl_callback_t[5]; callbacks[0].id = SASL_CB_GETREALM; callbacks[0].proc = 0; callbacks[0].context = 0; callbacks[1].id = SASL_CB_USER; callbacks[1].proc = 0; callbacks[1].context = 0; callbacks[2].id = SASL_CB_AUTHNAME; callbacks[2].proc = 0; callbacks[2].context = 0; callbacks[3].id = SASL_CB_PASS; callbacks[3].proc = 0; callbacks[3].context = 0; callbacks[4].id = SASL_CB_LIST_END; callbacks[4].proc = 0; callbacks[4].context = 0; result_result = Error; int r = sasl_client_new(service.toLatin1().data(), host.toLatin1().data(), localAddr.isEmpty() ? 0 : localAddr.toLatin1().data(), remoteAddr.isEmpty() ? 0 : remoteAddr.toLatin1().data(), callbacks, 0, &con); if(r != SASL_OK) { setAuthCondition(r); doResultsReady(); return; } if(!setsecprops()) { doResultsReady(); return; } result_mechlist = mechlist; servermode = false; step = 0; result_result = Success; clientTryAgain(); doResultsReady(); return; } // TODO: make use of disableServerSendLast virtual void startServer(const QString &realm, bool disableServerSendLast) { Q_UNUSED(disableServerSendLast); resetState(); g->appname = SASL_APP; if(!g->server_init) { sasl_server_init(NULL, QFile::encodeName(g->appname)); g->server_init = true; } callbacks = new sasl_callback_t[2]; callbacks[0].id = SASL_CB_PROXY_POLICY; callbacks[0].proc = (int(*)())scb_checkauth; callbacks[0].context = this; callbacks[1].id = SASL_CB_LIST_END; callbacks[1].proc = 0; callbacks[1].context = 0; result_result = Error; int r = sasl_server_new(service.toLatin1().data(), host.toLatin1().data(), !realm.isEmpty() ? realm.toLatin1().data() : 0, localAddr.isEmpty() ? 0 : localAddr.toLatin1().data(), remoteAddr.isEmpty() ? 0 : remoteAddr.toLatin1().data(), callbacks, 0, &con); if(r != SASL_OK) { setAuthCondition(r); doResultsReady(); return; } if(!setsecprops()) { doResultsReady(); return; } const char *ml; r = sasl_listmech(con, 0, 0, " ", 0, &ml, 0, 0); if(r != SASL_OK) return; result_mechlist = QString::fromUtf8(ml).split(' '); servermode = true; step = 0; ca_done = false; ca_skip = false; result_result = Success; doResultsReady(); return; } virtual void serverFirstStep(const QString &mech, const QByteArray *clientInit) { in_mech = mech; if(clientInit) { in_useClientInit = true; in_clientInit = *clientInit; } else in_useClientInit = false; serverTryAgain(); doResultsReady(); } virtual SASL::Params clientParams() const { SASLParams::SParams sparams = params.missing(); return SASL::Params(sparams.user, sparams.authzid, sparams.pass, sparams.realm); } virtual void setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) { if(user) params.setUsername(*user); if(authzid) params.setAuthzid(*authzid); if(pass) params.setPassword(*pass); if(realm) params.setRealm(*realm); } virtual QString username() const { return sc_username; } virtual QString authzid() const { return sc_authzid; } virtual void nextStep(const QByteArray &from_net) { in_buf = from_net; tryAgain(); } virtual void tryAgain() { if(servermode) serverTryAgain(); else clientTryAgain(); doResultsReady(); } virtual QString mech() const { if (servermode) return in_mech; else return out_mech; } virtual QStringList mechlist() const { return result_mechlist; } virtual QStringList realmlist() const { // TODO return QStringList(); } virtual void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) { int sf = 0; if( !(f & SASL::AllowPlain) ) sf |= SASL_SEC_NOPLAINTEXT; // if( !(f & SASL::AllowActiveVulnerable) ) // TODO // sf |= SASL_SEC_NOACTIVE; // if( !(f & SASL::AllowDictVulnerable) ) // TODO // sf |= SASL_SEC_NODICTIONARY; if( !(f & SASL::AllowAnonymous) ) sf |= SASL_SEC_NOANONYMOUS; if( f & SASL::RequireForwardSecrecy ) sf |= SASL_SEC_FORWARD_SECRECY; if( f & SASL::RequirePassCredentials ) sf |= SASL_SEC_PASS_CREDENTIALS; if( f & SASL::RequireMutualAuth ) sf |= SASL_SEC_MUTUAL_AUTH; secflags = sf; ssf_min = minSSF; ssf_max = maxSSF; } virtual bool waitForResultsReady(int msecs) { // TODO: for now, all operations block anyway Q_UNUSED(msecs); return true; } virtual void update(const QByteArray &from_net, const QByteArray &from_app) { bool ok = true; if(!from_app.isEmpty()) ok = sasl_endecode(from_app, &result_to_net, true); if(ok && !from_net.isEmpty()) ok = sasl_endecode(from_net, &result_plain, false); result_result = ok ? Success : Error; result_encoded = from_app.size(); //printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(), from_app.size(), result_plain.size()); doResultsReady(); } virtual bool haveClientInit() const { return result_haveClientInit; } virtual QByteArray stepData() const { return out_buf; } virtual QByteArray to_net() { QByteArray a = result_to_net; result_to_net.clear(); return a; } virtual int encoded() const { return result_encoded; } virtual QByteArray to_app() { QByteArray a = result_plain; result_plain.clear(); return a; } virtual SASL::AuthCondition authCondition() const { return result_authCondition; } }; //---------------------------------------------------------------------------- // saslProvider //---------------------------------------------------------------------------- saslProvider::saslProvider() { client_init = false; server_init = false; } void saslProvider::init() { } saslProvider::~saslProvider() { if(client_init || server_init) sasl_done(); } int saslProvider::qcaVersion() const { return QCA_VERSION; } QString saslProvider::name() const { return "qca-cyrus-sasl"; } QString saslProvider::credit() const { return QString(); // TODO } QStringList saslProvider::features() const { QStringList list; list += "sasl"; return list; } Provider::Context *saslProvider::createContext(const QString &type) { if ( type == "sasl" ) return new saslContext( this ); return 0; } } // namespace saslQCAPlugin using namespace saslQCAPlugin; //---------------------------------------------------------------------------- // saslPlugin //---------------------------------------------------------------------------- class saslPlugin : public QObject, public QCAPlugin { Q_OBJECT Q_INTERFACES(QCAPlugin) public: virtual Provider *createProvider() { return new saslProvider; } }; #include "qca-cyrus-sasl.moc" Q_EXPORT_PLUGIN2(qca_cyrus_sasl, saslPlugin) psi-0.14/third-party/qca/qca.pro0000644000175000017500000000372011305557613014644 0ustar janjanTEMPLATE = lib QT -= gui CONFIG += staticlib DEFINES += QCA_STATIC TARGET = qca_psi QCA_BASE = qca QCA_INCBASE = $$QCA_BASE/include QCA_SRCBASE = $$QCA_BASE/src MOC_DIR = .moc OBJECTS_DIR = .obj QCA_INC = $$QCA_INCBASE/QtCrypto QCA_CPP = $$QCA_SRCBASE INCLUDEPATH += $$QCA_INC $$QCA_CPP windows { # Explicitly remove d_and_r, so the lib gets built in the right place CONFIG -= debug_and_release # Set explicit targets, to ensure a correct name for MSVC } # botantools include($$QCA_SRCBASE/botantools/botantools.pri) PRIVATE_HEADERS += \ $$QCA_CPP/qca_plugin.h \ $$QCA_CPP/qca_safeobj.h \ $$QCA_CPP/qca_systemstore.h PUBLIC_HEADERS += \ $$QCA_INC/qca_export.h \ $$QCA_INC/qca_support.h \ $$QCA_INC/qca_tools.h \ $$QCA_INC/qca_core.h \ $$QCA_INC/qca_textfilter.h \ $$QCA_INC/qca_basic.h \ $$QCA_INC/qca_publickey.h \ $$QCA_INC/qca_cert.h \ $$QCA_INC/qca_keystore.h \ $$QCA_INC/qca_securelayer.h \ $$QCA_INC/qca_securemessage.h \ $$QCA_INC/qcaprovider.h \ $$QCA_INC/qpipe.h HEADERS += $$PRIVATE_HEADERS $$PUBLIC_HEADERS # do support first SOURCES += \ $$QCA_CPP/support/syncthread.cpp \ $$QCA_CPP/support/logger.cpp \ $$QCA_CPP/support/synchronizer.cpp \ $$QCA_CPP/support/dirwatch.cpp SOURCES += \ $$QCA_CPP/qca_tools.cpp \ $$QCA_CPP/qca_core.cpp \ $$QCA_CPP/qca_textfilter.cpp \ $$QCA_CPP/qca_plugin.cpp \ $$QCA_CPP/qca_basic.cpp \ $$QCA_CPP/qca_publickey.cpp \ $$QCA_CPP/qca_cert.cpp \ $$QCA_CPP/qca_keystore.cpp \ $$QCA_CPP/qca_securelayer.cpp \ $$QCA_CPP/qca_safeobj.cpp \ $$QCA_CPP/qca_securemessage.cpp \ $$QCA_CPP/qca_default.cpp \ $$QCA_CPP/support/qpipe.cpp \ $$QCA_CPP/support/console.cpp unix:!mac: { SOURCES += $$QCA_CPP/qca_systemstore_flatfile.cpp } windows: { SOURCES += $$QCA_CPP/qca_systemstore_win.cpp } mac: { SOURCES += $$QCA_CPP/qca_systemstore_mac.cpp } include(../../conf.pri) qc_universal:contains(QT_CONFIG,x86):contains(QT_CONFIG,ppc) { CONFIG += x86 ppc QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk } psi-0.14/third-party/qca/qca-cyrus-sasl.pri0000644000175000017500000000006311305557613016736 0ustar janjanSOURCES += $$PWD/qca-cyrus-sasl/qca-cyrus-sasl.cpp psi-0.14/src/0000755000175000017500000000000011305560074011123 5ustar janjanpsi-0.14/src/profileopen.ui0000644000175000017500000001567311305557613014025 0ustar janjan ProfileOpen 0 0 305 197 Open Profile 0 0 0 0 left Image goes here right 11 Open Profile 11 6 0 6 Profile: 7 0 0 0 &Automatically open on startup 0 6 Language: 7 0 0 0 QFrame::HLine QFrame::Sunken 0 &Quit psi/quit 59 20 Expanding Horizontal &Profiles... psi/profile &Open psi/logo_16 qPixmapFromMimeSource psi-0.14/src/vcardfactory.h0000644000175000017500000000341311305557613013771 0ustar janjan/* * vcardfactory.h - class for caching vCards * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef VCARDFACTORY_H #define VCARDFACTORY_H #include #include #include namespace XMPP { class VCard; class Jid; class Task; class JT_VCard; } using namespace XMPP; class PsiAccount; class VCardFactory : public QObject { Q_OBJECT public: static VCardFactory* instance(); const VCard *vcard(const Jid &); void setVCard(const Jid &, const VCard &); void setVCard(const PsiAccount* account, const VCard &v, QObject* obj = 0, const char* slot = 0); JT_VCard *getVCard(const Jid &, Task *rootTask, const QObject *, const char *slot, bool cacheVCard = true); signals: void vcardChanged(const Jid&); protected: void checkLimit(QString jid, VCard *vcard); private slots: void updateVCardFinished(); void taskFinished(); private: VCardFactory(); ~VCardFactory(); static VCardFactory* instance_; const int dictSize_; QStringList vcardList_; QMap vcardDict_; void saveVCard(const Jid &, const VCard &); }; #endif psi-0.14/src/common.h0000644000175000017500000001057711305557613012603 0ustar janjan/* * common.h - contains all the common variables and functions for Psi * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef COMMON_H #define COMMON_H #include #include #include #include #include #include #include "statuspreset.h" // ----------------------------------------------------------------------------- // Options // ----------------------------------------------------------------------------- enum { dcClose, dcHour, dcDay, dcNever }; enum Qt3Dock { Qt3Dock_Unmanaged = 0, Qt3Dock_TornOff = 1, Qt3Dock_Top = 2, Qt3Dock_Bottom = 3, Qt3Dock_Right = 4, Qt3Dock_Left = 5, Qt3Dock_Minimized = 6 }; class ToolbarPrefs { public: ToolbarPrefs(); QString id; QString name; QStringList keys; Qt3Dock dock; bool dirty; bool on; bool locked; // bool stretchable; // int index; bool nl; // int extraOffset; bool operator==(const ToolbarPrefs& other); }; struct lateMigrationOptions { QMap serviceRosterIconset; QMap customRosterIconset; QMap sp; // Status message presets. QMap< QString, QList > toolbars; }; // used to be part of the global options struct. // do not modify or save/load this value! it is calculated at run time! // FIXME find it a new home! extern int common_smallFontSize; // used to be part of the global options struct. // FIXME find it a new home! enum { EventPriorityDontCare = -1 }; // ----------------------------------------------------------------------------- // Status // ----------------------------------------------------------------------------- #include "xmpp_status.h" #define STATUS_OFFLINE XMPP::Status::Offline #define STATUS_ONLINE XMPP::Status::Online #define STATUS_AWAY XMPP::Status::Away #define STATUS_XA XMPP::Status::XA #define STATUS_DND XMPP::Status::DND #define STATUS_INVISIBLE XMPP::Status::Invisible #define STATUS_CHAT XMPP::Status::FFC #define STATUS_ASK 100 #define STATUS_NOAUTH 101 #define STATUS_ERROR 102 QString status2txt(int status); XMPP::Status makeStatus(int, const QString &); XMPP::Status makeStatus(int, const QString &, int); XMPP::Status::Type makeSTATUS(const XMPP::Status &); QString clipStatus(const QString &str, int width, int height); // ----------------------------------------------------------------------------- // Widget tools // ----------------------------------------------------------------------------- void bringToFront(QWidget *w, bool grabFocus = true); void replaceWidget(QWidget *, QWidget *); void closeDialogs(QWidget *); #ifdef Q_WS_X11 #include #include void x11wmClass(Display *dsp, WId wid, QString resName); #define X11WM_CLASS(x) x11wmClass(QX11Info::display(), winId(), (x)); #else #define X11WM_CLASS(x) /* dummy */ #endif // ----------------------------------------------------------------------------- // History utilities // ----------------------------------------------------------------------------- QString logencode(QString); QString logdecode(const QString &); // ----------------------------------------------------------------------------- // Misc. // ----------------------------------------------------------------------------- QString CAP(const QString &str); QString encodePassword(const QString &, const QString &); QString decodePassword(const QString &, const QString &); bool operator!=(const QMap &, const QMap &); bool fileCopy(const QString &src, const QString &dest); // used in option migration QString soundDetectPlayer(); void soundPlay(const QString &); extern Qt::WFlags psi_dialog_flags; // like QT_VERSION, but runtime int qVersionInt(); #endif psi-0.14/src/applicationinfo.h0000644000175000017500000000123311305557613014457 0ustar janjan#ifndef APPLICATIONINFO_H #define APPLICATIONINFO_H class QString; class ApplicationInfo { public: // Version info static QString name(); static QString version(); static QString capsNode(); static QString capsVersion(); static QString IPCName(); // URLs static QString getAppCastURL(); // Directories static QString homeDir(); static QString resourcesDir(); static QString libDir(); static QString profilesDir(); static QString historyDir(); static QString vCardDir(); static QStringList getCertificateStoreDirs(); static QString getCertificateStoreSaveDir(); // Namespaces static QString optionsNS(); static QString storageNS(); }; #endif psi-0.14/src/xmlconsole.h0000644000175000017500000000330011305557613013460 0ustar janjan/* * xmlconsole.h - dialog for interacting manually with Jabber * Copyright (C) 2001, 2002 Justin Karneges, Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMLCONSOLE_H #define XMLCONSOLE_H #include #include #include #include "ui_xmlconsole.h" class QTextEdit; class QCheckBox; class PsiAccount; class XmlPrompt; class XmlConsole : public QWidget { Q_OBJECT public: XmlConsole(PsiAccount *); ~XmlConsole(); void enable(); private slots: void clear(); void updateCaption(); void insertXml(); void dumpRingbuf(); void client_xmlIncoming(const QString &); void client_xmlOutgoing(const QString &); void xml_textReady(const QString &); protected: bool filtered(const QString&) const; private: Ui::XMLConsole ui_; PsiAccount *pa; QPointer prompt; }; class XmlPrompt : public QDialog { Q_OBJECT public: XmlPrompt(QWidget *parent=0); ~XmlPrompt(); signals: void textReady(const QString &); private slots: void doTransmit(); private: QTextEdit *te; }; #endif psi-0.14/src/accountmanagedlg.h0000644000175000017500000000264311305557613014602 0ustar janjan/* * accountmanagedlg.h - dialogs for manipulating PsiAccounts * Copyright (C) 2001-2009 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACCOUNTMANAGEDLG_H #define ACCOUNTMANAGEDLG_H #include "ui_accountmanage.h" namespace XMPP { class Jid; class Client; } class PsiCon; class PsiAccount; class QTreeWidgetItem; class AccountManageDlg : public QDialog, public Ui::AccountManage { Q_OBJECT public: AccountManageDlg(PsiCon *); ~AccountManageDlg(); private slots: void qlv_selectionChanged(QTreeWidgetItem *, QTreeWidgetItem *); void add(); void modify(); void modify(QTreeWidgetItem *); void remove(); void accountAdded(PsiAccount *); void accountRemoved(PsiAccount *); private: PsiCon *psi; }; #endif psi-0.14/src/physicallocation.cpp0000644000175000017500000001367011305557613015210 0ustar janjan/* * physicallocation.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "physicallocation.h" PhysicalLocation::PhysicalLocation() { } PhysicalLocation::PhysicalLocation(const QDomElement& el) { fromXml(el); } QDomElement PhysicalLocation::toXml(QDomDocument& doc) { QDomElement physloc = doc.createElement("physloc"); physloc.setAttribute("xmlns", "http://jabber.org/protocol/physloc"); if (!country_.isEmpty()) { QDomElement e = doc.createElement("country"); e.appendChild(doc.createTextNode(country_)); physloc.appendChild(e); } if (!region_.isEmpty()) { QDomElement e = doc.createElement("region"); e.appendChild(doc.createTextNode(region_)); physloc.appendChild(e); } if (!locality_.isEmpty()) { QDomElement e = doc.createElement("locality"); e.appendChild(doc.createTextNode(locality_)); physloc.appendChild(e); } if (!area_.isEmpty()) { QDomElement e = doc.createElement("area"); e.appendChild(doc.createTextNode(area_)); physloc.appendChild(e); } if (!street_.isEmpty()) { QDomElement e = doc.createElement("street"); e.appendChild(doc.createTextNode(street_)); physloc.appendChild(e); } if (!building_.isEmpty()) { QDomElement e = doc.createElement("building"); e.appendChild(doc.createTextNode(building_)); physloc.appendChild(e); } if (!floor_.isEmpty()) { QDomElement e = doc.createElement("floor"); e.appendChild(doc.createTextNode(floor_)); physloc.appendChild(e); } if (!room_.isEmpty()) { QDomElement e = doc.createElement("room"); e.appendChild(doc.createTextNode(room_)); physloc.appendChild(e); } if (!postalcode_.isEmpty()) { QDomElement e = doc.createElement("postalcode"); e.appendChild(doc.createTextNode(postalcode_)); physloc.appendChild(e); } if (!text_.isEmpty()) { QDomElement e = doc.createElement("text"); e.appendChild(doc.createTextNode(text_)); physloc.appendChild(e); } return physloc; } void PhysicalLocation::fromXml(const QDomElement& e) { if (e.tagName() != "physloc") return; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement m = n.toElement(); if (m.tagName() == "country") country_ = m.text(); else if (m.tagName() == "region") region_ = m.text(); else if (m.tagName() == "locality") locality_ = m.text(); else if (m.tagName() == "area") area_ = m.text(); else if (m.tagName() == "street") street_ = m.text(); else if (m.tagName() == "building") building_ = m.text(); else if (m.tagName() == "floor") floor_ = m.text(); else if (m.tagName() == "room") room_ = m.text(); else if (m.tagName() == "postalcode") postalcode_ = m.text(); else if (m.tagName() == "text") text_ = m.text(); } } const QString& PhysicalLocation::country() const { return country_; } const QString& PhysicalLocation::region() const { return region_; } const QString& PhysicalLocation::locality() const { return locality_; } const QString& PhysicalLocation::area() const { return area_; } const QString& PhysicalLocation::street() const { return street_; } const QString& PhysicalLocation::building() const { return building_; } const QString& PhysicalLocation::floor() const { return floor_; } const QString& PhysicalLocation::room() const { return room_; } const QString& PhysicalLocation::postalcode() const { return postalcode_; } const QString& PhysicalLocation::text() const { return text_; } bool PhysicalLocation::isNull() const { return country_.isNull() && region_.isNull() && locality_.isNull() && area_.isNull() && street_.isNull() && building_.isNull() && floor_.isNull() && room_.isNull() && postalcode_.isNull() && text_.isNull(); } bool PhysicalLocation::operator==(const PhysicalLocation& o) const { return country() == o.country() && region() == o.region() && locality() == o.locality() && area() == o.area() && street() == o.street() && building() == o.building() && floor() == o.floor() && room() == o.room() && postalcode() == o.postalcode() && text() == o.text(); } bool PhysicalLocation::operator!=(const PhysicalLocation& o) const { return !((*this) == o); } void PhysicalLocation::setCountry(const QString& s) { country_ = s; } void PhysicalLocation::setRegion(const QString& s) { region_ = s; } void PhysicalLocation::setLocality(const QString& s) { locality_ = s; } void PhysicalLocation::setArea(const QString& s) { area_ = s; } void PhysicalLocation::setStreet(const QString& s) { street_ = s; } void PhysicalLocation::setBuilding(const QString& s) { building_ = s; } void PhysicalLocation::setFloor(const QString& s) { floor_ = s; } void PhysicalLocation::setRoom(const QString& s) { room_ = s; } void PhysicalLocation::setPostalcode(const QString& s) { postalcode_ = s; } void PhysicalLocation::setText(const QString& s) { text_ = s; } QString PhysicalLocation::toString() const { QStringList locs; QString loc, str; if (!locality().isEmpty()) locs += locality(); if (!region().isEmpty()) locs += region(); if (!country().isEmpty()) locs += country(); if (!locs.isEmpty()) { loc = locs.join(", "); } if (!text().isEmpty()) { str += text(); if (!loc.isEmpty()) str += " ("; } str += loc; if (!text().isEmpty() && !loc.isEmpty()) str += ")"; return str; } psi-0.14/src/rc.h0000644000175000017500000000416411305557613011712 0ustar janjan/* * rc.h - Implementation of JEP-146 (Remote Controlling Clients) * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef RC_H #define RC_H #include "ahcommandserver.h" class PsiCon; class RCCommandServer : public AHCommandServer { public: RCCommandServer(AHCServerManager* m) : AHCommandServer(m) { } virtual QString node() const { return QString("http://jabber.org/protocol/rc#") + rcNode(); } virtual QString rcNode() const = 0; virtual bool isAllowed(const Jid&) const; }; class RCSetStatusServer : public RCCommandServer { public: RCSetStatusServer(AHCServerManager* m) : RCCommandServer(m) { } virtual QString name() const { return "Set Status"; } virtual QString rcNode() const { return "set-status"; } virtual AHCommand execute(const AHCommand&, const Jid&); }; class RCForwardServer : public RCCommandServer { public: RCForwardServer(AHCServerManager* m) : RCCommandServer(m) { } virtual QString name() const { return "Forward Messages"; } virtual QString rcNode() const { return "forward"; } virtual AHCommand execute(const AHCommand& c, const Jid&); }; class RCSetOptionsServer : public RCCommandServer { public: RCSetOptionsServer(AHCServerManager* m, PsiCon* c) : RCCommandServer(m), psiCon_(c) { } virtual QString name() const { return "Set Options"; } virtual QString rcNode() const { return "set-options"; } virtual AHCommand execute(const AHCommand& c, const Jid&); private: PsiCon* psiCon_; }; #endif psi-0.14/src/googleftmanager.cpp0000644000175000017500000002612411305557613015002 0ustar janjan/* * googleftmanager.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // libjingle includes #define POSIX #include "talk/base/sigslot.h" #include "talk/xmpp/constants.h" #include "talk/xmpp/jid.h" #include "talk/xmllite/xmlelement.h" #include "talk/xmllite/xmlprinter.h" #include "talk/base/network.h" #include "talk/p2p/base/session.h" #include "talk/p2p/base/sessionmanager.h" #include "talk/base/helpers.h" #include "talk/p2p/client/basicportallocator.h" #include "talk/p2p/base/sessionclient.h" #include "talk/p2p/client/sessionsendtask.h" #include "talk/p2p/client/httpportallocator.h" #include "talk/base/physicalsocketserver.h" #include "talk/base/thread.h" #include "talk/base/socketaddress.h" #include "talk/session/fileshare/fileshare.h" #include #include #include #include "xmpp_xmlcommon.h" #include "googleftmanager.h" // Should change in the future #define JINGLE_NS "http://www.google.com/session" #define JINGLEINFO_NS "google:jingleinfo" using namespace XMPP; // ---------------------------------------------------------------------------- /** * \class GoogleJingleInfoTask * A class for retrieving information from the server about Google's * Jingle support. */ class GoogleJingleInfoTask : public Task { public: GoogleJingleInfoTask(Task* parent) : Task(parent) { } void onGo() { QDomElement iq = createIQ(doc(), "get", "", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", JINGLEINFO_NS); iq.appendChild(query); send(iq); } bool take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { // TODO:Parse info setSuccess(); } else { setError(x); } return true; } }; // ---------------------------------------------------------------------------- /** * \class JingleIQResponder * \brief A task that ensures that we don't send an unsupported error */ class JingleIQResponder : public XMPP::Task { public: JingleIQResponder(XMPP::Task * parent) : Task(parent) {} ~JingleIQResponder() {} bool take(const QDomElement& e) { if(e.tagName() != "iq") return false; QDomElement first = e.firstChild().toElement(); if (!first.isNull() && first.attribute("xmlns") == JINGLE_NS) { return true; } return false; } }; // ---------------------------------------------------------------------------- /** * \brief A class for handling signals from libjingle. */ class GoogleSessionListener : public sigslot::has_slots<> { public: GoogleSessionListener(GoogleFTManager* manager); void fileShareSessionCreated(cricket::FileShareSession *); void sendStanza(const buzz::XmlElement *stanza); void signalingReady(); private: GoogleFTManager* manager_; }; GoogleSessionListener::GoogleSessionListener(GoogleFTManager* manager) : manager_(manager) { } void GoogleSessionListener::sendStanza(const buzz::XmlElement *stanza) { QString st(stanza->Str().c_str()); st.replace("sendStanza(st); } void GoogleSessionListener::fileShareSessionCreated(cricket::FileShareSession* session) { new GoogleFileTransfer(session, manager_); } void GoogleSessionListener::signalingReady() { manager_->session_manager_->OnSignalingReady(); } // ---------------------------------------------------------------------------- /** * \brief A class for handling signals from libjingle. */ class GoogleFileTransferListener : public sigslot::has_slots<> { public: GoogleFileTransferListener(GoogleFileTransfer*); void stateChanged(cricket::FileShareState); void progressChanged(cricket::FileShareSession*); void resampleImage(std::string path, int width, int height, talk_base::HttpTransaction* trans); private: GoogleFileTransfer* session_; }; GoogleFileTransferListener::GoogleFileTransferListener(GoogleFileTransfer* s) : session_(s) { } void GoogleFileTransferListener::stateChanged(cricket::FileShareState state) { switch(state) { case cricket::FS_OFFER: emit session_->manager_->incomingFileTransfer(session_); break; case cricket::FS_TRANSFER: qDebug("Transfer started"); break; case cricket::FS_COMPLETE: qDebug("Transfer complete"); break; case cricket::FS_LOCAL_CANCEL: case cricket::FS_REMOTE_CANCEL: qDebug("FS_CANCEL"); break; case cricket::FS_FAILURE: qDebug("FS_FAILURE"); break; } } void GoogleFileTransferListener::progressChanged(cricket::FileShareSession* sess) { size_t progress; std::string itemname; if (sess->GetProgress(progress) && sess->GetCurrentItemName(&itemname)) { emit session_->progressChanged(progress,QString(itemname.c_str())); } } void GoogleFileTransferListener::resampleImage(std::string, int, int, talk_base::HttpTransaction* trans) { // From PCP session_->session_->ResampleComplete(NULL, trans, false); } // ---------------------------------------------------------------------------- GoogleFileTransfer::GoogleFileTransfer(cricket::FileShareSession* s, GoogleFTManager* manager) : session_(s), manager_(manager) { listener_ = new GoogleFileTransferListener(this); session_->SignalState.connect(listener_, &GoogleFileTransferListener::stateChanged); session_->SignalNextFile.connect(listener_, &GoogleFileTransferListener::progressChanged); session_->SignalUpdateProgress.connect(listener_, &GoogleFileTransferListener::progressChanged); session_->SignalResampleImage.connect(listener_, &GoogleFileTransferListener::resampleImage); // Temporary #ifdef Q_WS_MAC QDir home(QDir::homeDirPath() + "/Desktop"); #else QDir home = QDir::home(); #endif QDir dir(home.path() + "/googletalk_files"); if(!dir.exists()) home.mkdir("googletalk_files"); session_->SetLocalFolder(dir.path().toStdString()); } XMPP::Jid GoogleFileTransfer::peer() const { return Jid(session_->jid().BareJid().Str().c_str()); } QString GoogleFileTransfer::fileName() const { return description(); } QString GoogleFileTransfer::description() const { QString description; if (session_->manifest()->size() == 1) description = QString("'%1'").arg(session_->manifest()->item(0).name.c_str()); else if (session_->manifest()->GetFileCount() && session_->manifest()->GetFolderCount()) description = QString("%1 files and %2 directories").arg(session_->manifest()->GetFileCount()).arg(session_->manifest()->GetFolderCount()); else if (session_->manifest()->GetFileCount()) description = QString("%1 files").arg(session_->manifest()->GetFileCount()); else if (session_->manifest()->GetFolderCount()) description = QString("%1 directories").arg(session_->manifest()->GetFolderCount()); else description = "(Unknown)"; return description; } qlonglong GoogleFileTransfer::fileSize() const { size_t filesize; if (!session_->GetTotalSize(filesize)) filesize = -1; return filesize; } void GoogleFileTransfer::accept(qlonglong, qlonglong) { session_->Accept(); } void GoogleFileTransfer::reject() { session_->Decline(); } void GoogleFileTransfer::cancel() { session_->Cancel(); } // ---------------------------------------------------------------------------- GoogleFTManager::GoogleFTManager(Client* client) : client_(client) { initialized_ = false; connect(client_, SIGNAL(rosterRequestFinished(bool, int, const QString &)), SLOT(initialize())); connect(client_, SIGNAL(disconnected()), SLOT(deinitialize())); } void GoogleFTManager::initialize() { if (initialized_) return; QString jid = ((ClientStream&) client_->stream()).jid().full(); if (jid.isEmpty()) { qWarning("googleftmanager.cpp: Empty JID"); return; } buzz::Jid j(jid.ascii()); // FIXME: Ascii is evil // Static stuff if (socket_server_ == NULL) { //talk_base::InitializeSSL(); cricket::InitRandom(j.Str().c_str(),j.Str().size()); socket_server_ = new talk_base::PhysicalSocketServer(); thread_ = new talk_base::Thread(socket_server_); talk_base::ThreadManager::SetCurrent(thread_); thread_->Start(); network_manager_ = new talk_base::NetworkManager(); port_allocator_.reset(new cricket::HttpPortAllocator(network_manager_, "psi")); } listener_ = new GoogleSessionListener(this); session_manager_.reset(new cricket::SessionManager(port_allocator_.get(), NULL)); session_manager_->SignalOutgoingMessage.connect(listener_, &GoogleSessionListener::sendStanza); //session_manager_->SignalRequestSignaling.connect(session_manager_, &cricket::SessionManager::OnSignalingReady); session_manager_->SignalRequestSignaling.connect(listener_, &GoogleSessionListener::signalingReady); file_share_session_client_.reset(new cricket::FileShareSessionClient(session_manager_.get(), j, "psi")); file_share_session_client_->SignalFileShareSessionCreate.connect(listener_, &GoogleSessionListener::fileShareSessionCreated); session_manager_->AddClient(NS_GOOGLE_SHARE, file_share_session_client_.get()); // Listen to incoming packets connect(client_,SIGNAL(xmlIncoming(const QString&)),SLOT(receiveStanza(const QString&))); // IQ Responder new JingleIQResponder(client_->rootTask()); initialized_ = true; } void GoogleFTManager::deinitialize() { if (!initialized_) return; // Stop listening to incoming packets disconnect(client_,SIGNAL(xmlIncoming(const QString&)),this,SLOT(receiveStanza(const QString&))); delete listener_; initialized_ = false; } GoogleFTManager::~GoogleFTManager() { } void GoogleFTManager::sendStanza(const QString& stanza) { client_->send(stanza); } void GoogleFTManager::receiveStanza(const QString& sstanza) { // Add a namespace to the element (for libjingle to process correctly) QDomDocument doc; doc.setContent(sstanza); /*doc.documentElement().setAttribute("xmlns","jabber:client"); QString stanza = doc.toString(); buzz::XmlElement *e = buzz::XmlElement::ForStr(stanza.ascii()); if (!session_manager_.get()->IsSessionMessage(e)) return;*/ QDomNode n = doc.documentElement().firstChild(); bool ok = false; while (!n.isNull() && !ok) { QDomElement e = n.toElement(); if (!e.isNull() && e.attribute("xmlns") == JINGLE_NS) { ok = true; } n = n.nextSibling(); } if (!ok) return; buzz::XmlElement *e = buzz::XmlElement::ForStr(sstanza.ascii()); session_manager_->OnIncomingMessage(e); } talk_base::PhysicalSocketServer* GoogleFTManager::socket_server_ = NULL; talk_base::Thread *GoogleFTManager::thread_ = NULL; talk_base::NetworkManager* GoogleFTManager::network_manager_ = NULL; talk_base::scoped_ptr GoogleFTManager::port_allocator_; psi-0.14/src/widgets/0000755000175000017500000000000011305557613012576 5ustar janjanpsi-0.14/src/widgets/psiwidgets.cpp0000644000175000017500000002626211305557613015474 0ustar janjan/* * psiwidgets.cpp - plugin for loading Psi's custom widgets into Qt Designer * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psiwidgets.h" #include "busywidget.h" #include "fancylabel.h" #include "iconwidget.h" #include "iconlabel.h" #include "iconbutton.h" #include "iconsetselect.h" #include "iconsetdisplay.h" #include "icontoolbutton.h" #include "urllabel.h" #include "psitextview.h" static const char *psiwidget_data[] = { "16 16 5 1", ". c None", "# c #000000", "c c #57acda", "b c #72bde6", "a c #cde9f8", ".###..####..###.", "#aaa#.#aa#.#aaa#", "#abbb##ac##abcc#", ".##ab##ac##ac##.", "..#abc#ac#abc#..", "..#abc#ac#abc#..", "..#abc#ac#abc#..", "..#abc#ac#abc#..", "..#abbbbbbbbc#..", "...#abbbbbcc#...", "....##cccc##....", "......#ac#......", "......#ac#......", "......#ac#......", "......#ac#......", "......####......"}; //---------------------------------------------------------------------------- // PsiWidgetPlugin - base plugin class to avoid code duplication //---------------------------------------------------------------------------- PsiWidgetPlugin::PsiWidgetPlugin( QObject *parent ) : QObject( parent ) { initialized = false; } QWidget *PsiWidgetPlugin::createWidget(QWidget */* parent */) { return 0; } QString PsiWidgetPlugin::name() const { return "Psi Plugin"; } QString PsiWidgetPlugin::group() const { return "Psi"; } QString PsiWidgetPlugin::toolTip() const { return name(); } QString PsiWidgetPlugin::whatsThis() const { return "Psi Widget"; } QString PsiWidgetPlugin::includeFile() const { return "psiwidget.h"; } QString PsiWidgetPlugin::codeTemplate() const { return QString(); } QString PsiWidgetPlugin::domXml() const { return QString(); } QIcon PsiWidgetPlugin::icon() const { return QIconSet( QPixmap( (const char **)psiwidget_data ) ); } bool PsiWidgetPlugin::isContainer() const { return false; } void PsiWidgetPlugin::initialize( QDesignerFormEditorInterface * ) { if ( initialized ) return; initialized = true; } bool PsiWidgetPlugin::isInitialized() const { return initialized; } //---------------------------------------------------------------------------- // BusyWidgetPlugin //---------------------------------------------------------------------------- class BusyWidgetPlugin : public PsiWidgetPlugin { Q_OBJECT public: BusyWidgetPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new BusyWidget( parent ); } QString name() const { return "BusyWidget"; } QString domXml() const { return "\n" "\n"; } QString whatsThis() const { return "Widget for indicating that program is doing something."; } QString includeFile() const { return "busywidget.h"; } }; //---------------------------------------------------------------------------- // IconLabelPlugin //---------------------------------------------------------------------------- class IconLabelPlugin : public PsiWidgetPlugin { Q_OBJECT public: IconLabelPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new IconLabel( parent ); } QString name() const { return "IconLabel"; } QString domXml() const { return "\n" " \n" " \n" " 0\n" " 0\n" " 100\n" " 100\n" " \n" " \n" "\n"; } QString whatsThis() const { return "Label that can contain animated PsiIcon."; } QString includeFile() const { return "iconlabel.h"; } }; //---------------------------------------------------------------------------- // FancyLabelPlugin //---------------------------------------------------------------------------- class FancyLabelPlugin : public PsiWidgetPlugin { Q_OBJECT public: FancyLabelPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new FancyLabel( parent ); } QString name() const { return "FancyLabel"; } QString domXml() const { return "\n" " \n" " \n" " 0\n" " 0\n" " 100\n" " 100\n" " \n" " \n" "\n"; } QString whatsThis() const { return "Just a Fancy Label. Use it for decoration of dialogs. ;-)"; } QString includeFile() const { return "fancylabel.h"; } }; //---------------------------------------------------------------------------- // IconsetSelectPlugin //---------------------------------------------------------------------------- class IconsetSelectPlugin : public PsiWidgetPlugin { Q_OBJECT public: IconsetSelectPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new IconsetSelect( parent ); } QString name() const { return "IconsetSelect"; } QString domXml() const { return "\n" "\n"; } QString whatsThis() const { return "Widget for Iconset selection."; } QString includeFile() const { return "iconsetselect.h"; } }; //---------------------------------------------------------------------------- // IconsetDisplayPlugin //---------------------------------------------------------------------------- class IconsetDisplayPlugin : public PsiWidgetPlugin { Q_OBJECT public: IconsetDisplayPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new IconsetDisplay( parent ); } QString name() const { return "IconsetDisplay"; } QString domXml() const { return "\n" "\n"; } QString whatsThis() const { return "Displays all icons in Iconset."; } QString includeFile() const { return "iconsetdisplay.h"; } }; //---------------------------------------------------------------------------- // IconButtonPlugin //---------------------------------------------------------------------------- class IconButtonPlugin : public PsiWidgetPlugin { Q_OBJECT public: IconButtonPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new IconButton( parent ); } QString name() const { return "IconButton"; } QString domXml() const { return "\n" "\n"; } QString whatsThis() const { return "PushButton that can contain animated PsiIcon."; } QString includeFile() const { return "iconbutton.h"; } }; //---------------------------------------------------------------------------- // IconToolButtonPlugin //---------------------------------------------------------------------------- class IconToolButtonPlugin : public PsiWidgetPlugin { Q_OBJECT public: IconToolButtonPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new IconToolButton( parent ); } QString name() const { return "IconToolButton"; } QString domXml() const { return "\n" "\n"; } QString whatsThis() const { return "ToolButton that can contain animated PsiIcon."; } QString includeFile() const { return "icontoolbutton.h"; } }; //---------------------------------------------------------------------------- // PsiTextViewPlugin //---------------------------------------------------------------------------- class PsiTextViewPlugin : public PsiWidgetPlugin { Q_OBJECT public: PsiTextViewPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new PsiTextView( parent ); } QString name() const { return "PsiTextView"; } QString domXml() const { return "\n" "\n"; } QString whatsThis() const { return "Widget for displaying rich-text data, with inline Icons."; } QString includeFile() const { return "psitextview.h"; } }; //---------------------------------------------------------------------------- // URLLabelPlugin //---------------------------------------------------------------------------- class URLLabelPlugin : public PsiWidgetPlugin { Q_OBJECT public: URLLabelPlugin( QObject *parent = 0 ) : PsiWidgetPlugin( parent ) { // nothing to do } QWidget *createWidget(QWidget *parent) { return new URLLabel( parent ); } QString name() const { return "URLLabel"; } QString domXml() const { return "\n" " \n" " http://host\n" " \n" " \n" " The Title\n" " \n" "\n"; } QString whatsThis() const { return "Widget for displaying clickable URLs."; } QString includeFile() const { return "urllabel.h"; } }; //---------------------------------------------------------------------------- // AllPsiWidgetsPlugin //---------------------------------------------------------------------------- class AllPsiWidgetsPlugin : public QObject, public QDesignerCustomWidgetCollectionInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) public: AllPsiWidgetsPlugin(QObject *parent = 0) : QObject( parent ) { plugins.append( new BusyWidgetPlugin( this ) ); plugins.append( new IconLabelPlugin( this ) ); plugins.append( new FancyLabelPlugin( this ) ); plugins.append( new IconsetSelectPlugin( this ) ); plugins.append( new IconsetDisplayPlugin( this ) ); plugins.append( new IconButtonPlugin( this ) ); plugins.append( new IconToolButtonPlugin( this ) ); plugins.append( new PsiTextViewPlugin( this ) ); plugins.append( new URLLabelPlugin( this ) ); } virtual QList customWidgets() const { return plugins; } private: QList plugins; }; Q_EXPORT_PLUGIN( AllPsiWidgetsPlugin ); #include "psiwidgets.moc" psi-0.14/src/widgets/iconsetselect.h0000644000175000017500000000256311305557613015621 0ustar janjan/* * iconsetselect.h - contact list widget * Copyright (C) 2001-2005 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONSETSELECT_H #define ICONSETSELECT_H #include class Iconset; class IconsetSelectItem; class IconsetSelect : public QListWidget { Q_OBJECT public: IconsetSelect(QWidget *parent = 0); ~IconsetSelect(); void insert(const Iconset &); // iconsets must be inserted in following order: most prioritent first const Iconset *iconset() const; QListWidgetItem *lastItem() const; QStyleOptionViewItem viewOptions() const; public slots: void moveItemUp(); void moveItemDown(); private: friend class IconsetSelectItem; }; #endif psi-0.14/src/widgets/psirichtext.cpp0000644000175000017500000003032311305557613015651 0ustar janjan/* * psirichtext.h - helper functions to handle Icons in QTextDocuments * Copyright (C) 2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psirichtext.h" #include #include #include #include // for QTextObjectInterface #include #include #include #include #include #include #include #include #include #include "textutil.h" #ifndef WIDGET_PLUGIN #include "iconset.h" #else class PsiIcon; class Iconset; #endif static const int IconFormatType = 0x1000; //---------------------------------------------------------------------------- // TextIconFormat //---------------------------------------------------------------------------- class TextIconFormat : public QTextCharFormat { public: TextIconFormat(const QString &iconName, const QString &text); enum Property { IconName = QTextFormat::UserProperty + 1, IconText = QTextFormat::UserProperty + 2 }; }; TextIconFormat::TextIconFormat(const QString &iconName, const QString &text) : QTextCharFormat() { Q_UNUSED(text); setObjectType(IconFormatType); QTextFormat::setProperty(IconName, iconName); QTextFormat::setProperty(IconText, text); // TODO: handle animations } //---------------------------------------------------------------------------- // IconTextObjectInterface //---------------------------------------------------------------------------- #ifndef WIDGET_PLUGIN class TextIconHandler : public QObject, public QTextObjectInterface { Q_OBJECT Q_INTERFACES(QTextObjectInterface) public: TextIconHandler(QObject *parent = 0); virtual QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format); virtual void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format); }; TextIconHandler::TextIconHandler(QObject *parent) : QObject(parent) { } QSizeF TextIconHandler::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) { Q_UNUSED(doc); Q_UNUSED(posInDocument) const QTextCharFormat charFormat = format.toCharFormat(); return IconsetFactory::iconPixmap(charFormat.stringProperty(TextIconFormat::IconName)).size(); } void TextIconHandler::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) { Q_UNUSED(doc); Q_UNUSED(posInDocument); const QTextCharFormat charFormat = format.toCharFormat(); const QPixmap pixmap = IconsetFactory::iconPixmap(charFormat.stringProperty(TextIconFormat::IconName)); painter->drawPixmap(rect, pixmap, pixmap.rect()); } #endif // WIDGET_PLUGIN //---------------------------------------------------------------------------- // PsiRichText //---------------------------------------------------------------------------- /** * You need to call this function on your QTextDocument to make it * capable of displaying inline Icons. Uninstaller ships separately. */ void PsiRichText::install(QTextDocument *doc) { Q_ASSERT(doc); #ifndef WIDGET_PLUGIN static TextIconHandler *handler = 0; if (!handler) handler = new TextIconHandler(qApp); doc->documentLayout()->registerHandler(IconFormatType, handler); #endif } /** * Make sure that QTextDocument has correctly layouted its text. */ void PsiRichText::ensureTextLayouted(QTextDocument *doc, int documentWidth, Qt::Alignment align, Qt::LayoutDirection layoutDirection, bool textWordWrap) { // from QLabelPrivate::ensureTextLayouted Q_UNUSED(textWordWrap); Q_UNUSED(layoutDirection); Q_UNUSED(align); // bah, QTextDocumentLayout is private :-/ // QTextDocumentLayout *lout = qobject_cast(doc->documentLayout()); // Q_ASSERT(lout); // // int flags = (textWordWrap ? 0 : Qt::TextSingleLine) | align; // flags |= (layoutDirection == Qt::RightToLeft) ? QTextDocumentLayout::RTL : QTextDocumentLayout::LTR; // lout->setBlockTextFlags(flags); // // if (textWordWrap) { // // ensure that we break at words and not just about anywhere // lout->setWordWrapMode(QTextOption::WordWrap); // } QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); fmt.setMargin(0); doc->rootFrame()->setFrameFormat(fmt); doc->setTextWidth(documentWidth); } /** * Inserts an PsiIcon into document. * \param cursor this cursor is used to insert icon * \param iconName icon's name, by which it could be found in IconsetFactory * \param iconText icon's text, used when copy operation is performed */ void PsiRichText::insertIcon(QTextCursor &cursor, const QString &iconName, const QString &iconText) { #ifdef WIDGET_PLUGIN Q_UNUSED(cursor); Q_UNUSED(iconName); Q_UNUSED(iconText); #else QTextCharFormat format = cursor.charFormat(); TextIconFormat icon(iconName, iconText); cursor.insertText(QString(QChar::ObjectReplacementCharacter), icon); cursor.setCharFormat(format); #endif } typedef QQueue TextIconFormatQueue; /** * Adds null format to queue for all ObjectReplacementCharacters that were * already in the text. Returns passed \param text to save some code. */ static QString preserveOriginalObjectReplacementCharacters(QString text, TextIconFormatQueue *queue) { int objReplChars = 0; objReplChars += text.count(QChar::ObjectReplacementCharacter); // tags are replaced to ObjectReplacementCharacters // internally by Qt functions. // But we must be careful if some other character instead of // 0x20 is used immediately after tag opening, this could // create a hole. ejabberd protects us from it though. objReplChars += text.count("enqueue(0); return text; } /** * Replaces all tags with handy ObjectReplacementCharacters, and * adds appropriate format to the \param queue. Returns processed * \param text. */ static QString convertIconsToObjectReplacementCharacters(QString text, TextIconFormatQueue *queue) { // Format: static QRegExp rxName("name=\"([^\"]+)\""); static QRegExp rxText("text=\"([^\"]+)\""); QString result; QString work = text; forever { int start = work.indexOf("", start); Q_ASSERT(end != -1); QString fragment = work.mid(start, end - start); if (rxName.indexIn(fragment) != -1) { QString iconName = TextUtil::unescape(rxName.capturedTexts()[1]); QString iconText; if (rxText.indexIn(fragment) != -1) iconText = TextUtil::unescape(rxText.capturedTexts()[1]); queue->enqueue(new TextIconFormat(iconName, iconText)); result += QChar::ObjectReplacementCharacter; } work = work.mid(end + 1); } return result + preserveOriginalObjectReplacementCharacters(work, queue); } /** * Applies text formats from \param queue to all ObjectReplacementCharacters * in \param doc, starting from \param cursor's position. */ static void applyFormatToIcons(QTextDocument *doc, TextIconFormatQueue *queue, QTextCursor &cursor) { QTextCursor searchCursor = cursor; forever { searchCursor = doc->find(QString(QChar::ObjectReplacementCharacter), searchCursor); if (searchCursor.isNull()) break; Q_ASSERT(!queue->isEmpty()); TextIconFormat *format = queue->dequeue(); if (format) { searchCursor.setCharFormat(*format); delete format; } } // if it's not true, there's a memleak Q_ASSERT(queue->isEmpty()); // clear the selection that's left after successful QTextDocument::find() cursor.clearSelection(); } /** * Groups some related function calls together. */ static void appendTextHelper(QTextDocument *doc, QString text, QTextCursor &cursor) { TextIconFormatQueue queue; // we need to save this to start searching from // here when applying format to icons int initialpos = cursor.position(); cursor.insertFragment(QTextDocumentFragment::fromHtml(convertIconsToObjectReplacementCharacters(text, &queue))); cursor.setPosition(initialpos); applyFormatToIcons(doc, &queue, cursor); } /** * Sets entire contents of specified QTextDocument to text. * \param text text to append to the QTextDocument. Please note that if you * insert any s, attributes' values MUST be Qt::escaped. */ void PsiRichText::setText(QTextDocument *doc, const QString &text) { QFont font = doc->defaultFont(); doc->clear(); QTextCursor cursor(doc); QTextCharFormat charFormat = cursor.charFormat(); charFormat.setFont(font); cursor.setCharFormat(charFormat); appendText(doc, cursor, text); } /** * Appends a new paragraph with text to the end of the document. * \param text text to append to the QTextDocument. Please note that if you * insert any s, attributes' values MUST be Qt::escaped. */ void PsiRichText::appendText(QTextDocument *doc, QTextCursor &cursor, const QString &text) { cursor.beginEditBlock(); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.clearSelection(); if (!cursor.atBlockStart()) { cursor.insertBlock(); // clear trackbar for new blocks QTextBlockFormat blockFormat = cursor.blockFormat(); blockFormat.clearProperty(QTextFormat::BlockTrailingHorizontalRulerWidth); cursor.setBlockFormat(blockFormat); } appendTextHelper(doc, text, cursor); cursor.endEditBlock(); } /** * Call this function on your QTextDocument to get plain text * representation, and all Icons will be replaced by their * initial text. */ QString PsiRichText::convertToPlainText(const QTextDocument *doc) { QString obrepl = QString(QChar::ObjectReplacementCharacter); QQueue queue; QTextCursor nc = doc->find(obrepl, 0); QTextCursor cursor; while (!nc.isNull()) { queue.enqueue(nc.charFormat()); cursor = nc; nc = doc->find(obrepl, cursor); } QString raw = doc->toPlainText(); QStringList parts = raw.split(obrepl); QString result = parts.at(0); for (int i = 1; i < parts.size(); ++i) { if (!queue.isEmpty()) { QTextCharFormat format = queue.dequeue(); if ((format).objectType() == IconFormatType) { result += format.stringProperty(TextIconFormat::IconText); } } result += parts.at(i); } return result; } /** * Adds \a emoticon to \a textEdit. */ void PsiRichText::addEmoticon(QTextEdit *textEdit, const QString &emoticon) { Q_ASSERT(textEdit); if (!textEdit || emoticon.isEmpty()) return; QString text = emoticon + ' '; QTextCursor cursor = textEdit->textCursor(); PsiRichText::Selection selection = PsiRichText::saveSelection(textEdit, cursor); cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1); if (!cursor.selectedText().isEmpty() && !cursor.selectedText().at(0).isSpace()) text = " " + text; textEdit->insertPlainText(text); PsiRichText::restoreSelection(textEdit, cursor, selection); } /** * Saves current Selection in a structure, so it could be restored at later time. */ PsiRichText::Selection PsiRichText::saveSelection(QTextEdit *textEdit, QTextCursor &cursor) { Selection selection; selection.start = selection.end = -1; if (cursor.hasSelection()) { selection.start = cursor.selectionStart(); selection.end = cursor.selectionEnd(); } return selection; } /** * Restores a Selection that was previously saved by call to saveSelection(). */ void PsiRichText::restoreSelection(QTextEdit *textEdit, QTextCursor &cursor, PsiRichText::Selection selection) { if (selection.start != -1 && selection.end != -1) { cursor.setPosition(selection.start, QTextCursor::MoveAnchor); cursor.setPosition(selection.end, QTextCursor::KeepAnchor); } } #ifndef WIDGET_PLUGIN #include "psirichtext.moc" #endif psi-0.14/src/widgets/psiwidgets.h0000644000175000017500000000324211305557613015132 0ustar janjan/* * psiwidgets.h - plugin for loading Psi's custom widgets into Qt Designer * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIWIDGETSPLUGIN_H #define PSIWIDGETSPLUGIN_H #include #include #include class PsiWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_INTERFACES( QDesignerCustomWidgetInterface ) public: PsiWidgetPlugin(QObject *parent = 0); virtual QWidget *createWidget(QWidget *parent); virtual QString name() const; virtual QString group() const; virtual QString toolTip() const; virtual QString whatsThis() const; virtual QString includeFile() const; virtual QString codeTemplate() const; virtual QString domXml() const; virtual QIcon icon() const; virtual bool isContainer() const; void initialize( QDesignerFormEditorInterface * ); bool isInitialized() const; private: bool initialized; }; #endif psi-0.14/src/widgets/widgets.pri0000644000175000017500000000211211305557613014754 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += \ $$PWD/busywidget.cpp \ $$PWD/fancylabel.cpp \ $$PWD/iconselect.cpp \ $$PWD/iconwidget.cpp \ $$PWD/psitextview.cpp \ $$PWD/urllabel.cpp \ $$PWD/urlobject.cpp \ $$PWD/iconaction.cpp \ $$PWD/fancypopup.cpp \ $$PWD/psirichtext.cpp \ $$PWD/psitooltip.cpp \ $$PWD/psitiplabel.cpp \ $$PWD/psitabwidget.cpp \ $$PWD/psitabbar.cpp \ $$PWD/actionlineedit.cpp HEADERS += \ $$PWD/stretchwidget.h \ $$PWD/busywidget.h \ $$PWD/fancylabel.h \ $$PWD/iconselect.h \ $$PWD/iconsetselect.h \ $$PWD/iconsetdisplay.h \ $$PWD/iconwidget.h \ $$PWD/iconbutton.h \ $$PWD/psitextview.h \ $$PWD/iconaction.h \ $$PWD/fancypopup.h \ $$PWD/urllabel.h \ $$PWD/urlobject.h \ $$PWD/updatingcombobox.h \ $$PWD/iconlabel.h \ $$PWD/icontoolbutton.h \ $$PWD/fancypopuplist.h \ $$PWD/psirichtext.h \ $$PWD/psitooltip.h \ $$PWD/psitiplabel.h \ $$PWD/psitabwidget.h \ $$PWD/psitabbar.h \ $$PWD/actionlineedit.h # to remove dependency on iconset and stuff #DEFINES += WIDGET_PLUGIN # where to search for widgets plugin #QMAKE_UIC += -L $$PWD psi-0.14/src/widgets/fancypopup.cpp0000644000175000017500000002546711305557613015504 0ustar janjan/* * fancypopup.cpp - the FancyPopup passive popup widget * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "fancypopup.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "iconset.h" #include "fancylabel.h" #include "iconlabel.h" #include "psitooltip.h" #define BUTTON_WIDTH 16 #define BUTTON_HEIGHT 14 /*static int checkComponent(int b) { int c = b; if ( c > 0xFF ) c = 0xFF; return c; } static QColor makeColor(QColor baseColor, int percent) { float p = (float)percent/100; int r = checkComponent( (int)(baseColor.red() + ((float)p * baseColor.red())) ); int g = checkComponent( (int)(baseColor.green() + ((float)p * baseColor.green())) ); int b = checkComponent( (int)(baseColor.blue() + ((float)p * baseColor.blue())) ); return QColor(r, g, b); }*/ //---------------------------------------------------------------------------- // FancyPopup::Private //---------------------------------------------------------------------------- class FancyPopup::Private : public QObject { Q_OBJECT public: Private(FancyPopup *p); ~Private(); QPoint position(); class BackgroundWidget : public QWidget { public: BackgroundWidget(QWidget *parent) : QWidget(parent) { } void setBackground(QPixmap pix) { background = pix; } private: QPixmap background; protected: void paintEvent(QPaintEvent *) { QPainter *p = new QPainter(this); p->drawTiledPixmap(0, 0, width(), height(), background); delete p; } }; bool eventFilter(QObject *o, QEvent *e); public slots: void popupDestroyed(QObject *); public: void initContents(QString title, const PsiIcon *icon, bool copyIcon); // parameters static int hideTimeout; static QColor backgroundColor; enum PopupLayout { TopToBottom = 1, BottomToTop = -1 }; PopupLayout popupLayout; QList prevPopups; QBoxLayout *layout; FancyPopup *popup; QTimer *hideTimer; }; int FancyPopup::Private::hideTimeout = 5 * 1000; // 5 seconds QColor FancyPopup::Private::backgroundColor = QColor (0x52, 0x97, 0xF9); FancyPopup::Private::Private(FancyPopup *p) : QObject(p) { popup = p; hideTimer = new QTimer(this); connect(hideTimer, SIGNAL(timeout()), popup, SLOT(hide())); } FancyPopup::Private::~Private() { } void FancyPopup::Private::popupDestroyed(QObject *obj) { if ( prevPopups.contains((FancyPopup *)obj) ) { prevPopups.removeAll((FancyPopup *)obj); popup->move( position() ); } } QPoint FancyPopup::Private::position() { QRect geom = qApp->desktop()->availableGeometry(popup); QPoint destination(geom.x() + geom.width(), geom.y() + geom.height()); // in which corner popup should appear if ( destination.y() > (qApp->desktop()->screenGeometry().height()/2) ) popupLayout = Private::BottomToTop; else popupLayout = Private::TopToBottom; if ( (destination.x() + popup->width()) > (geom.x() + geom.width()) ) destination.setX( geom.x() + geom.width() - popup->width() ); if ( destination.x() < 0 ) destination.setX( 0 ); if ( (destination.y() + popup->height()) > (geom.y() + geom.height()) ) destination.setY( geom.y() + geom.height() - popup->height() ); if ( destination.y() < 0 ) destination.setY( 0 ); foreach ( FancyPopup *p, prevPopups ) destination.setY( destination.y() + popupLayout * p->height() ); return destination; } void FancyPopup::Private::initContents(QString title, const PsiIcon *icon, bool copyIcon) { // TODO: use darker color on popup borders QPalette backgroundPalette; backgroundPalette.setBrush(QPalette::Background, QBrush(backgroundColor)); QPixmap back(1, 1); back.fill(backgroundColor); QVBoxLayout *vbox = new QVBoxLayout(popup); vbox->setMargin(0); vbox->setSpacing(0); // top row QHBoxLayout *tophbox = new QHBoxLayout; vbox->addLayout(tophbox); QLabel *top1 = new QLabel(popup); top1->setAutoFillBackground(true); top1->setFixedWidth(3); top1->setPalette(backgroundPalette); tophbox->addWidget(top1); QVBoxLayout *topvbox = new QVBoxLayout; tophbox->addLayout(topvbox); QLabel *top2 = new QLabel(popup); top2->setAutoFillBackground(true); top2->setFixedHeight(1); top2->setPalette(backgroundPalette); topvbox->addWidget(top2); QHBoxLayout *tophbox2 = new QHBoxLayout; topvbox->addLayout(tophbox2); IconLabel *titleIcon = new IconLabel(popup); titleIcon->setAutoFillBackground(true); titleIcon->setPsiIcon(icon, copyIcon); titleIcon->setPalette(backgroundPalette); tophbox2->addWidget(titleIcon); QLabel *top5 = new QLabel(popup); top5->setAutoFillBackground(true); top5->setFixedWidth(3); top5->setPalette(backgroundPalette); tophbox2->addWidget(top5); // title label QLabel *titleText = new QLabel(popup); titleText->setAutoFillBackground(true); QBrush titleFontColor; if ( (backgroundColor.red() + backgroundColor.green() + backgroundColor.blue())/3 > 128 ) titleFontColor = QBrush(Qt::white); else titleFontColor = QBrush(Qt::black); QPalette titlePalette = backgroundPalette; titlePalette.setBrush(QPalette::Text, titleFontColor); titleText->setPalette(titlePalette); QFont titleFont = titleText->font(); titleFont.setBold(true); titleText->setFont(titleFont); titleText->setText( title ); titleText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); tophbox2->addWidget(titleText); // 2-pixel space Private::BackgroundWidget *spacing = new Private::BackgroundWidget(popup); spacing->setBackground(back); tophbox2->addWidget(spacing); QVBoxLayout *spacingLayout = new QVBoxLayout(spacing); spacingLayout->addSpacing(2); // close button Private::BackgroundWidget *closeButtonBack = new Private::BackgroundWidget(popup); closeButtonBack->setBackground(back); tophbox2->addWidget(closeButtonBack); QVBoxLayout *closeButtonBackLayout = new QVBoxLayout(closeButtonBack); closeButtonBackLayout->setMargin(0); closeButtonBackLayout->addStretch(); QToolButton *closeButton = new QToolButton(closeButtonBack); closeButton->setObjectName("closeButton"); closeButton->setToolTip(tr("Close")); closeButtonBackLayout->addWidget( closeButton ); closeButtonBackLayout->addStretch(); closeButton->setFocusPolicy( Qt::NoFocus ); closeButton->setIcon( popup->style()->standardPixmap(QStyle::SP_TitleBarCloseButton) ); closeButton->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT); connect(closeButton, SIGNAL(clicked()), popup, SLOT(hide())); QLabel *top3 = new QLabel(popup); top3->setAutoFillBackground(true); top3->setFixedHeight(1); top3->setPalette(backgroundPalette); topvbox->addWidget(top3); QLabel *top4 = new QLabel(popup); top4->setAutoFillBackground(true); top4->setFixedWidth(3); top4->setPalette(backgroundPalette); tophbox->addWidget(top4); // middle row QHBoxLayout *middlehbox = new QHBoxLayout; vbox->addLayout(middlehbox); QLabel *middle1 = new QLabel(popup); middle1->setAutoFillBackground(true); middle1->setFixedWidth(4); middle1->setPalette(backgroundPalette); middlehbox->addWidget(middle1); middlehbox->addSpacing(5); QVBoxLayout *middlevbox = new QVBoxLayout; middlehbox->addLayout(middlevbox); middlevbox->addSpacing(5); layout = middlevbox; // we'll add more items later in addLayout() middlehbox->addSpacing(5); QLabel *middle3 = new QLabel(popup); middle3->setAutoFillBackground(true); middle3->setFixedWidth(4); middle3->setPalette(backgroundPalette); middlehbox->addWidget(middle3); // bottom row QHBoxLayout *bottomhbox = new QHBoxLayout; vbox->addLayout(bottomhbox); QLabel *bottom1 = new QLabel(popup); bottom1->setAutoFillBackground(true); bottom1->setFixedSize( 4, 4 ); bottom1->setPalette(backgroundPalette); bottomhbox->addWidget(bottom1); QLabel *bottom2 = new QLabel(popup); bottom2->setAutoFillBackground(true); bottom2->setFixedHeight(4); bottom2->setPalette(backgroundPalette); bottomhbox->addWidget(bottom2); QLabel *bottom3 = new QLabel(popup); bottom3->setAutoFillBackground(true); bottom3->setFixedSize( 4, 4 ); bottom3->setPalette(backgroundPalette); bottomhbox->addWidget(bottom3); } bool FancyPopup::Private::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::MouseButtonRelease) popup->mouseReleaseEvent((QMouseEvent *)e); return QObject::eventFilter(o, e); } //---------------------------------------------------------------------------- // FancyPopup //---------------------------------------------------------------------------- static const QFlags POPUP_FLAGS = Qt::ToolTip | Qt::WindowStaysOnTopHint; // | Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint; FancyPopup::FancyPopup(QString title, const PsiIcon *icon, FancyPopup *prev, bool copyIcon) : QFrame( 0, POPUP_FLAGS ) { QWidget::setAttribute(Qt::WA_DeleteOnClose); setWindowModality(Qt::NonModal); d = new Private(this); if ( prev ) { QList prevPopups = prev->d->prevPopups; prevPopups.append(prev); foreach (FancyPopup *popup, prevPopups) { d->prevPopups.append( popup ); connect(popup, SIGNAL(destroyed(QObject *)), d, SLOT(popupDestroyed(QObject *))); } } d->initContents(title, icon, copyIcon); } FancyPopup::~FancyPopup() { } void FancyPopup::addLayout(QLayout *layout, int stretch) { d->layout->addLayout(layout, stretch); d->layout->addSpacing(5); } void FancyPopup::show() { if ( size() != sizeHint() ) resize( sizeHint() ); // minimumSizeHint() // QLabels with rich contents don't propagate mouse clicks QList labels = findChildren(); foreach(QLabel *label, labels) label->installEventFilter(d); // position popup move ( d->position() ); // display popup restartHideTimer(); QFrame::show(); } void FancyPopup::hideEvent(QHideEvent *e) { d->hideTimer->stop(); deleteLater(); QFrame::hideEvent(e); } void FancyPopup::mouseReleaseEvent(QMouseEvent *e) { if (!isVisible()) return; emit clicked((int)e->button()); hide(); } void FancyPopup::restartHideTimer() { d->hideTimer->start( d->hideTimeout ); } void FancyPopup::setHideTimeout(int time) { FancyPopup::Private::hideTimeout = time; } void FancyPopup::setBorderColor(QColor c) { FancyPopup::Private::backgroundColor = c; } #include "fancypopup.moc" psi-0.14/src/widgets/busywidget.cpp0000644000175000017500000003007311305557613015473 0ustar janjan/* * busywidget.cpp - cool animating widget * Copyright (C) 2001, 2002 Justin Karneges * Hideaki Omuro * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "busywidget.h" #include #include #include #include ///////////////////////////////////////////////////////////////////////////// // common defines // #define FPS 20 // frequency of update #define SPINRATE 24 // 1024ths of a revolution per frame #define SPINOFFSET 4 // frames each panel is offset by #define COLORSTOPPED 0xFFFFFF // color when stopped #define COLORSPINNING 0xFFFFFF // color when spinning #define COLORSHADOW 0x000000 // color of shadow ///////////////////////////////////////////////////////////////////////////// // derived defines // #define MSECSPERFRAME (1000 / FPS) ///////////////////////////////////////////////////////////////////////////// // declared later // extern char psigraphic[]; // panel class class CPanel { public: int angle; int height; bool spinning; int alpha; CPanel(int height = 1); int GetModHeight(); int GetShade(); void Spin(int n); void SetAngle(int _angle) { angle = _angle % 1024; } void SetHeight(int _height) { height = _height; } int GetAngle() { return angle % 1024; } int GetHeight() { return height; } int GetModOffset() { return (height - GetModHeight()) / 2; } }; // color class class CColor { public: int m_clr; CColor(int _r, int _g, int _b) { SetColor(_r, _g, _b); } CColor(int _clr) { SetColor(_clr); } inline void SetColor(int _r, int _g, int _b) { SetColor((_r << 16) + (_g << 8) + _b); } inline void SetColor(int _clr) { m_clr = _clr; } inline short GetR() { return m_clr >> 16; } inline short GetG() { return (m_clr >> 8) & 255; } inline short GetB() { return m_clr & 255; } CColor Alpha(CColor clr, int alpha = 256); }; class BusyWidget::Private : public QObject { Q_OBJECT private: BusyWidget *busy; public: Private(BusyWidget *b) { t = 0; busy = b; stopInProgress = false; } bool stopInProgress; bool isActive; int frame; int at; QPixmap pix; QTimer *t; // data CPanel panel[5]; int pcountdown; int ocountdown; void render() { busy->update(); } void renderPixmap() { pix = QPixmap(busy->width(), busy->height()); pix.fill(QColor("#406080")); QPainter p(&pix); int i, j, k, l; int row; for(i = 0; i < 5; i++) { int o = panel[i].GetModOffset(); CColor c1(COLORSPINNING), c2(COLORSTOPPED), c3(COLORSHADOW); CColor b = c1.Alpha(c2, panel[i].alpha * 8); CColor a = b.Alpha(c3, panel[i].GetShade()); l = panel[i].GetModHeight(); double radangle = (double) 3.1415926f * (double) panel[i].GetAngle() / (double) 512; int step = (int)((double)1024 / cos(radangle)); step = step < 0 ? -step : step; int n = (int)((double)1024 * cos(radangle) * 17 / 2); n = n < 0 ? -n : n; row = 8192 - step * n / 1024; QColor clr(a.GetR(), a.GetG(), a.GetB()); for(j = 0; j < l; j++) { int m = row / 1024 + 1; for(k = 0; k < 16; k++) { p.setPen(psigraphic[i * 304 + m * 16 + k] ? Qt::black : clr); p.drawPoint(i * 16 + k + 1, o + j + 1); } row += step; } } p.setPen(Qt::black); p.drawRect(0, 0, busy->width(), busy->height()); } public slots: void stop() { if ( stopInProgress ) { stopInProgress = false; isActive = false; if( !ocountdown ) ocountdown = SPINOFFSET * 4 + 1; } } }; ///////////////////////////////////////////////////////////////////////////// // code // BusyWidget::BusyWidget(QWidget *parent) :QWidget(parent) { d = new Private(this); d->isActive = false; d->frame = 0; d->at = 0; d->pcountdown = 0; d->ocountdown = 0; setFixedSize(sizeHint()); setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); int i; for(i = 0; i < 5; i++) d->panel[i].SetHeight(17); d->renderPixmap(); } BusyWidget::~BusyWidget() { delete d; } QSize BusyWidget::minimumSizeHint() const { return QSize( 82, 19 ); } QSize BusyWidget::sizeHint() const { return minimumSizeHint(); } bool BusyWidget::isActive() const { return (d->isActive && !d->stopInProgress); } void BusyWidget::setActive(bool a) { if ( a ) start(); else stop(); } void BusyWidget::start() { d->stopInProgress = false; if(d->isActive) return; d->isActive = true; if(!d->pcountdown) d->pcountdown = SPINOFFSET * 4 + 1; if(!d->t) { d->t = new QTimer(this); connect(d->t, SIGNAL(timeout()), SLOT(animate())); animate(); d->t->start(MSECSPERFRAME); } } void BusyWidget::stop() { if(!d->isActive) return; if ( d->stopInProgress ) return; d->stopInProgress = true; QTimer::singleShot(0, d, SLOT(stop())); } void BusyWidget::animate() { int i; for(i = 0; i < 5; i++) d->panel[i].Spin(SPINRATE); if(d->pcountdown) if(!(--d->pcountdown % SPINOFFSET)) d->panel[d->pcountdown / SPINOFFSET].spinning = true; if(d->ocountdown) if(!(--d->ocountdown % SPINOFFSET)) d->panel[d->ocountdown / SPINOFFSET].spinning = false; if(!d->isActive) { bool isValid = false; for(i = 0; i < 5; i++) if(d->panel[i].spinning || d->panel[i].GetAngle() != 0 || d->panel[i].alpha != 0) isValid = true; if(!isValid) { if (d->t) d->t->deleteLater(); d->t = 0; } } d->renderPixmap(); d->render(); } void BusyWidget::paintEvent(QPaintEvent *) { QPainter p(this); p.drawPixmap(0,0, d->pix); } void BusyWidget::resizeEvent(QResizeEvent *) { d->renderPixmap(); } ///////////////////////////////////////////////////////////////////////// // stuff beyond here for animating rotating psi panels // // color stuff CColor CColor::Alpha(CColor clr, int alpha) { int ialpha = 256 - alpha; int r, g, b; r = (alpha * GetR() + ialpha * clr.GetR()) / 256; g = (alpha * GetG() + ialpha * clr.GetG()) / 256; b = (alpha * GetB() + ialpha * clr.GetB()) / 256; return CColor(r, g, b); } // panel stuff CPanel::CPanel(int _height) { height = _height; spinning = false; angle = 0; alpha = 0; } int CPanel::GetModHeight() { int l = GetAngle(); if(l > 512) l = 1024 - l; double radangle = (double) 3.1415926f * (double) l / (double) 512; int tmp = (int)(cos(radangle)* (double) height); return tmp < 0 ? -tmp : tmp; } int CPanel::GetShade() { int l = GetAngle() + 128; if(GetAngle() >= 256 && GetAngle() < 768) l += 512; if(l >= 1024) l %= 1024; if(l == 0) l += 1024; double radangle = (double) 3.1415926f * (double) l / (double) 512; return 128 + (int)(cos(radangle)* (double) 128); } void CPanel::Spin(int n) { int i = angle + n; if(!spinning) { if(i >= 1024) SetAngle(0); if(angle < 512 && i >= 512) SetAngle(0); if(angle) SetAngle(i); } else SetAngle(i); if(spinning) { if(alpha < 32) alpha+=2; } else { if(alpha) alpha-=2; } } char psigraphic[304*5] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #include "busywidget.moc" psi-0.14/src/widgets/iconwidget.cpp0000644000175000017500000004203111305557613015436 0ustar janjan/* * iconwidget.cpp - misc. Iconset- and PsiIcon-aware widgets * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconwidget.h" #include "iconsetdisplay.h" #include "iconsetselect.h" #include "icontoolbutton.h" #include "iconbutton.h" #include #include #include #ifndef WIDGET_PLUGIN # include "iconset.h" # include # include # include # include "pixmaputil.h" #else # include static const char *cancel_xpm[] = { "22 22 60 1", " c None", ". c #E84300", "+ c #E63F00", "@ c #D11E00", "# c #D11B00", "$ c #F69D50", "% c #F59A4D", "& c #E23800", "* c #EE5F1F", "= c #ED5A1D", "- c #CD1700", "; c #FECBA2", "> c #FEC69A", ", c #F39045", "' c #DE3200", ") c #FE7B3C", "! c #FE7234", "~ c #EC4C15", "{ c #CC1100", "] c #FEC091", "^ c #FEBA89", "/ c #F2873D", "( c #DA2C00", "_ c #FE692C", ": c #EB4712", "< c #CA0F00", "[ c #FEB480", "} c #FEAE78", "| c #F07D35", "1 c #D62600", "2 c #FEA870", "3 c #FEA166", "4 c #EF722D", "5 c #D32100", "6 c #FE9B5F", "7 c #FE9356", "8 c #F16C2A", "9 c #F16525", "0 c #FE8B4D", "a c #FE8445", "b c #EE4B15", "c c #FE6025", "d c #EE4310", "e c #C90E00", "f c #FE561D", "g c #FE4B16", "h c #EA2F08", "i c #C70900", "j c #FE4010", "k c #FE350B", "l c #EA1D03", "m c #C60700", "n c #FE2906", "o c #FE1A02", "p c #E90900", "q c #C50300", "r c #FE0A00", "s c #FE0000", "t c #E90000", "u c #C40000", " ", " ", " .+ @# ", " .$%& @*=- ", " .$;>,' @*)!~{ ", " +%>]^/( @*)!_:< ", " &,^[}|1 @*)!_:< ", " '/}2345@*)!_:< ", " (|36789)!_:< ", " 1470a)!_:< ", " 58a)!_b< ", " @9)!_cde ", " @*)!_cfghi ", " @*)!_bdgjklm ", " @*)!_:data(index, Qt::SizeHintRole).toSize(); } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const QAbstractItemModel *model = index.model(); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; // draw the background color if (option.showDecorationSelected && (option.state & QStyle::State_Selected)) { painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight)); painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); QVariant value = model->data(index, Qt::BackgroundRole); if (value.isValid() && qvariant_cast(value).isValid()) painter->fillRect(option.rect, qvariant_cast(value)); } painter->drawPixmap(option.rect.topLeft(), model->data(index, Qt::DecorationRole).value()); QVariant textPosition = model->data(index, RealIconWidgetItem::TextPositionRole); if (textPosition.isValid() && !qvariant_cast(textPosition).isNull()) painter->drawText(option.rect.topLeft() + qvariant_cast(textPosition), model->data(index, Qt::DisplayRole).value()); if (option.state & QStyle::State_HasFocus) { QStyleOptionFocusRect o; o.QStyleOption::operator=(option); QRect r = option.rect; QPoint margin(1, 1); o.rect = QRect(r.topLeft() + margin, r.bottomRight() - margin); o.state |= QStyle::State_KeyboardFocusChange; o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Background); QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); } } }; //---------------------------------------------------------------------------- // IconsetSelect //---------------------------------------------------------------------------- class IconsetSelectItem : public RealIconWidgetItem { Q_OBJECT private: static const int margin; static const int displayNumIcons; #ifndef WIDGET_PLUGIN Iconset iss; QMap iconRects; #endif int w, h; mutable int fullW, fullH; public: IconsetSelectItem(QListWidget *parent, const Iconset &_iconset) : RealIconWidgetItem(parent) { #ifndef WIDGET_PLUGIN iss = _iconset; setText( iss.name() ); w = margin; h = 2*margin; int count; QListIterator it = iss.iterator(); count = 0; while ( it.hasNext() ) { if ( count++ >= displayNumIcons ) break; // display only first displayNumIcons icons PsiIcon *icon = it.next(); QPixmap pix = icon->pixmap(); iconRects[icon] = QRect( w, margin, pix.width(), pix.height() ); w += pix.width() + margin; h = qMax( h, pix.height() + 2*margin ); connect(icon, SIGNAL(pixmapChanged()), SLOT(update())); icon->activated(false); // start animation } QMutableMapIterator it2(iconRects); while (it2.hasNext()) { it2.next(); QRect r = it2.value(); it2.setValue(QRect(r.x(), (h - r.height()) / 2, r.width(), r.height())); } #else Q_UNUSED( _iconset ); #endif } ~IconsetSelectItem() { #ifndef WIDGET_PLUGIN QMap::Iterator it; for (it = iconRects.begin(); it != iconRects.end(); it++) it.key()->stop(); #endif } const Iconset *iconset() const { #ifndef WIDGET_PLUGIN return &iss; #else return 0; #endif } int height() const { int hh = listWidget()->fontMetrics().lineSpacing() + h; return qMax( hh, QApplication::globalStrut().height() ); } int width() const { int ww = qMax(listWidget()->fontMetrics().width( text() ) + 6 + 15, w + 10); return qMax( ww, QApplication::globalStrut().width() ); } void paint(QPainter *painter) const { #ifndef WIDGET_PLUGIN QFontMetrics fm = painter->fontMetrics(); QMap::ConstIterator it; for (it = iconRects.begin(); it != iconRects.end(); it++) { PsiIcon *icon = it.key(); QRect r = it.value(); painter->drawPixmap(QPoint(10 + r.left(), fm.lineSpacing() + 2 + r.top()), icon->pixmap()); } #else Q_UNUSED(painter); #endif } QPoint textPosition(QPainter *painter) const { QFontMetrics fm = painter->fontMetrics(); return QPoint(3, fm.ascent() + (fm.leading()+1)/2 + 1); } }; const int IconsetSelectItem::margin = 3; const int IconsetSelectItem::displayNumIcons = 10; IconsetSelect::IconsetSelect(QWidget *parent) : QListWidget(parent) { setItemDelegate(new IconWidgetDelegate(this)); } IconsetSelect::~IconsetSelect() { } void IconsetSelect::insert(const Iconset &iconset) { #ifndef WIDGET_PLUGIN new IconsetSelectItem(this, iconset); #else Q_UNUSED(iconset); #endif } void IconsetSelect::moveItemUp() { if ( currentRow() < 1 ) return; QListWidgetItem *i = currentItem(); if ( !i ) return; int prevRow = row(i) - 1; i = takeItem(row(i)); insertItem(prevRow, i); setItemSelected(i, true); setCurrentItem(i); } void IconsetSelect::moveItemDown() { if ( !currentItem() || currentRow() > (int)count() - 2 ) return; QListWidgetItem *i = currentItem(); if ( !i ) return; int nextRow = row(i) + 1; i = takeItem(row(i)); insertItem(nextRow, i); setCurrentItem(i); } const Iconset *IconsetSelect::iconset() const { IconsetSelectItem *i = (IconsetSelectItem *)currentItem(); if ( !i ) { QList items = selectedItems(); i = !items.isEmpty() ? (IconsetSelectItem *)items.first() : 0; } if ( i ) return i->iconset(); return 0; } QListWidgetItem *IconsetSelect::lastItem() const { return item(count() - 1); } QStyleOptionViewItem IconsetSelect::viewOptions() const { QStyleOptionViewItem o = QListWidget::viewOptions(); o.showDecorationSelected = true; return o; } //---------------------------------------------------------------------------- // IconsetDisplay //---------------------------------------------------------------------------- class IconsetDisplayItem : public RealIconWidgetItem { Q_OBJECT private: static const int margin; PsiIcon icon; int w, h; public: IconsetDisplayItem(QListWidget *parent, PsiIcon *i, int iconW) : RealIconWidgetItem(parent) { #ifndef WIDGET_PLUGIN icon = *i; w = iconW; connect(&icon, SIGNAL(pixmapChanged()), SLOT(update())); icon.activated(false); h = icon.pixmap().height(); QStringList str; foreach(PsiIcon::IconText t, icon.text()) str += t.text; if ( !str.isEmpty() ) setText(str.join(", ")); else setText(tr("Name: '%1'").arg(icon.name())); #else Q_UNUSED( i ); Q_UNUSED( iconW ); #endif } ~IconsetDisplayItem() { #ifndef WIDGET_PLUGIN icon.stop(); #endif } int height() const { int hh = qMax(h + 2*margin, listWidget()->fontMetrics().lineSpacing() + 2); return qMax( hh, QApplication::globalStrut().height() ); } int width() const { int ww = listWidget()->fontMetrics().width(text()) + w + 3*margin + 15; return qMax( ww, QApplication::globalStrut().width() ); } void paint(QPainter *painter) const { #ifndef WIDGET_PLUGIN painter->drawPixmap(QPoint((2*margin+w - icon.pixmap().width())/2, margin), icon.pixmap()); #else Q_UNUSED(painter); #endif } QPoint textPosition(QPainter *painter) const { QFontMetrics fm = painter->fontMetrics(); return QPoint(w + 2*margin, fm.ascent() + (fm.leading()+1)/2 + 1); } }; const int IconsetDisplayItem::margin = 3; IconsetDisplay::IconsetDisplay(QWidget *parent) : QListWidget(parent) { setItemDelegate(new IconWidgetDelegate(this)); } IconsetDisplay::~IconsetDisplay() { } void IconsetDisplay::setIconset(const Iconset &iconset) { #ifndef WIDGET_PLUGIN int w = 0; QListIterator it = iconset.iterator(); while ( it.hasNext() ) { w = qMax(w, it.next()->pixmap().width()); } it = iconset.iterator(); while ( it.hasNext() ) { new IconsetDisplayItem(this, it.next(), w); } #else Q_UNUSED(iconset); #endif } //---------------------------------------------------------------------------- // IconButton //---------------------------------------------------------------------------- class IconButton::Private : public QObject { Q_OBJECT public: PsiIcon *icon; IconButton *button; bool textVisible; bool activate, forced; #ifdef WIDGET_PLUGIN QString iconName; #endif public: Private(IconButton *b) { icon = 0; button = b; textVisible = true; forced = false; } ~Private() { iconStop(); } void setIcon(PsiIcon *i) { #ifndef WIDGET_PLUGIN iconStop(); if ( i ) icon = i->copy(); iconStart(); #else Q_UNUSED(i); #endif } void iconStart() { #ifndef WIDGET_PLUGIN if ( icon ) { connect(icon, SIGNAL(pixmapChanged()), SLOT(iconUpdated())); if ( activate ) icon->activated(true); // FIXME: should icon play sound when it's activated on button? } updateIcon(); #endif } void iconStop() { #ifndef WIDGET_PLUGIN if ( icon ) { disconnect(icon, 0, this, 0 ); if ( activate ) icon->stop(); delete icon; icon = 0; } #endif } void update() { iconUpdated(); } void updateIcon() { iconUpdated(); } public slots: void iconUpdated() { button->setUpdatesEnabled(false); #ifndef WIDGET_PLUGIN button->setIcon(icon ? icon->pixmap() : QPixmap()); #else QPixmap pix; if (!iconName.isEmpty()) { QPixmap pix((const char **)cancel_xpm); pix = QPixmap(pix); } button->setIcon(pix); #endif button->setUpdatesEnabled(true); button->update(); } }; IconButton::IconButton(QWidget *parent) : QPushButton(parent) { d = new Private(this); } IconButton::~IconButton() { delete d; } void IconButton::setIcon(const QPixmap &p) { QPushButton::setIcon(p); } void IconButton::forceSetPsiIcon(const PsiIcon *i, bool activate) { d->activate = activate; d->setIcon((PsiIcon *)i); d->forced = true; } void IconButton::setPsiIcon(const PsiIcon *i, bool activate) { #ifndef Q_WS_X11 if ( !text().isEmpty() ) return; #endif forceSetPsiIcon(i, activate); d->forced = false; } void IconButton::setPsiIcon(const QString &name) { #ifndef WIDGET_PLUGIN setPsiIcon( IconsetFactory::iconPtr(name) ); #else d->iconName = name; d->iconUpdated(); #endif } QString IconButton::psiIconName() const { #ifndef WIDGET_PLUGIN if ( d->icon ) return d->icon->name(); return QString::null; #else return d->iconName; #endif } void IconButton::setText(const QString &text) { #ifndef Q_WS_X11 if ( !d->forced ) setPsiIcon(0); #endif QPushButton::setText( text ); d->updateIcon(); } bool IconButton::textVisible() const { return d->textVisible; } void IconButton::setTextVisible(bool v) { d->textVisible = v; d->updateIcon(); } //---------------------------------------------------------------------------- // IconToolButton //---------------------------------------------------------------------------- class IconToolButton::Private : public QObject { Q_OBJECT public: PsiIcon *icon; IconToolButton *button; bool activate; #ifdef WIDGET_PLUGIN QString iconName; #endif public: Private(IconToolButton *b) { icon = 0; button = b; } ~Private() { iconStop(); } void setIcon(const PsiIcon *i) { #ifndef WIDGET_PLUGIN iconStop(); if ( i ) icon = new PsiIcon(*i); iconStart(); #else Q_UNUSED(i); #endif } void iconStart() { #ifndef WIDGET_PLUGIN if ( icon ) { connect(icon, SIGNAL(pixmapChanged()), SLOT(iconUpdated())); if ( activate ) icon->activated(true); // FIXME: should icon play sound when it's activated on button? } iconUpdated(); #endif } void iconStop() { #ifndef WIDGET_PLUGIN if ( icon ) { disconnect(icon, 0, this, 0 ); if ( activate ) icon->stop(); delete icon; icon = 0; } #endif } void update() { iconUpdated(); } private slots: void iconUpdated() { button->setUpdatesEnabled(false); #ifndef WIDGET_PLUGIN QPixmap pix = icon ? icon->pixmap() : QPixmap(); if (pix.isNull()) button->QToolButton::setIcon(QIcon()); else button->QToolButton::setIcon(pix); button->setIcon(icon ? icon->pixmap() : QPixmap()); #else button->setIcon(QPixmap()); #endif button->setUpdatesEnabled(true); button->update(); } }; IconToolButton::IconToolButton(QWidget *parent) : QToolButton(parent) { d = new Private(this); } IconToolButton::~IconToolButton() { delete d; } void IconToolButton::setIcon(const QIcon &p) { QToolButton::setIcon(p); } void IconToolButton::setPsiIcon(const PsiIcon *i, bool activate) { d->activate = activate; d->setIcon ((PsiIcon *)i); } void IconToolButton::setPsiIcon(const QString &name) { #ifndef WIDGET_PLUGIN setPsiIcon( IconsetFactory::iconPtr(name) ); #else d->iconName = name; #endif } QString IconToolButton::psiIconName() const { #ifndef WIDGET_PLUGIN if ( d->icon ) return d->icon->name(); return QString::null; #else return d->iconName; #endif } void IconToolButton::paintEvent(QPaintEvent* event) { setToolButtonStyle(icon().isNull() ? Qt::ToolButtonTextOnly : Qt::ToolButtonIconOnly); QToolButton::paintEvent(event); } #include "iconwidget.moc" psi-0.14/src/widgets/iconaction.cpp0000644000175000017500000002247111305557613015436 0ustar janjan/* * iconaction.cpp - the QAction subclass that uses Icons and supports animation * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconaction.h" #include "icontoolbutton.h" #include "iconwidget.h" #ifndef WIDGET_PLUGIN #include "iconset.h" #else class PsiIcon; class Iconset; #endif #include #include #include #include //---------------------------------------------------------------------------- // IconAction //---------------------------------------------------------------------------- class IconAction::Private : public QObject { Q_OBJECT public: QList buttons; PsiIcon *icon; #ifdef WIDGET_PLUGIN QString iconName; #endif IconAction *action; Private(IconAction *act, QObject *parent) { icon = 0; action = act; Q_ASSERT(action); if (parent->isWidgetType()) ((QWidget *)parent)->addAction(action); #ifdef Q_WS_MAC action->setIconVisibleInMenu(false); #endif } ~Private() { #ifndef WIDGET_PLUGIN if (icon) { delete icon; icon = 0; } #endif } void init(const QString &objectName, const QString &statusTip, QKeySequence shortcut, bool checkable) { action->setObjectName(objectName); action->setStatusTip(statusTip); action->setShortcut(shortcut); action->setCheckable(checkable); } }; IconAction::IconAction(QObject *parent, const QString &name) : QAction(parent) { d = new Private(this, parent); setObjectName(name); } IconAction::IconAction(const QString &statusTip, const QString &icon, const QString &text, QKeySequence accel, QObject *parent, const QString &name, bool checkable) : QAction(text, parent) { d = new Private(this, parent); d->init(name, statusTip, accel, checkable); setPsiIcon(icon); } IconAction::IconAction(const QString &statusTip, const QString &text, QKeySequence accel, QObject *parent, const QString &name, bool checkable) : QAction(text, parent) { d = new Private(this, parent); d->init(name, statusTip, accel, checkable); } IconAction::~IconAction() { // delete the buttons list before our own destruction IconToolButton *button; foreach ( button, d->buttons ) delete button; d->buttons.clear(); delete d; } const PsiIcon *IconAction::psiIcon() const { return d->icon; } void IconAction::setPsiIcon(const PsiIcon *i) { #ifdef WIDGET_PLUGIN Q_UNUSED(i); #else if ( d->icon ) { disconnect(d->icon, 0, this, 0 ); d->icon->stop(); delete d->icon; d->icon = 0; } QIcon is; if ( i ) { d->icon = new PsiIcon(*i); connect(d->icon, SIGNAL(iconModified()), SLOT(iconUpdated())); d->icon->activated(true); is = d->icon->icon(); } QAction::setIcon( is ); IconToolButton *btn; foreach ( btn, d->buttons ) btn->setPsiIcon ( d->icon ); #endif } void IconAction::setPsiIcon(const QString &name) { #ifdef WIDGET_PLUGIN d->iconName = name; #else setPsiIcon( IconsetFactory::iconPtr(name) ); #endif } QString IconAction::psiIconName() const { #ifndef WIDGET_PLUGIN if ( d->icon ) return d->icon->name(); #else return d->iconName; #endif return QString::null; } bool IconAction::addTo(QWidget *w) { w->addAction(this); return true; QStringList supportedContainers; supportedContainers << "QWidget"; if (w->inherits("QToolBar") || supportedContainers.contains(w->metaObject()->className())) { QString bname = objectName() + "_action_button"; IconToolButton *btn = new IconToolButton(w); btn->setObjectName(bname); d->buttons.append(btn); btn->setDefaultAction(this); btn->setText(text()); btn->setPsiIcon(d->icon, false); btn->setDefaultAction(this); // need to explicitly update popupMode, // because setDefaultAction resets it btn->setPopupMode(QToolButton::InstantPopup); btn->setToolTip(toolTipFromMenuText()); btn->setAutoRaise(true); btn->setFocusPolicy(Qt::NoFocus); if (supportedContainers.contains(w->metaObject()->className())) if (w->layout()) w->layout()->addWidget(btn); connect(btn, SIGNAL(toggled(bool)), this, SLOT(setChecked(bool))); connect(btn, SIGNAL(destroyed()), SLOT(objectDestroyed())); addingToolButton(btn); } else w->addAction(this); return true; } void IconAction::objectDestroyed() { const QObject *obj = sender(); d->buttons.removeAll((IconToolButton *)obj); } void IconAction::setChecked(bool b) { QAction::setChecked(b); IconToolButton *btn; foreach ( btn, d->buttons ) btn->setChecked(b); } void IconAction::toolButtonToggled(bool b) { setChecked(b); } void IconAction::setEnabled(bool e) { QAction::setEnabled(e); IconToolButton *btn; foreach ( btn, d->buttons ) btn->setEnabled (e); } void IconAction::setText(const QString &t) { QAction::setText(t); IconToolButton *btn; foreach ( btn, d->buttons ) btn->setText(t); } QList IconAction::buttonList() { return d->buttons; } void IconAction::iconUpdated() { #ifndef WIDGET_PLUGIN QAction::setIcon(d->icon ? d->icon->icon() : QIcon()); #endif } QString IconAction::toolTipFromMenuText() const { QString tt, str = text(); for (int i = 0; i < (int)str.length(); i++) if ( str[i] == '&' && str[i+1] != '&' ) continue; else tt += str[i]; return tt; } void IconAction::setMenu( QMenu *p ) { doSetMenu(p); } void IconAction::doSetMenu(QMenu* p) { QAction::setMenu(p); IconToolButton* btn; foreach(btn, d->buttons) { btn->setMenu(0); if (menu()) btn->setMenu(menu()); } } void IconAction::setIcon( const QIcon &ic ) { QAction::setIcon( ic ); IconToolButton *btn; foreach ( btn, d->buttons ) btn->setIcon( ic ); } void IconAction::setVisible( bool b ) { QAction::setVisible( b ); IconToolButton *btn; foreach ( btn, d->buttons ) { if ( b ) btn->show(); else btn->hide(); } } IconAction *IconAction::copy() const { IconAction *act = new IconAction(text(), psiIconName(), statusTip(), shortcut(), 0, objectName(), isCheckable()); *act = *this; return act; } IconAction &IconAction::operator=( const IconAction &from ) { setText( from.text() ); setPsiIcon( from.psiIconName() ); setStatusTip( from.statusTip() ); setShortcut( from.shortcut() ); setObjectName( from.objectName() ); setCheckable( from.isCheckable() ); setWhatsThis( whatsThis() ); // TODO: add more return *this; } //---------------------------------------------------------------------------- // IconActionGroup //---------------------------------------------------------------------------- class IconActionGroup::Private : public QObject { Q_OBJECT public: Private(IconActionGroup *_group) { group = _group; dirty = false; } IconActionGroup *group; QMenu *popup; bool exclusive; bool usesDropDown; bool dirty; public slots: void updatePopup(); }; void IconActionGroup::Private::updatePopup() { if (!dirty) return; if (!usesDropDown) qWarning("IconActionGroup does not support !usesDropDown yet"); popup->clear(); QList list = group->findChildren(); foreach(QAction *action, list) { if (!group->psiIcon() && action->inherits("IconAction")) group->setIcon(((IconAction *)action)->icon()); popup->addAction(action); } group->setMenu(popup); dirty = false; } IconActionGroup::IconActionGroup(QObject *parent, const char *name, bool exclusive) : IconAction( parent, name ) { d = new Private(this); d->popup = new QMenu(); d->dirty = true; setUsesDropDown(true); d->updatePopup(); d->exclusive = exclusive; } IconActionGroup::~IconActionGroup() { delete d->popup; delete d; } void IconActionGroup::childEvent(QChildEvent *e) { IconAction::childEvent(e); d->dirty = true; QTimer::singleShot( 0, d, SLOT( updatePopup() ) ); } void IconActionGroup::add( QAction * ) { qWarning("IconActionGroup::add(): not implemented"); } void IconActionGroup::addSeparator() { QAction *separatorAction = new QAction(this); separatorAction->setObjectName("separator_action"); separatorAction->setSeparator(true); } bool IconActionGroup::addTo( QWidget *w ) { if ( w->inherits("Q3PopupMenu") || w->inherits("QMenu") ) { QMenu *popup = (QMenu *)w; QList list = findChildren(); QAction *action; foreach ( action, list ) popup->addAction(action); return true; } w->addAction(this); return true; } IconAction *IconActionGroup::copy() const { qWarning("IconActionGroup::copy() doesn't work!"); return (IconAction *)this; } void IconActionGroup::setExclusive( bool e ) { d->exclusive = e; } bool IconActionGroup::isExclusive() const { return d->exclusive; } void IconActionGroup::setUsesDropDown( bool u ) { d->usesDropDown = u; } bool IconActionGroup::usesDropDown() const { return d->usesDropDown; } void IconActionGroup::addingToolButton(IconToolButton *btn) { btn->setPopupMode( QToolButton::MenuButtonPopup ); } #include "iconaction.moc" psi-0.14/src/widgets/iconsetdisplay.h0000644000175000017500000000221111305557613015775 0ustar janjan/* * iconsetdisplay.h - contact list widget * Copyright (C) 2001-2005 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONSETDISPLAY_H #define ICONSETDISPLAY_H #include class IconsetDisplayItem; class Iconset; class IconsetDisplay : public QListWidget { Q_OBJECT public: IconsetDisplay(QWidget *parent = 0); ~IconsetDisplay(); void setIconset(const Iconset &); private: friend class IconsetDisplayItem; }; #endif psi-0.14/src/widgets/iconselect.h0000644000175000017500000000246511305557613015106 0ustar janjan/* * iconselect.h - class that allows user to select an PsiIcon from an Iconset * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONSELECT_H #define ICONSELECT_H #include class PsiIcon; class Iconset; class IconSelectPopup : public QMenu { Q_OBJECT public: IconSelectPopup(QWidget *parent = 0); ~IconSelectPopup(); void setIconset(const Iconset &); const Iconset &iconset() const; // reimplemented void mousePressEvent(QMouseEvent *e); signals: void iconSelected(const PsiIcon *); void textSelected(QString); private: class Private; Private *d; }; #endif psi-0.14/src/widgets/psitooltip.cpp0000644000175000017500000001475711305557613015526 0ustar janjan/* * psitooltip.cpp - PsiIcon-aware QToolTip clone * Copyright (C) 2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psitooltip.h" #include #include #include #include #include #include #include "private/qeffects_p.h" #include "psitiplabel.h" //---------------------------------------------------------------------------- // PsiToolTipHandler //---------------------------------------------------------------------------- class PsiToolTipHandler : public QObject { Q_OBJECT public: static PsiToolTipHandler *getInstance() { static PsiToolTipHandler *instance = 0; if (!instance) instance = new PsiToolTipHandler(); return instance; } void install(QWidget *widget) { watchedWidgets_[widget] = true; connect(widget, SIGNAL(destroyed(QObject*)), SLOT(widgetDestroyed(QObject*))); } private slots: void widgetDestroyed(QObject* obj) { QWidget* widget = static_cast(obj); watchedWidgets_.remove(widget); } private: QHash watchedWidgets_; PsiToolTipHandler() : QObject(qApp) { qApp->installEventFilter(this); } bool eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::ToolTip) { QWidget *widget = static_cast(obj); if (watchedWidgets_.contains(widget) && (widget->isActiveWindow() || widget->window()->testAttribute(Qt::WA_AlwaysShowToolTips))) { QPoint pos = dynamic_cast(event)->globalPos(); PsiToolTip::showText(pos, widget->toolTip(), widget); event->setAccepted(true); return true; } } return false; } }; //---------------------------------------------------------------------------- // ToolTipPosition //---------------------------------------------------------------------------- ToolTipPosition::ToolTipPosition(const QPoint& _pos, const QWidget* _w) : pos(_pos) , w(_w) { } int ToolTipPosition::getScreenNumber() const { if (QApplication::desktop()->isVirtualDesktop()) return QApplication::desktop()->screenNumber(pos); return QApplication::desktop()->screenNumber(w); } QRect ToolTipPosition::screenRect() const { #ifdef Q_WS_MAC return QApplication::desktop()->availableGeometry(getScreenNumber()); #else return QApplication::desktop()->screenGeometry(getScreenNumber()); #endif } QPoint ToolTipPosition::calculateTipPosition(const QWidget* label) const { QRect screen = screenRect(); QPoint p = pos; p += QPoint(2, #ifdef Q_WS_WIN 24 #else 16 #endif ); if (p.x() + label->width() > screen.x() + screen.width()) p.rx() -= 4 + label->width(); if (p.y() + label->height() > screen.y() + screen.height()) p.ry() -= 24 + label->height(); if (p.y() < screen.y()) p.setY(screen.y()); if (p.x() + label->width() > screen.x() + screen.width()) p.setX(screen.x() + screen.width() - label->width()); if (p.x() < screen.x()) p.setX(screen.x()); if (p.y() + label->height() > screen.y() + screen.height()) p.setY(screen.y() + screen.height() - label->height()); return p; } //---------------------------------------------------------------------------- // PsiToolTip //---------------------------------------------------------------------------- PsiToolTip::PsiToolTip() : QObject(QCoreApplication::instance()) {} /** * QTipLabel's font is being determined at run-time. However QTipLabel's and * QToolTip's font is the same, so we install our PsiTextLabel's font to be * the same as QToolTip's. */ static void installPsiToolTipFont() { static bool toolTipFontInstalled = false; if (toolTipFontInstalled) return; qApp->setFont(QToolTip::font(), "PsiTipLabel"); toolTipFontInstalled = true; } /** * Shows \a text as a tool tip, at global position \a pos. The * optional widget argument, \a w, is used to determine the * appropriate screen on multi-head systems. */ void PsiToolTip::doShowText(const QPoint &pos, const QString &text, const QWidget *w) { if (text.isEmpty() || (w && !w->underMouse())) { if (PsiTipLabel::instance()) PsiTipLabel::instance()->hideTip(); return; } QPointer calc(createTipPosition(pos, w)); calc->deleteLater(); if (PsiTipLabel::instance() && moveAndUpdateTipLabel(PsiTipLabel::instance(), text)) { updateTipLabel(PsiTipLabel::instance(), text); // fancy moving tooltip effect PsiTipLabel::instance()->move(calc->calculateTipPosition(PsiTipLabel::instance())); return; } bool preventAnimation = (PsiTipLabel::instance() != 0); installPsiToolTipFont(); QFrame *label = createTipLabel(text, QApplication::desktop()->screen(calc->getScreenNumber())); label->move(calc->calculateTipPosition(label)); if ( QApplication::isEffectEnabled(Qt::UI_AnimateTooltip) == false || preventAnimation) label->show(); else if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)) qFadeEffect(label); else qScrollEffect(label); } bool PsiToolTip::moveAndUpdateTipLabel(PsiTipLabel* label, const QString& text) { return label->theText() == text; } void PsiToolTip::updateTipLabel(PsiTipLabel* label, const QString& text) { Q_UNUSED(label); Q_UNUSED(text); } ToolTipPosition* PsiToolTip::createTipPosition(const QPoint& cursorPos, const QWidget* parentWidget) { return new ToolTipPosition(cursorPos, parentWidget); } PsiTipLabel* PsiToolTip::createTipLabel(const QString& text, QWidget* parent) { PsiTipLabel* label = new PsiTipLabel(parent); label->init(text); return label; } /** * After installation, all tool tips in specified widget will be processed * through PsiToolTip and thus tags would be correctly handled. */ void PsiToolTip::doInstall(QWidget *w) { PsiToolTipHandler::getInstance()->install(w); } PsiToolTip *PsiToolTip::instance_ = 0; PsiToolTip* PsiToolTip::instance() { if (!instance_) instance_ = new PsiToolTip(); return instance_; } #include "psitooltip.moc" psi-0.14/src/widgets/unittest/0000755000175000017500000000000011305557613014455 5ustar janjanpsi-0.14/src/widgets/unittest/iconaction/0000755000175000017500000000000011305557613016603 5ustar janjanpsi-0.14/src/widgets/unittest/iconaction/testiconaction.cpp0000644000175000017500000000356611305557613022347 0ustar janjan#include "iconaction.h" #include "icontoolbutton.h" #include #include #include #include class TestIconAction : public QObject { Q_OBJECT private: IconAction *action, *checkableAction; IconToolButton *findToolButton(QToolBar *toolBar) { IconToolButton *toolButton = toolBar->findChild(); if ( !toolButton ) throw "toolButton == 0!"; return toolButton; } private slots: void initTestCase() { action = new IconAction("statusTip", "foobar/icon", "text", 0, this, "action"); QCOMPARE(action->statusTip(), QString("statusTip")); QCOMPARE(action->text(), QString("text")); QCOMPARE(action->psiIconName(), QString("foobar/icon")); QCOMPARE(action->isCheckable(), false); QVERIFY(action->shortcut().isEmpty()); QCOMPARE(action->objectName(), QString("action")); checkableAction = new IconAction("statusTip2", "foobar/icon2", "text2", 0, this, "checkableAction", true); QCOMPARE(checkableAction->isCheckable(), true); } void cleanupTestCase() { delete action; delete checkableAction; } void testToolButtonClick() { QToolBar toolBar; action->addTo(&toolBar); QSignalSpy spy(action, SIGNAL(triggered())); IconToolButton *button = findToolButton(&toolBar); QCOMPARE(button->isCheckable(), false); button->click(); QCOMPARE(spy.count(), 1); } void testToolButtonChecked() { QToolBar toolBar; checkableAction->addTo(&toolBar); QSignalSpy spy(checkableAction, SIGNAL(toggled(bool))); IconToolButton *button = findToolButton(&toolBar); QCOMPARE(button->isCheckable(), true); QCOMPARE(checkableAction->isChecked(), false); button->click(); QCOMPARE(checkableAction->isChecked(), true); button->click(); QCOMPARE(checkableAction->isChecked(), false); QCOMPARE(spy.count(), 2); } }; QTEST_MAIN(TestIconAction) #include "testiconaction.moc" psi-0.14/src/widgets/unittest/iconaction/iconaction.pro0000644000175000017500000000067511305557613021463 0ustar janjan# unittest helpers TARGET = iconaction CONFIG += unittest TESTBASEDIR = ../../../../unittest include($$TESTBASEDIR/unittest.pri) QT += gui DEFINES += WIDGET_PLUGIN INCLUDEPATH += ../.. DEPENDPATH += ../.. SOURCES += \ testiconaction.cpp \ ../../iconaction.cpp \ ../../iconwidget.cpp HEADERS += \ ../../iconaction.h \ ../../iconwidget.h \ ../../icontoolbutton.h \ ../../iconbutton.h \ ../../iconsetdisplay.h \ ../../iconsetselect.hpsi-0.14/src/widgets/unittest/richtext/0000755000175000017500000000000011305557613016307 5ustar janjanpsi-0.14/src/widgets/unittest/richtext/richtext.pro0000644000175000017500000000026711305557613020670 0ustar janjan# unittest helpers TARGET = richtext CONFIG += unittest TESTBASEDIR = ../../../../unittest include($$TESTBASEDIR/unittest.pri) QT += gui DEFINES += WIDGET_PLUGIN SOURCES += main.cpppsi-0.14/src/widgets/unittest/richtext/main.cpp0000644000175000017500000000132011305557613017733 0ustar janjan#include "../../psirichtext.cpp" #include #include #include class TestRichText : public QObject { Q_OBJECT private: int countText(QTextDocument *doc, QString text) { int result = 0; QTextCursor cursor(doc); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); forever { cursor = doc->find(text, cursor); if (cursor.isNull()) break; result++; } return result; } private slots: void testSetText() { QTextDocument doc; PsiRichText::setText(&doc, "Test "); QCOMPARE(countText(&doc, QString(QChar::ObjectReplacementCharacter)), 1); } }; QTEST_MAIN(TestRichText) #include "main.moc" psi-0.14/src/widgets/psitooltip.h0000644000175000017500000000374011305557613015161 0ustar janjan/* * psitooltip.h - PsiIcon-aware QToolTip clone * Copyright (C) 2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSITOOLTIP_H #define PSITOOLTIP_H #include class PsiTipLabel; class ToolTipPosition : public QObject { public: ToolTipPosition(const QPoint& cursorPos, const QWidget* parentWidget); virtual ~ToolTipPosition() {} int getScreenNumber() const; QRect screenRect() const; virtual QPoint calculateTipPosition(const QWidget* label) const; protected: QPoint pos; const QWidget* w; }; class PsiToolTip : public QObject { public: static void showText(const QPoint &pos, const QString &text, const QWidget *w = 0) { instance()->doShowText(pos, text, w); } static void install(QWidget *w) { instance()->doInstall(w); } static PsiToolTip* instance(); protected: PsiToolTip(); void doShowText(const QPoint &pos, const QString &text, const QWidget *w = 0); void doInstall(QWidget *w); virtual ToolTipPosition* createTipPosition(const QPoint& cursorPos, const QWidget* parentWidget); virtual PsiTipLabel* createTipLabel(const QString& text, QWidget* parent); virtual bool moveAndUpdateTipLabel(PsiTipLabel* label, const QString& text); virtual void updateTipLabel(PsiTipLabel* label, const QString& text); static PsiToolTip* instance_; }; #endif psi-0.14/src/widgets/icontoolbutton.h0000644000175000017500000000306111305557613016031 0ustar janjan/* * iconwidget.h - misc. Iconset- and PsiIcon-aware widgets * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONTOOLBUTTON_H #define ICONTOOLBUTTON_H #include #include class PsiIcon; class Iconset; class IconToolButton : public QToolButton { Q_OBJECT Q_PROPERTY( QString psiIconName READ psiIconName WRITE setPsiIcon ) Q_OVERRIDE( QPixmap pixmap DESIGNABLE false SCRIPTABLE false ) Q_OVERRIDE( QIcon icon DESIGNABLE false SCRIPTABLE false ) public: IconToolButton(QWidget *parent = 0); ~IconToolButton(); void setIcon(const QIcon &); public slots: void setPsiIcon(const PsiIcon *, bool activate = true); void setPsiIcon(const QString &); QString psiIconName() const; protected: // reimplemented void paintEvent(QPaintEvent* event); public: class Private; private: Private *d; }; #endif psi-0.14/src/widgets/updatingcombobox.h0000644000175000017500000000046611305557613016321 0ustar janjan#ifndef UPDATINGCOMBOBOX_H #define UPDATINGCOMBOBOX_H #include class UpdatingComboBox : public QComboBox { Q_OBJECT public: UpdatingComboBox(QWidget* parent) : QComboBox(parent) {} virtual void showPopup() { emit popup(); QComboBox::showPopup(); } signals: void popup(); }; #endif psi-0.14/src/widgets/README0000644000175000017500000000074411305557613013463 0ustar janjanPsiWidgets README ~~~~~~~~~~~~~~~~~ Introduction ~~~~~~~~~~~~ This is a package of widgets, that are used in Psi Jabber client. You may be interested in it, if you want to develop custom dialogs, or hack existing ones. Read below for installation instructions. Installation ~~~~~~~~~~~~ Requirements: Qt 3.1.x (http://www.trolltech.com) Type these commands in terminal: % qmake % make % su -c "make install" Now open Qt Designer and enjoy :-) psi-0.14/src/widgets/psitabbar.cpp0000644000175000017500000000623111305557613015253 0ustar janjan/* * psitabbar.cpp - Tabbar child for Psi * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psitabbar.h" #include "psitabwidget.h" #include #include /** * Constructor */ PsiTabBar::PsiTabBar(PsiTabWidget *parent) : QTabBar(parent) , dragsEnabled_(true) { //setAcceptDrops(true); } /** * Destructor */ PsiTabBar::~PsiTabBar() { } /** * Returns the parent PsiTabWidget. */ PsiTabWidget* PsiTabBar::psiTabWidget() { return dynamic_cast (parent()); } /** * Overriding this allows us to emit signals for double clicks */ void PsiTabBar::mouseDoubleClickEvent(QMouseEvent *event) { const QPoint pos = event->pos(); int tab = findTabUnder(pos); if (tab >= 0 && tab < count()) { emit mouseDoubleClickTab(tab); } } /* * Returns the index of the tab at a position, or -1 if out of bounds. */ int PsiTabBar::findTabUnder(const QPoint &pos) { for (int i = 0; i < count(); i++) { if (tabRect(i).contains(pos)) { return i; } } return -1; } void PsiTabBar::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { int tabno = findTabUnder(event->pos()); dragStartPosition_ = event->pos(); dragTab_ = tabno; if (tabno != -1) { setCurrentIndex(tabno); } } event->accept(); } /* * Used for starting drags of tabs */ void PsiTabBar::mouseMoveEvent(QMouseEvent *event) { if (!dragsEnabled_) { return; } if (!(event->buttons() & Qt::LeftButton)) { return; } if ((event->pos() - dragStartPosition_).manhattanLength() < QApplication::startDragDistance()) { return; } if (dragTab_ != -1) { QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; QByteArray data; QPixmap icon; data.setNum(dragTab_); mimeData->setData(PSITABDRAGMIMETYPE, data); drag->setMimeData(mimeData); drag->setPixmap(icon); Qt::DropAction dropAction = drag->start(Qt::MoveAction); Q_UNUSED(dropAction); } event->accept(); } void PsiTabBar::contextMenuEvent(QContextMenuEvent *event) { event->accept(); emit contextMenu(event, findTabUnder(event->pos())); } void PsiTabBar::wheelEvent(QWheelEvent *event) { int numDegrees = event->delta() / 8; int numSteps = numDegrees / 15; int newIndex = currentIndex() - numSteps; while (newIndex < 0) { newIndex += count(); } newIndex = newIndex % count(); setCurrentIndex(newIndex); event->accept(); } /* * Enable/disable dragging of tabs */ void PsiTabBar::setDragsEnabled(bool enabled) { dragsEnabled_ = enabled; } psi-0.14/src/widgets/urlobject.cpp0000644000175000017500000001323511305557613015277 0ustar janjan/* * urlobject.cpp - helper class for handling links * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "urlobject.h" #include #include #include #include #include #include "iconaction.h" //! \if _hide_doc_ class URLObject::Private : QObject { Q_OBJECT public: QString link; IconAction *act_xmpp, *act_mailto, *act_join_groupchat, *act_send_message, *act_chat, *act_browser, *act_add_to_roster, *act_copy; URLObject *urlObject; QSignalMapper xmppActionMapper; void connectXmppAction(QAction* action, const QString& query) { connect(action, SIGNAL(triggered()), &xmppActionMapper, SLOT(map())); xmppActionMapper.setMapping(action, query); } Private(URLObject *parent) : QObject(parent) { urlObject = parent; QString tr; tr = qApp->translate("URLLabel", "Open"); act_xmpp = new IconAction(tr, "psi/jabber", tr, 0, this); connect(act_xmpp, SIGNAL(triggered()), SLOT(popupAction())); tr = qApp->translate("URLLabel", "Open mail composer"); act_mailto = new IconAction(tr, "psi/email", tr, 0, this); connect(act_mailto, SIGNAL(triggered()), SLOT(popupAction())); tr = qApp->translate("URLLabel", "Open web browser"); act_browser = new IconAction(tr, "psi/www", tr, 0, this); connect(act_browser, SIGNAL(triggered()), SLOT(popupAction())); tr = qApp->translate("URLLabel", "Add to Roster"); act_add_to_roster = new IconAction(tr, "psi/addContact", tr, 0, this); connectXmppAction(act_add_to_roster, "roster"); tr = qApp->translate("URLLabel", "Send message to"); act_send_message = new IconAction(tr, "psi/message", tr, 0, this); connectXmppAction(act_send_message, "message"); tr = qApp->translate("URLLabel", "Chat with"); act_chat = new IconAction(tr, "psi/chat", tr, 0, this); connectXmppAction(act_chat, "message;type=chat"); tr = qApp->translate("URLLabel", "Join groupchat"); act_join_groupchat = new IconAction(tr, "psi/groupChat", tr, 0, this); connectXmppAction(act_join_groupchat, "join"); tr = qApp->translate("URLLabel", "Copy location"); act_copy = new IconAction(tr, tr, 0, this); connect(act_copy, SIGNAL(triggered()), SLOT(popupCopy())); connect(&xmppActionMapper, SIGNAL(mapped(const QString&)), SLOT(xmppAction(const QString&))); } QString copyString(QString from) { QString l = from; int colon = l.indexOf(':'); if ( colon == -1 ) colon = 0; QString service = l.left( colon ); if ( service == "mailto" || service == "jabber" || service == "jid" || service == "xmpp" || service == "atstyle") { if ( colon > -1 ) l = l.mid( colon + 1 ); while ( l[0] == '/' ) l = l.mid( 1 ); } return l; } public slots: void popupAction(QString lnk) { emit urlObject->openURL(lnk); } void popupAction() { popupAction(link); } void popupCopy(QString lnk) { QApplication::clipboard()->setText( copyString(lnk), QClipboard::Clipboard ); if(QApplication::clipboard()->supportsSelection()) QApplication::clipboard()->setText( copyString(lnk), QClipboard::Selection ); } void popupCopy() { popupCopy(link); } void xmppAction(const QString& lnk, const QString& query) { QUrl uri(lnk); QString queryType = query.left(query.indexOf(';')); uri.setQueryDelimiters('=', ';'); if (uri.queryItems().value(0).first != queryType) { uri.setEncodedQuery(query.toAscii()); } emit urlObject->openURL(uri.toString()); } void xmppAction(const QString& query) { xmppAction(link, query); } }; //! \endif /** * \class URLObject * \brief Helper class for handling clicking on URLs */ /** * Default constructor. */ URLObject::URLObject() : QObject(qApp) { d = new Private(this); } /** * Returns instance of the class, and creates it if necessary. */ URLObject *URLObject::getInstance() { static URLObject *urlObject = 0; if (!urlObject) urlObject = new URLObject(); return urlObject; } /** * Creates QMenu with actions corresponding to link's type. * @param lnk link in service:url format */ QMenu *URLObject::createPopupMenu(const QString &lnk) { d->link = lnk; if ( d->link.isEmpty() ) return 0; int colon = d->link.indexOf(':'); if ( colon == -1 ) colon = 0; QString service = d->link.left( colon ); QMenu *m = new QMenu; // FIXME: atstyle doesn't work. it's always mailto. bool needGenericOpen = true; if (service == "mailto" || service == "atstyle") { needGenericOpen = false; m->addAction(d->act_mailto); } if (service == "jabber" || service == "jid" || service == "xmpp" || service == "atstyle") { needGenericOpen = false; m->addAction(d->act_xmpp); m->addAction(d->act_chat); m->addAction(d->act_send_message); m->addAction(d->act_join_groupchat); //m->addAction(d->act_add_to_roster); } if (needGenericOpen) { m->addAction(d->act_browser); } m->addAction(d->act_copy); return m; } /** * Simulates default action using the passed URL. * \param lnk URL string */ void URLObject::popupAction(QString lnk) { d->popupAction(lnk); } #include "urlobject.moc" psi-0.14/src/widgets/psitiplabel.h0000644000175000017500000000156311305557613015264 0ustar janjan#ifndef PSITIPLABEL_H #define PSITIPLABEL_H #include #include class QTextDocument; class PsiTipLabel : public QFrame { Q_OBJECT public: PsiTipLabel(QWidget* parent); ~PsiTipLabel(); virtual void init(const QString& text); static PsiTipLabel* instance(); void setText(const QString& text); // int heightForWidth(int w) const; QSize sizeHint() const; QSize minimumSizeHint() const; bool eventFilter(QObject *, QEvent *); QString theText() const; QBasicTimer hideTimer, deleteTimer; void hideTip(); protected: void enterEvent(QEvent*); void timerEvent(QTimerEvent* e); void paintEvent(QPaintEvent* e); // QSize sizeForWidth(int w) const; private: QTextDocument* doc; QString theText_; bool isRichText; int margin; // int indent; virtual void initUi(); virtual void startHideTimer(); static PsiTipLabel* instance_; }; #endif psi-0.14/src/widgets/stretchwidget.h0000644000175000017500000000034511305557613015631 0ustar janjan#ifndef STRETCHWIDGET_H #define STRETCHWIDGET_H class StretchWidget: public QWidget { public: StretchWidget(QWidget *parent) : QWidget( parent ) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } }; #endif psi-0.14/src/widgets/busywidget.h0000644000175000017500000000306211305557613015136 0ustar janjan/* * busywidget.h - cool animating widget * Copyright (C) 2001, 2002 Justin Karneges * Hideaki Omuro * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef BUSYWIDGET_H #define BUSYWIDGET_H #include class CColor; class CPanel; class BusyWidget : public QWidget { Q_OBJECT Q_PROPERTY( bool active READ isActive WRITE setActive ) Q_OVERRIDE( QSize minimumSize DESIGNABLE false SCRIPTABLE false ) Q_OVERRIDE( QSize maximumSize DESIGNABLE false SCRIPTABLE false ) public: BusyWidget(QWidget *parent=0); ~BusyWidget(); bool isActive() const; QSize minimumSizeHint() const; QSize sizeHint() const; public slots: void start(); void stop(); void setActive(bool); protected: void paintEvent(QPaintEvent *); void resizeEvent(QResizeEvent *); private slots: void animate(); public: class Private; private: Private *d; friend class Private; }; #endif psi-0.14/src/widgets/urlobject.h0000644000175000017500000000300411305557613014735 0ustar janjan/* * urlobject.h - helper class for handling links * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef URLOBJECT_H #define URLOBJECT_H #include class QMenu; // TODO: This class should be further refactored into more modular system. // It should allow registering/unregistering of QRegExps corresponding to // different actions. Also class's base API should be made public. // // Examples of future use: // URLObject::getInstance()::registerAction(QRegExp("^http:\/\/"), act_open_browser); class URLObject : public QObject { Q_OBJECT protected: URLObject(); public: static URLObject *getInstance(); QMenu *createPopupMenu(const QString &lnk); void popupAction(QString lnk); signals: void openURL(QString); public: class Private; private: Private *d; }; #endif psi-0.14/src/widgets/psitabbar.h0000644000175000017500000000333611305557613014723 0ustar janjan/* * psitabbar.h - Tabbar child for Psi * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _PSITABBAR_H_ #define _PSITABBAR_H_ #include #include class PsiTabWidget; class PsiTabBar : public QTabBar { Q_OBJECT public: PsiTabBar(PsiTabWidget *parent); ~PsiTabBar(); PsiTabWidget *psiTabWidget(); void setDragsEnabled(bool enabled); // default enabled signals: void mouseDoubleClickTab(int tab); void tabDropped(int tab, PsiTabBar *source); // context menu on the blank space will have tab==-1 void contextMenu(QContextMenuEvent *event, int tab); protected: void mouseDoubleClickEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); //void dragEnterEvent(QDragEnterEvent *event); //void dropEvent(QDropEvent *event); void mousePressEvent(QMouseEvent *event); void contextMenuEvent(QContextMenuEvent *event); void wheelEvent(QWheelEvent *event); private: int findTabUnder(const QPoint &pos); QPoint dragStartPosition_; int dragTab_; bool dragsEnabled_; }; #endif /* _PSITABBAR_H_ */ psi-0.14/src/widgets/urllabel.h0000644000175000017500000000306311305557613014553 0ustar janjan/* * psitextview.h - PsiIcon-aware QTextView subclass widget * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef URLLABEL_H #define URLLABEL_H #include class QWidget; class QObject; class URLLabel : public QLabel { Q_OBJECT Q_PROPERTY( QString url READ url WRITE setUrl ) Q_PROPERTY( QString title READ title WRITE setTitle ) Q_OVERRIDE( QString text DESIGNABLE false SCRIPTABLE false ) //Q_OVERRIDE( TextFormat DESIGNABLE false SCRIPTABLE false ) public: URLLabel(QWidget *parent = 0); ~URLLabel(); const QString &url() const; void setUrl(const QString &); const QString &title() const; void setTitle(const QString &); protected: virtual void contextMenuEvent(QContextMenuEvent *); virtual void mouseReleaseEvent(QMouseEvent *); void updateText(); public: class Private; private: Private *d; }; #endif psi-0.14/src/widgets/iconbutton.h0000644000175000017500000000334411305557613015137 0ustar janjan/* * iconwidget.h - misc. Iconset- and PsiIcon-aware widgets * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONBUTTON_H #define ICONBUTTON_H #include #include #include #include #include class PsiIcon; class IconButton : public QPushButton { Q_OBJECT Q_PROPERTY( QString psiIconName READ psiIconName WRITE setPsiIcon ) Q_PROPERTY( bool textVisible READ textVisible WRITE setTextVisible ) Q_OVERRIDE( QPixmap pixmap DESIGNABLE false SCRIPTABLE false ) Q_OVERRIDE( QIcon icon DESIGNABLE false SCRIPTABLE false ) public: IconButton(QWidget *parent = 0); ~IconButton(); void setIcon(const QPixmap &); public slots: void setPsiIcon(const PsiIcon *, bool activate = true); void forceSetPsiIcon(const PsiIcon *, bool activate = true); void setPsiIcon(const QString &); QString psiIconName() const; void setText(const QString &); bool textVisible() const; void setTextVisible(bool); public: class Private; private: Private *d; }; #endif psi-0.14/src/widgets/fancypopup.h0000644000175000017500000000267411305557613015144 0ustar janjan/* * fancypopup.h - the FancyPopup passive popup widget * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef FANCYPOPUP_H #define FANCYPOPUP_H #include class PsiIcon; class QTimer; class FancyPopup : public QFrame { Q_OBJECT public: FancyPopup(QString title, const PsiIcon *icon = 0, FancyPopup *prev = 0, bool copyIcon = true); ~FancyPopup(); void addLayout(QLayout *layout, int stretch = 0); static void setHideTimeout(int); static void setBorderColor(QColor); void show(); void restartHideTimer(); signals: void clicked(int); protected: void hideEvent(QHideEvent *); void mouseReleaseEvent(QMouseEvent *); public: class Private; private: Private *d; friend class Private; }; #endif psi-0.14/src/widgets/private/0000755000175000017500000000000011305557613014250 5ustar janjanpsi-0.14/src/widgets/private/qeffects_p.h0000644000175000017500000000353711305557613016550 0ustar janjan/**************************************************************************** ** ** Copyright (C) 1992-2006 Trolltech AS. All rights reserved. ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #ifndef QEFFECTS_P_H #define QEFFECTS_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists for the convenience // of qeffects.cpp, qcombobox.cpp, qpopupmenu.cpp and qtooltip.cpp. // This header file may change from version to version without notice, // or even be removed. // // We mean it. // #include "QtCore/qnamespace.h" #ifndef QT_NO_EFFECTS class QWidget; struct QEffects { enum Direction { LeftScroll = 0x0001, RightScroll = 0x0002, UpScroll = 0x0004, DownScroll = 0x0008 }; typedef uint DirFlags; }; extern void Q_GUI_EXPORT qScrollEffect(QWidget*, QEffects::DirFlags dir = QEffects::DownScroll, int time = -1); extern void Q_GUI_EXPORT qFadeEffect(QWidget*, int time = -1); #endif // QT_NO_EFFECTS #endif // QEFFECTS_P_H psi-0.14/src/widgets/urllabel.cpp0000644000175000017500000000444011305557613015106 0ustar janjan/* * urllabel.cpp - clickable URL-label * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "urllabel.h" #include #include #include "urlobject.h" //! \if _hide_doc_ class URLLabel::Private { public: QString url; QString title; }; //! \endif /** * \class URLLabel * \brief Clickable URL-label */ /** * Default constructor. */ URLLabel::URLLabel(QWidget *parent) : QLabel(parent) { d = new Private; setCursor( Qt::PointingHandCursor ); } URLLabel::~URLLabel() { delete d; } /** * Returns URL of this label. */ const QString &URLLabel::url() const { return d->url; } /** * Sets the URL of this label to url * \param url an URL string */ void URLLabel::setUrl(const QString &url) { d->url = url; updateText(); } /** * Returns title of this label. */ const QString &URLLabel::title() const { return d->title; } /** * Sets the title of this lable to t * \param t this string will be shown to user */ void URLLabel::setTitle(const QString &t) { d->title = t; updateText(); } void URLLabel::updateText() { setText( QString("%2").arg(d->url).arg(d->title) ); if ( d->url != d->title ) setToolTip(d->url); else setToolTip(QString()); } void URLLabel::contextMenuEvent(QContextMenuEvent *e) { QMenu *m = URLObject::getInstance()->createPopupMenu(d->url); if ( m ) { m->exec( e->globalPos() ); delete m; } e->accept(); } void URLLabel::mouseReleaseEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) URLObject::getInstance()->popupAction(url()); QLabel::mouseReleaseEvent(e); } psi-0.14/src/widgets/fancypopuplist.h0000644000175000017500000000313511305557613016031 0ustar janjan/* * fancypopuplist.h - the list class to hold all the FancyPopups * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef POPUPLIST_H #define POPUPLIST_H #include #include #include "fancypopup.h" class FancyPopupList : public QObject, public QList { Q_OBJECT public: FancyPopupList() { } ~FancyPopupList() { while ( !isEmpty() ) delete takeFirst(); } FancyPopup *last() { if ( !count() ) return 0; return QList::first(); } void prepend(const FancyPopup *d) { if ( isEmpty() ) emit started(); connect(d, SIGNAL(destroyed(QObject *)), SLOT(popupDestroyed(QObject *))); QList::prepend((FancyPopup *)d); } signals: void started(); void finished(); private slots: void popupDestroyed(QObject *p) { removeAll((FancyPopup *)p); if ( isEmpty() ) emit finished(); } }; #endif psi-0.14/src/widgets/psitabwidget.h0000644000175000017500000000523311305557613015440 0ustar janjan/* * psitabwidget.h - Customised QTabWidget for Psi * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSITABWIDGET_H #define PSITABWIDGET_H #include #include #include #include "psitabbar.h" class QVBoxLayout; class QHBoxLayout; class QToolButton; class QStackedLayout; class QMenu; /** * \class PsiTabWidget * \brief */ class PsiTabWidget : public QWidget //: public QTabWidget { Q_OBJECT public: PsiTabWidget(QWidget *parent = 0); ~PsiTabWidget(); void setTabTextColor(QWidget *tab, const QColor &color); int count(); QWidget *currentPage(); int currentPageIndex(); QWidget *widget(int index); void addTab(QWidget *, QString); void showPage(QWidget *); void showPageDirectly(QWidget *); void removePage(QWidget *); QWidget* page(int index); int getIndex(QWidget *); void setTabText(QWidget *, const QString &); void setTabPosition(QTabWidget::TabPosition pos); void setCloseIcon(const QIcon &); void setTabBarShown(bool shown); // default shown void setTabButtonsShown(bool shown); // default shown void setDragsEnabled(bool enabled); // default enabled public slots: void setCurrentPage(int); void removeCurrentPage(); signals: void mouseDoubleClickTab(QWidget *tab); void currentChanged(QWidget *selected); void closeButtonClicked(); void aboutToShowMenu(QMenu *); // context menu on the blank space will have tab==-1 void tabContextMenu(int tab, QPoint pos, QContextMenuEvent *event); private slots: void mouseDoubleClickTab(int tab); void tab_currentChanged(int tab); void tab_contextMenu(QContextMenuEvent *event, int tab); void menu_aboutToShow(); void menu_triggered(QAction *act); private: QVector widgets_; QTabBar *tabBar_; QVBoxLayout *layout_; QHBoxLayout *barLayout_; QStackedLayout *stacked_; QToolButton *closeButton_; QToolButton *downButton_; QTabWidget::TabPosition tabsPosition_; QMenu *menu_; }; #define PSITABDRAGMIMETYPE "x-drag-drop/x-psi-tab-drag" #endif psi-0.14/src/widgets/widgets.pro0000644000175000017500000000152011305557613014764 0ustar janjanTEMPLATE = lib CONFIG += designer plugin release TARGET = psiwidgets target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target # don't litter main dir MOC_DIR = .moc OBJECTS_DIR = .obj UI_DIR = .ui SOURCES += \ psiwidgets.cpp \ fancylabel.cpp \ busywidget.cpp \ iconwidget.cpp \ iconaction.cpp \ urlobject.cpp \ urllabel.cpp \ psirichtext.cpp \ psitextview.cpp # psitooltip.cpp \ # psitabwidget.cpp \ # psitabbar.cpp HEADERS += \ psiwidgets.h \ fancylabel.h \ busywidget.h \ iconwidget.h \ iconbutton.h \ iconsetdisplay.h \ iconsetselect.h \ iconaction.h \ updatingcombobox.h \ urlobject.h \ urllabel.h \ iconlabel.h \ icontoolbutton.h \ psirichtext.h \ psitextview.h # psitooltip.h \ # psitabwidget.h \ # psitabbar.h DISTFILES += \ README \ iconselect.cpp \ iconselect.h DEFINES += WIDGET_PLUGIN psi-0.14/src/widgets/iconlabel.h0000644000175000017500000000251711305557613014704 0ustar janjan/* * iconlabel.h - the FancyLabel widget * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONLABEL_H #define ICONLABEL_H #include #include class PsiIcon; class IconLabel : public QLabel { Q_OBJECT Q_PROPERTY( QString psiIconName READ psiIconName WRITE setPsiIcon ) public: IconLabel(QWidget *parent = 0); ~IconLabel(); const PsiIcon *psiIcon () const; QString psiIconName () const; void setPsiIcon (const PsiIcon *, bool copyIcon = true); void setPsiIcon (const QString &); void setScaledContents(int width, int height); class Private; private: Private *d; }; #endif psi-0.14/src/widgets/iconselect.cpp0000644000175000017500000002113111305557613015430 0ustar janjan/* * iconselect.cpp - class that allows user to select an PsiIcon from an Iconset * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconselect.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iconset.h" #include "psitooltip.h" //---------------------------------------------------------------------------- // IconSelectButton //---------------------------------------------------------------------------- //! \if _hide_doc_ /** \class IconSelectButton \brief This button is used by IconSelect and displays one PsiIcon */ class IconSelectButton : public QAbstractButton { Q_OBJECT private: PsiIcon *ic; QString text; QSize s; bool animated; public: IconSelectButton(QWidget *parent) : QAbstractButton(parent) { ic = 0; animated = false; connect (this, SIGNAL(clicked()), SLOT(iconSelected())); } ~IconSelectButton() { iconStop(); if ( ic ) { delete ic; ic = 0; } } void setIcon(const PsiIcon *i) { iconStop(); if ( ic ) { delete ic; ic = 0; } if ( i ) ic = new PsiIcon(*((PsiIcon *)i)); else ic = 0; } const PsiIcon *icon() const { return ic; } QSize sizeHint() const { return s; } void setSizeHint(QSize sh) { s = sh; } signals: void iconSelected(const PsiIcon *); void textSelected(QString); public slots: void aboutToShow() { iconStart(); } void aboutToHide() { iconStop(); } private: void iconStart() { if ( ic ) { connect(ic, SIGNAL(pixmapChanged()), SLOT(iconUpdated())); if ( !animated ) { ic->activated(false); animated = true; } if ( !ic->text().isEmpty() ) { text = ic->defaultText(); // and list of possible variants in the ToolTip QStringList toolTip; foreach(PsiIcon::IconText t, ic->text()) { toolTip += t.text; } QString toolTipText = toolTip.join(", "); if ( toolTipText.length() > 30 ) toolTipText = toolTipText.left(30) + "..."; setToolTip(toolTipText); } } } void iconStop() { if ( ic ) { disconnect(ic, 0, this, 0 ); if ( animated ) { ic->stop(); animated = false; } } } void enterEvent(QEvent *) { setFocus(); update(); } // focus follows mouse mode void leaveEvent(QEvent *) { clearFocus(); update(); } private slots: void iconUpdated() { update(); } void iconSelected() { clearFocus(); if ( ic ) { emit iconSelected(ic); emit textSelected(text); } } private: // reimplemented void paintEvent(QPaintEvent *) { QPainter p(this); QFlags flags = QStyle::State_Active | QStyle::State_Enabled; if ( hasFocus() ) flags |= QStyle::State_Selected; QStyleOptionMenuItem opt; opt.palette = palette(); opt.state = flags; opt.font = font(); opt.rect = rect(); style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this); if ( ic ) { QPixmap pix = ic->pixmap(); p.drawPixmap((width() - pix.width())/2, (height() - pix.height())/2, pix); } } }; //! \endif //---------------------------------------------------------------------------- // IconSelect -- the widget that does all dirty work //---------------------------------------------------------------------------- class IconSelect : public QWidget { Q_OBJECT private: IconSelectPopup *menu; Iconset is; QGridLayout *grid; bool shown; signals: void updatedGeometry(); public: IconSelect(IconSelectPopup *parentMenu); ~IconSelect(); void setIconset(const Iconset &); const Iconset &iconset() const; protected: void noIcons(); void createLayout(); void paintEvent(QPaintEvent *) { QPainter p(this); QStyleOptionMenuItem opt; opt.palette = palette(); opt.rect = rect(); style()->drawControl(QStyle::CE_MenuEmptyArea, &opt, &p, this); } protected slots: void closeMenu(); }; IconSelect::IconSelect(IconSelectPopup *parentMenu) : QWidget(parentMenu) { menu = parentMenu; connect(menu, SIGNAL(textSelected(QString)), SLOT(closeMenu())); grid = 0; noIcons(); } IconSelect::~IconSelect() { } void IconSelect::closeMenu() { // this way all parent menus (if any) would be closed too QMouseEvent me(QEvent::MouseButtonPress, menu->pos() - QPoint(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); menu->mousePressEvent(&me); // just in case menu->close(); } void IconSelect::createLayout() { Q_ASSERT(!grid); grid = new QGridLayout(this); grid->setMargin(style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this)); grid->setSpacing(1); } void IconSelect::noIcons() { createLayout(); QLabel *lbl = new QLabel(this); grid->addWidget(lbl, 0, 0); lbl->setText( tr("No icons available") ); emit updatedGeometry(); } void IconSelect::setIconset(const Iconset &iconset) { is = iconset; // delete all children if (grid) { delete grid; grid = 0; QList list = findChildren(); qDeleteAll(list); } if ( !is.count() ) { noIcons(); return; } // first we need to find optimal size for elements and don't forget about // taking too much screen space float w = 0, h = 0; double count; // the 'double' type is somewhat important for MSVC.NET here QListIterator it = is.iterator(); for (count = 0; it.hasNext(); count++) { PsiIcon *icon = it.next(); w += icon->pixmap().width(); h += icon->pixmap().height(); } w /= count; h /= count; const int margin = 2; int tileSize = (int)qMax(w, h) + 2*margin; QRect r = QApplication::desktop()->availableGeometry( menu ); int maxSize = qMin(r.width(), r.height())*3/4; int size = (int)ceil( sqrt( count ) ); if ( size*tileSize > maxSize ) { // too many icons. find reasonable size. int c = 0; for (w = 0; w <= maxSize; w += tileSize) c++; size = c - 1; } // now, fill grid with elements createLayout(); count = 0; int row = 0; int column = 0; it = is.iterator(); while ( it.hasNext() ) { if ( ++count > size*size ) break; IconSelectButton *b = new IconSelectButton(this); grid->addWidget(b, row, column); b->setIcon( it.next() ); b->setSizeHint( QSize(tileSize, tileSize) ); connect (b, SIGNAL(iconSelected(const PsiIcon *)), menu, SIGNAL(iconSelected(const PsiIcon *))); connect (b, SIGNAL(textSelected(QString)), menu, SIGNAL(textSelected(QString))); connect (menu, SIGNAL(aboutToShow()), b, SLOT(aboutToShow())); connect (menu, SIGNAL(aboutToHide()), b, SLOT(aboutToHide())); if (++column >= size) { ++row; column = 0; } } emit updatedGeometry(); } const Iconset &IconSelect::iconset() const { return is; } //---------------------------------------------------------------------------- // IconSelectPopup //---------------------------------------------------------------------------- class IconSelectPopup::Private : public QObject { Q_OBJECT public: Private(IconSelectPopup *parent) : QObject(parent) , parent_(parent) {} IconSelectPopup* parent_; IconSelect *icsel_; QWidgetAction* widgetAction_; public slots: void updatedGeometry() { widgetAction_->setDefaultWidget(icsel_); parent_->removeAction(widgetAction_); parent_->addAction(widgetAction_); } }; IconSelectPopup::IconSelectPopup(QWidget *parent) : QMenu(parent) { d = new Private(this); d->icsel_ = new IconSelect(this); d->widgetAction_ = new QWidgetAction(this); connect(d->icsel_, SIGNAL(updatedGeometry()), d, SLOT(updatedGeometry())); d->updatedGeometry(); } IconSelectPopup::~IconSelectPopup() { } void IconSelectPopup::setIconset(const Iconset &i) { d->icsel_->setIconset(i); } const Iconset &IconSelectPopup::iconset() const { return d->icsel_->iconset(); } /** It's used by child widget to close the menu by simulating a click slightly outside of menu. This seems to be the best way to achieve this. */ void IconSelectPopup::mousePressEvent(QMouseEvent *e) { QMenu::mousePressEvent(e); } #include "iconselect.moc" psi-0.14/src/widgets/fancylabel.cpp0000644000175000017500000002110311305557613015377 0ustar janjan/* * fancylabel.cpp - the FancyLabel widget * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "fancylabel.h" #include #include #include #include #include #include #include #ifndef WIDGET_PLUGIN #include "iconset.h" #endif #include "iconlabel.h" //---------------------------------------------------------------------------- // IconLabel //---------------------------------------------------------------------------- class IconLabel::Private : public QObject { Q_OBJECT public: IconLabel *label; PsiIcon *icon; bool copyIcon; #ifdef WIDGET_PLUGIN QString iconName; #endif Private(IconLabel *l) { label = l; icon = 0; } ~Private() { stopIcon(); #ifndef WIDGET_PLUGIN if ( icon && copyIcon ) delete icon; #endif } void setIcon(const PsiIcon *i, bool _copyIcon) { copyIcon = _copyIcon; stopIcon(); #ifndef WIDGET_PLUGIN if ( i && copyIcon ) icon = new PsiIcon(*i); else icon = (PsiIcon *)i; #else Q_UNUSED(i); #endif startIcon(); } protected: void stopIcon() { #ifndef WIDGET_PLUGIN if ( icon ) { disconnect(icon, 0, this, 0); icon->stop(); } #endif } void startIcon() { #ifndef WIDGET_PLUGIN if ( icon ) { connect(icon, SIGNAL(pixmapChanged()), SLOT(iconUpdated())); icon->activated(false); // TODO: should icon play sound when it's activated on icon? } iconUpdated(); #endif } private slots: void iconUpdated() { #ifndef WIDGET_PLUGIN label->setPixmap(icon ? icon->pixmap() : QPixmap()); #endif } }; IconLabel::IconLabel(QWidget *parent) : QLabel(parent) { d = new Private(this); } IconLabel::~IconLabel() { delete d; } const PsiIcon *IconLabel::psiIcon () const { return d->icon; } QString IconLabel::psiIconName () const { #ifndef WIDGET_PLUGIN if ( d->icon ) return d->icon->name(); return QString::null; #else return d->iconName; #endif } void IconLabel::setPsiIcon(const PsiIcon *i, bool copyIcon) { d->setIcon(i, copyIcon); } void IconLabel::setPsiIcon(const QString &name) { #ifndef WIDGET_PLUGIN setPsiIcon( IconsetFactory::iconPtr(name) ); #else d->iconName = name; setText("icon:
" + name + "
"); #endif } void IconLabel::setScaledContents(int width, int height) { QLabel::setScaledContents(true); setMinimumSize(width, height); setMaximumSize(width, height); } //---------------------------------------------------------------------------- // MyFancyFrame -- internal //---------------------------------------------------------------------------- class MyFancyFrame : public QFrame { Q_OBJECT protected: void paintEvent(QPaintEvent *event) { QPainter *p = new QPainter(this); p->drawPixmap(0, 0, background); delete p; QFrame::paintEvent(event); } void resizeEvent (QResizeEvent *e) { QFrame::resizeEvent (e); QRect rect = geometry(); int w = rect.width(); if ( rect.height() <= 0 || w <= 0 ) return; // avoid crash int r1, g1, b1; from->getRgb (&r1, &g1, &b1); int r2, g2, b2; to->getRgb (&r2, &g2, &b2); float stepR = (float)(r2 - r1) / w; float stepG = (float)(g2 - g1) / w; float stepB = (float)(b2 - b1) / w; QPixmap pix (rect.width(), rect.height()); QPainter p; p.begin (&pix); for (int i = 0; i < w; i++) { int r = (int)((float)r1 + stepR*i); int g = (int)((float)g1 + stepG*i); int b = (int)((float)b1 + stepB*i); p.setPen ( QColor( r, g, b ) ); p.drawLine ( i, 0, i, rect.height() ); } p.end (); background = pix; update(); } private: QColor *from, *to; QPixmap background; public: MyFancyFrame (QWidget *parent, QColor *_from, QColor *_to) : QFrame (parent) { from = _from; to = _to; } void repaintBackground() { QResizeEvent e(size(), size()); resizeEvent(&e); } }; //---------------------------------------------------------------------------- // FancyLabel //---------------------------------------------------------------------------- class FancyLabel::Private : public QObject { public: MyFancyFrame *frame; IconLabel *text, *help, *pix; QColor from, to, font; QString textStr, helpStr; static int smallFontSize; Private (FancyLabel *parent) : QObject(parent), from(72, 172, 243), to(255, 255, 255), font(0, 0, 0) { QHBoxLayout *mainbox = new QHBoxLayout( parent ); mainbox->setSpacing(0); mainbox->setMargin(0); frame = new MyFancyFrame ( parent, &from, &to ); frame->setFrameShape( QFrame::StyledPanel ); frame->setFrameShadow( QFrame::Raised ); QHBoxLayout *frameLayout = new QHBoxLayout(frame); frameLayout->setMargin(0); frameLayout->setSpacing(0); QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); layout->setSpacing(0); frameLayout->addLayout( layout ); text = new IconLabel( frame ); text->setSizePolicy( (QSizePolicy::Policy)7, (QSizePolicy::Policy)5 ); layout->addWidget( text ); help = new IconLabel( frame ); layout->addWidget( help ); QFont font = help->font(); font.setPointSize(smallFontSize); help->setFont(font); pix = new IconLabel( frame ); pix->setSizePolicy( (QSizePolicy::Policy)1, (QSizePolicy::Policy)5 ); frameLayout->addWidget( pix ); mainbox->addWidget( frame ); } }; int FancyLabel::Private::smallFontSize = 0; FancyLabel::FancyLabel (QWidget *parent) : QWidget (parent) { d = new Private (this); } FancyLabel::~FancyLabel () { } void FancyLabel::setText (const QString &text) { d->textStr = text; d->text->setText (QString("").arg(d->font.name()) + text + ""); } void FancyLabel::setHelp (const QString &help) { d->helpStr = help; QString f1 = ""; QString f2 = ""; if ( d->smallFontSize ) { f1 = ""; f2 = ""; } d->help->setText (QString("").arg(d->font.name()) + f1 + help + f2 + ""); } void FancyLabel::setPixmap (const QPixmap &pix) { d->pix->setPixmap( pix ); } void FancyLabel::setColorFrom (const QColor &col) { d->from = col; d->frame->repaintBackground(); } void FancyLabel::setColorTo (const QColor &col) { d->to = col; d->frame->repaintBackground(); } void FancyLabel::setColorFont (const QColor &col) { d->font = col; d->frame->repaintBackground(); } const QString &FancyLabel::text () const { return d->textStr; } const QString &FancyLabel::help () const { return d->helpStr; } const QPixmap *FancyLabel::pixmap () const { return d->pix->pixmap(); } const QColor &FancyLabel::colorFrom () const { return d->from; } const QColor &FancyLabel::colorTo () const { return d->to; } const QColor &FancyLabel::colorFont () const { return d->font; } const PsiIcon *FancyLabel::psiIcon () const { return d->pix->psiIcon(); } void FancyLabel::setPsiIcon (const PsiIcon *i) { d->pix->setPsiIcon(i); } void FancyLabel::setPsiIcon (const QString &name) { d->pix->setPsiIcon(name); } QString FancyLabel::psiIconName () const { return d->pix->psiIconName(); } FancyLabel::Shape FancyLabel::frameShape () const { return (FancyLabel::Shape)(int)d->frame->frameShape(); } void FancyLabel::setFrameShape (FancyLabel::Shape v) { d->frame->setFrameShape( (QFrame::Shape)(int)v ); d->frame->repaintBackground(); } FancyLabel::Shadow FancyLabel::frameShadow () const { return (FancyLabel::Shadow)(int)d->frame->frameShadow(); } void FancyLabel::setFrameShadow (FancyLabel::Shadow v) { d->frame->setFrameShadow( (QFrame::Shadow)(int)v ); d->frame->repaintBackground(); } int FancyLabel::lineWidth () const { return d->frame->lineWidth(); } void FancyLabel::setLineWidth (int v) { d->frame->setLineWidth(v); d->frame->repaintBackground(); } int FancyLabel::midLineWidth () const { return d->frame->midLineWidth(); } void FancyLabel::setMidLineWidth (int v) { d->frame->setMidLineWidth(v); d->frame->repaintBackground(); } void FancyLabel::setScaledContents(int width, int height) { d->pix->setScaledContents(width, height); } void FancyLabel::setSmallFontSize(int s) { Private::smallFontSize = s; } #include "fancylabel.moc" psi-0.14/src/widgets/psitextview.h0000644000175000017500000000370311305557613015345 0ustar janjan/* * psitextview.h - PsiIcon-aware QTextView subclass widget * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSITEXTVIEW #define PSITEXTVIEW #include class QMimeData; class QTextCursor; class PsiTextView : public QTextEdit { Q_OBJECT public: PsiTextView(QWidget *parent = 0); bool atBottom(); virtual void appendText(const QString &text); QString getHtml() const; QString getPlainText() const; public slots: void scrollToBottom(); void scrollToTop(); protected: // make these functions unusable, because they modify // document structure and we can't override them to // handle Icons correctly void append(const QString &) { } void toHtml() const { } void toPlainText() const { } void insertHtml(const QString &) { } void insertPlainText(const QString &) { } void setHtml(const QString &) { } void setPlainText(const QString &) { } // reimplemented void contextMenuEvent(QContextMenuEvent *e); void mouseMoveEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); QMimeData *createMimeDataFromSelection() const; void resizeEvent(QResizeEvent *); QString getTextHelper(bool html) const; class Private; private: Private *d; }; #endif psi-0.14/src/widgets/psitiplabel.cpp0000644000175000017500000001302611305557613015614 0ustar janjan#include "psitiplabel.h" #include #include #include #include #include #include #include #include #include #include "psirichtext.h" PsiTipLabel *PsiTipLabel::instance_ = 0; PsiTipLabel* PsiTipLabel::instance() { return instance_; } PsiTipLabel::PsiTipLabel(QWidget* parent) : QFrame(parent, Qt::ToolTip) , doc(0) { delete instance_; instance_ = this; } void PsiTipLabel::init(const QString& text) { setText(text); initUi(); resize(sizeHint()); qApp->installEventFilter(this); startHideTimer(); setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0); setPalette(QToolTip::palette()); } void PsiTipLabel::setText(const QString& text) { theText_ = text; isRichText = false; if (doc) { if (Qt::mightBeRichText(theText_)) { isRichText = true; PsiRichText::install(doc); PsiRichText::setText(doc, theText_); } else { doc->setPlainText(theText_); } } } void PsiTipLabel::initUi() { margin = 1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this); setFrameStyle(QFrame::NoFrame); // doc = new QTextDocument(this); // QTextDocumentLayout is private in Qt4 // and it's impossible to set wrapping mode directly. // So we create this QTextEdit instance and use its QTextDocument, // just because QTextEdit can set the wrapping mode. // Yes, this is crazy... QTextEdit *edit = new QTextEdit(this); edit->hide(); edit->setWordWrapMode(QTextOption::WordWrap); doc = edit->document(); doc->setUndoRedoEnabled(false); doc->setDefaultFont(font()); ensurePolished(); setText(theText_); } void PsiTipLabel::startHideTimer() { hideTimer.start(10000, this); } QString PsiTipLabel::theText() const { return theText_; } /* QSize PsiTipLabel::sizeForWidth(int w) const { QRect br; int hextra = 2 * margin; int vextra = hextra; if (isRichText) { hextra = 1; vextra = 1; } PsiRichText::ensureTextLayouted(doc, w); const qreal oldTextWidth = doc->textWidth(); doc->adjustSize(); br = QRect(QPoint(0, 0), doc->size().toSize()); doc->setTextWidth(oldTextWidth); QFontMetrics fm(font()); QSize extra(hextra + 1, vextra); // Make it look good with the default ToolTip font on Mac, which has a small descent. if (fm.descent() == 2 && fm.ascent() >= 11) vextra++; const QSize contentsSize(br.width() + hextra, br.height() + vextra); return contentsSize; } */ QSize PsiTipLabel::sizeHint() const { QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); fmt.setMargin(0); doc->rootFrame()->setFrameFormat(fmt); // PsiRichText::ensureTextLayouted(doc, -1); doc->adjustSize(); // br = QRect(QPoint(0, 0), doc->size().toSize()); // this way helps to fight empty space on the right: QSize docSize = QSize(doc->idealWidth(), doc->size().toSize().height()); QFontMetrics fm(font()); QSize extra(2*margin + 2, 2*margin + 1); // "+" for tip's frame // Make it look good with the default ToolTip font on Mac, which has a small descent. if (fm.descent() == 2 && fm.ascent() >= 11) ++extra.rheight(); return docSize + extra; } QSize PsiTipLabel::minimumSizeHint() const { return sizeHint(); // qWarning("PsiTipLabel::minimumSizeHint"); // ensurePolished(); // QSize sh = sizeForWidth(-1); // QSize msh(-1, -1); // // msh.rheight() = sizeForWidth(QWIDGETSIZE_MAX).height(); // height for one line // msh.rwidth() = sizeForWidth(0).width(); // wrap ? size of biggest word : min doc size // if (sh.height() < msh.height()) // msh.rheight() = sh.height(); // // return msh; } void PsiTipLabel::paintEvent(QPaintEvent *) { QStylePainter p(this); QStyleOptionFrame opt; opt.init(this); p.drawPrimitive(QStyle::PE_PanelTipLabel, opt); p.end(); // stolen from QLabel::paintEvent QPainter painter(this); drawFrame(&painter); QRect cr = contentsRect(); cr.adjust(margin, margin, -margin, -margin); PsiRichText::ensureTextLayouted(doc, width() - 2*margin); QAbstractTextDocumentLayout *layout = doc->documentLayout(); // QRect lr = rect(); QRect lr = cr; QAbstractTextDocumentLayout::PaintContext context; // Adjust the palette context.palette = palette(); if (foregroundRole() != QPalette::Text && isEnabled()) context.palette.setColor(QPalette::Text, context.palette.color(foregroundRole())); painter.save(); painter.translate(lr.x() + 1, lr.y() + 1); painter.setClipRect(lr.translated(-lr.x() - 1, -lr.y() - 1)); layout->draw(&painter, context); painter.restore(); } PsiTipLabel::~PsiTipLabel() { instance_ = 0; } void PsiTipLabel::hideTip() { hide(); // timer based deletion to prevent animation deleteTimer.start(250, this); } void PsiTipLabel::enterEvent(QEvent*) { hideTip(); } void PsiTipLabel::timerEvent(QTimerEvent *e) { if (e->timerId() == hideTimer.timerId()) hideTip(); else if (e->timerId() == deleteTimer.timerId()) deleteLater(); } bool PsiTipLabel::eventFilter(QObject *, QEvent *e) { switch (e->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { int key = static_cast(e)->key(); Qt::KeyboardModifiers mody = static_cast(e)->modifiers(); if ((mody & Qt::KeyboardModifierMask) || (key == Qt::Key_Shift || key == Qt::Key_Control || key == Qt::Key_Alt || key == Qt::Key_Meta)) break; } case QEvent::Leave: case QEvent::WindowActivate: case QEvent::WindowDeactivate: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::FocusIn: case QEvent::FocusOut: case QEvent::Wheel: hideTip(); default: ; } return false; } psi-0.14/src/widgets/iconwidget.h0000644000175000017500000000223211305557613015102 0ustar janjan/* * iconwidget.h - misc. Iconset- and PsiIcon-aware widgets * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONWIDGET_H #define ICONWIDGET_H #include #include class Iconset; class IconWidgetItem : public QObject, public QListWidgetItem { Q_OBJECT public: IconWidgetItem(QListWidget *parent = 0) : QListWidgetItem(parent) {} virtual const Iconset *iconset() const { return 0; } }; #endif psi-0.14/src/widgets/psitabwidget.cpp0000644000175000017500000001777211305557613016006 0ustar janjan/* * psitabwidget.cpp - Customised QTabWidget for Psi * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psitabwidget.h" #include "psitabbar.h" #include #include #include #include #include #include #include #include /** * Constructor */ PsiTabWidget::PsiTabWidget(QWidget *parent) : QWidget(parent) { tabsPosition_ = QTabWidget::East; // impossible => uninitialised state tabBar_ = new PsiTabBar(this); tabBar_->setUsesScrollButtons(true); layout_ = new QVBoxLayout(this); layout_->setMargin(0); layout_->setSpacing(0); barLayout_ = new QHBoxLayout; layout_->addLayout(barLayout_); barLayout_->setMargin(0); barLayout_->setSpacing(0); barLayout_->addWidget(tabBar_, 2); barLayout_->setAlignment(Qt::AlignLeft); int buttonwidth = qMax(tabBar_->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, tabBar_), QApplication::globalStrut().width()); downButton_ = new QToolButton(this); downButton_->setMinimumSize(3,3); downButton_->setFixedWidth(buttonwidth); downButton_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); menu_ = new QMenu(this); downButton_->setMenu(menu_); connect(menu_, SIGNAL(aboutToShow()), SLOT(menu_aboutToShow())); connect(menu_, SIGNAL(triggered(QAction*)), SLOT(menu_triggered(QAction*))); barLayout_->addWidget(downButton_); closeButton_ = new QToolButton(this); closeButton_->setMinimumSize(3,3); closeButton_->setFixedWidth(buttonwidth); closeButton_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); barLayout_->addWidget(closeButton_); closeButton_->setText("x"); downButton_->setArrowType(Qt::DownArrow); downButton_->setPopupMode(QToolButton::InstantPopup); stacked_ = new QStackedLayout(layout_); setTabPosition(QTabWidget::North); connect( tabBar_, SIGNAL(mouseDoubleClickTab(int)), SLOT(mouseDoubleClickTab(int))); connect( tabBar_, SIGNAL( currentChanged(int)), SLOT(tab_currentChanged(int))); connect( tabBar_, SIGNAL( contextMenu(QContextMenuEvent*,int)), SLOT( tab_contextMenu(QContextMenuEvent*,int))); connect( closeButton_, SIGNAL(clicked()), SIGNAL(closeButtonClicked())); } void PsiTabWidget::setCloseIcon(const QIcon& icon) { closeButton_->setIcon(icon); closeButton_->setText(""); } /** * Destructor */ PsiTabWidget::~PsiTabWidget() { } /** * Set the color of text on a tab. * \param tab Widget for the tab to change. * \param color Color to set text. */ void PsiTabWidget::setTabTextColor( QWidget* tab, const QColor& color) { for (int i = 0; i < count(); i++) { if (widget(i) == tab) { tabBar_->setTabTextColor(i, color); } } } /** * Returns the specified widget. * \param index Widget to return. * \return Specified widget. */ QWidget *PsiTabWidget::widget(int index) { return widgets_[index]; } void PsiTabWidget::mouseDoubleClickTab(int tab) { emit mouseDoubleClickTab(widget(tab)); } /** * Number of tabs/widgets */ int PsiTabWidget::count() { return tabBar_->count(); } /** * Returns the widget of the current page */ QWidget *PsiTabWidget::currentPage() { if (currentPageIndex() == -1) return 0; return widgets_[currentPageIndex()]; } void PsiTabWidget::tab_currentChanged(int tab) { // qt 4.4 sends -1 i case of an empty QTabbar, ignore that case. if (tab == -1) return; setCurrentPage(tab); emit currentChanged(currentPage()); } /** * Returns the index of the current page */ int PsiTabWidget::currentPageIndex() { return tabBar_->currentIndex(); } /** * Add the Widget to the tab stack. */ void PsiTabWidget::addTab(QWidget *widget, QString name) { Q_ASSERT(widget); if (widgets_.contains(widget)) { return; } widgets_.append(widget); stacked_->addWidget(widget); tabBar_->addTab(name); showPage(currentPage()); } /** * Selects the page for the specified widget. */ void PsiTabWidget::showPage(QWidget* widget) { for (int i = 0; i < count(); i++) { if (widgets_[i] == widget) { showPageDirectly(widget); tabBar_->setCurrentIndex(i); } } } /** * Selects the page for the specified widget (internal helper). */ void PsiTabWidget::showPageDirectly(QWidget* widget) { // FIXME move this back into showPage? should this be in the public interface? for (int i=0; i < count(); i++) { if (widgets_[i] == widget) { stacked_->setCurrentWidget(widget); // currentChanged is handled by tabBar_ return; } } } /** * Removes the page for the specified widget. */ void PsiTabWidget::removePage(QWidget* widget) { for (int i=0; i < count(); i++) { if (widgets_[i] == widget) { stacked_->removeWidget(widget); widgets_.remove(i); tabBar_->removeTab(i); // tabBar_ emits current changed if needed } } } /** * Finds the index of the widget (or -1 if missing). */ int PsiTabWidget::getIndex(QWidget* widget) { for (int i = 0; i < count(); i++) { if (widgets_[i] == widget) { return i; } } return -1; } /** * Set the text of the tab. */ void PsiTabWidget::setTabText(QWidget* widget, const QString& label) { int index = getIndex(widget); if (index == -1) { return; } tabBar_->setTabText(index, label); } void PsiTabWidget::setCurrentPage(int index) { Q_ASSERT(index >=0 && index < count()); showPage(widgets_[index]); } void PsiTabWidget::removeCurrentPage() { removePage(currentPage()); } void PsiTabWidget::setTabPosition(QTabWidget::TabPosition pos) { if (tabsPosition_ == pos) { return; } tabsPosition_ = pos; tabBar_->setShape(tabsPosition_ == QTabWidget::North ? QTabBar::RoundedNorth : QTabBar::RoundedSouth); layout_->removeItem(barLayout_); layout_->removeItem(stacked_); // addLayout sets parent and complains if it's already set barLayout_->setParent(0); stacked_->setParent(0); if (tabsPosition_ == QTabWidget::North) { layout_->addLayout(barLayout_); layout_->addLayout(stacked_); } else { layout_->addLayout(stacked_); layout_->addLayout(barLayout_); } } void PsiTabWidget::menu_aboutToShow() { menu_->clear(); bool vis = false; for (int i = 0; i < tabBar_->count(); i++) { QRect r = tabBar_->tabRect(i); bool newvis = tabBar_->rect().contains(r); if (newvis != vis) { menu_->addSeparator (); vis = newvis; } menu_->addAction(tabBar_->tabText(i))->setData(i+1); } emit aboutToShowMenu(menu_); } void PsiTabWidget::menu_triggered(QAction *act) { int idx = act->data().toInt(); if (idx <= 0 || idx > tabBar_->count()) { // out of range // emit signal? } else { setCurrentPage(idx-1); } } void PsiTabWidget::tab_contextMenu( QContextMenuEvent * event, int tab) { emit tabContextMenu(tab, tabBar_->mapToGlobal(event->pos()), event); } QWidget* PsiTabWidget::page(int index) { Q_ASSERT(index >=0 && index < count()); return widgets_[index]; } /** * Show/hide the tab bar of this widget */ void PsiTabWidget::setTabBarShown(bool shown) { if (shown && tabBar_->isHidden()) { tabBar_->show(); } else if (!shown && !tabBar_->isHidden()) { tabBar_->hide(); } } /** * Show/hide the menu and close buttons that appear next to the tab bar */ void PsiTabWidget::setTabButtonsShown(bool shown) { if (shown && downButton_->isHidden()) { downButton_->show(); closeButton_->show(); } else if (!shown && !downButton_->isHidden()) { downButton_->hide(); closeButton_->hide(); } } /** * Enable/disable dragging of tabs */ void PsiTabWidget::setDragsEnabled(bool enabled) { ((PsiTabBar *)tabBar_)->setDragsEnabled(enabled); } psi-0.14/src/widgets/fancylabel.h0000644000175000017500000000677511305557613015066 0ustar janjan/* * fancylabel.h - the FancyLabel widget * Copyright (C) 2003 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef FANCYLABEL_H #define FANCYLABEL_H #include #include class QPixmap; class QColor; class PsiIcon; class FancyLabel : public QWidget { Q_OBJECT Q_PROPERTY( QPixmap pixmap READ pixmap WRITE setPixmap ) Q_PROPERTY( QString text READ text WRITE setText ) Q_PROPERTY( QString help READ help WRITE setHelp ) Q_PROPERTY( QColor colorFrom READ colorFrom WRITE setColorFrom ) Q_PROPERTY( QColor colorTo READ colorTo WRITE setColorTo ) Q_PROPERTY( QColor colorFont READ colorFont WRITE setColorFont ) Q_PROPERTY( QString psiIconName READ psiIconName WRITE setPsiIcon ) Q_ENUMS( Shape Shadow ) Q_PROPERTY( Shape frameShape READ frameShape WRITE setFrameShape ) Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow ) Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth ) Q_PROPERTY( int midLineWidth READ midLineWidth WRITE setMidLineWidth ) public: FancyLabel (QWidget *parent = 0); ~FancyLabel (); const QString &text () const; const QString &help () const; const QPixmap *pixmap () const; const QColor &colorFrom () const; const QColor &colorTo () const; const QColor &colorFont () const; const PsiIcon *psiIcon () const; QString psiIconName () const; void setText (const QString &); void setHelp (const QString &); void setPixmap (const QPixmap &); void setColorFrom (const QColor &); void setColorTo (const QColor &); void setColorFont (const QColor &); void setPsiIcon (const PsiIcon *); void setPsiIcon (const QString &); enum Shape { NoFrame = 0, // no frame Box = 0x0001, // rectangular box Panel = 0x0002, // rectangular panel WinPanel = 0x0003, // rectangular panel (Windows) StyledPanel = 0x0006, // rectangular panel depending on the GUI style PopupPanel = 0x0007, // rectangular panel depending on the GUI style MenuBarPanel = 0x0008, ToolBarPanel = 0x0009, LineEditPanel = 0x000a, TabWidgetPanel = 0x000b, GroupBoxPanel = 0x000c, MShape = 0x000f // mask for the shape }; enum Shadow { Plain = 0x0010, // plain line Raised = 0x0020, // raised shadow effect Sunken = 0x0030, // sunken shadow effect MShadow = 0x00f0 }; // mask for the shadow Shape frameShape () const; void setFrameShape (Shape); Shadow frameShadow () const; void setFrameShadow (Shadow); int lineWidth () const; void setLineWidth (int); int midLineWidth () const; void setMidLineWidth (int); void setScaledContents(int width, int height); static void setSmallFontSize(int); private: class Private; Private *d; }; #endif psi-0.14/src/widgets/psirichtext.h0000644000175000017500000000337011305557613015320 0ustar janjan/* * psirichtext.h - helper functions to handle Icons in QTextDocuments * Copyright (C) 2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include class QTextEdit; class PsiRichText { public: static void install(QTextDocument *doc); static void ensureTextLayouted(QTextDocument *doc, int documentWidth, Qt::Alignment align = Qt::AlignLeft, Qt::LayoutDirection layoutDirection = Qt::LeftToRight, bool textWordWrap = true); static void setText(QTextDocument *doc, const QString &text); static void insertIcon(QTextCursor &cursor, const QString &iconName, const QString &iconText); static void appendText(QTextDocument *doc, QTextCursor &cursor, const QString &text); static QString convertToPlainText(const QTextDocument *doc); static void addEmoticon(QTextEdit *textEdit, const QString &emoticon); struct Selection { int start, end; }; static Selection saveSelection(QTextEdit *textEdit, QTextCursor &cursor); static void restoreSelection(QTextEdit *textEdit, QTextCursor &cursor, Selection selection); }; psi-0.14/src/widgets/actionlineedit.cpp0000644000175000017500000001350511305557613016301 0ustar janjan/* * actionlineedit.h - QLineEdit widget with buttons on right side * Copyright (C) 2009 Sergey Il'inykh * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include "actionlineedit.h" ActionLineEditButton::ActionLineEditButton( QWidget *parent ) : QAbstractButton(parent), action_(0), popup_(0) { setCursor(Qt::PointingHandCursor); } /** * Same as for QToolButton */ void ActionLineEditButton::setDefaultAction(QAction *act) { action_ = act; //TODO what if we set another action. disconnect events... connect(this, SIGNAL(clicked()), act, SLOT(trigger())); connect(act, SIGNAL(changed()), this, SLOT(updateFromAction())); updateFromAction(); } QAction * ActionLineEditButton::defaultAction() { return action_; } void ActionLineEditButton::setPopup(QWidget *widget) { if (!popup_) { disconnect(this, SLOT(showPopup())); //TODO test it. } if (widget) { popup_ = widget; popup_->setWindowFlags(Qt::Popup); connect(this, SIGNAL(clicked()), this, SLOT(showPopup())); popup_->adjustSize(); } } void ActionLineEditButton::showPopup() { if (popup_) { if (popup_->isHidden()) { const QPoint pos = mapToGlobal(QPoint(width()-popup_->width(), height())); popup_->move(pos); popup_->show(); } else { popup_->hide(); } } } /** * Invlidates button is action changed */ void ActionLineEditButton::updateFromAction() { setText(action_->text()); setIcon(action_->icon()); setToolTip(action_->toolTip()); setCheckable(action_->isCheckable()); setChecked(action_->isChecked()); setEnabled(action_->isEnabled()); setVisible(action_->isVisible()); adjustSize(); } void ActionLineEditButton::paintEvent ( QPaintEvent * event ) { Q_UNUSED(event) QPainter painter(this); ActionLineEdit *p = (ActionLineEdit *)parent(); Qt::ToolButtonStyle tbs = p->toolButtonStyle(); int lpos = 0; //int h = height(); int h = p->minimumSizeHint().height()-2; //2px padding from max. if (!icon().isNull() && tbs != Qt::ToolButtonTextOnly) { const QPixmap pix = icon().pixmap( QSize(h, h), isEnabled()?QIcon::Normal:QIcon::Disabled, isChecked()?QIcon::On:QIcon::Off ); painter.drawPixmap(0, (height() - pix.height())/2, pix); lpos += pix.width(); } if (!(text().isEmpty()) && tbs != Qt::ToolButtonIconOnly) { if (lpos) { lpos+=2; // notice these 2px also in the sizeHint! } painter.drawText(QRect(lpos, 0, width()-lpos, height()), Qt::AlignVCenter, text()); } } QSize ActionLineEditButton::sizeHint () const { ActionLineEdit *p = (ActionLineEdit *)parent(); Qt::ToolButtonStyle tbs = p->toolButtonStyle(); int w = 0, h = p->height(); int ih = ((QLineEdit *)parent())->minimumSizeHint().height()-2; //2px padding from max. the same as in paintEvent QSize is(0, 0), ts(0, 0); if (!icon().isNull() && tbs != Qt::ToolButtonTextOnly) { is = icon().actualSize( QSize(ih, ih), isEnabled()?QIcon::Normal:QIcon::Disabled, isChecked()?QIcon::On:QIcon::Off ); } if (tbs != Qt::ToolButtonIconOnly) { ts = fontMetrics().size(Qt::TextSingleLine, text()); } // 4px padding right, 2px -space between icon and text QSize ret = QSize(((w = ts.width())>0?(w+(is.width()?2:0)):0) + is.width() + 4, h); return ret; } ActionLineEdit::ActionLineEdit(QWidget *parent) : QLineEdit(parent), toolButtonStyle_(Qt::ToolButtonIconOnly) { QHBoxLayout *layout = new QHBoxLayout; setLayout(layout); layout->setSpacing(0); layout->setMargin(0); layout->insertStretch(0); } ActionLineEditButton * ActionLineEdit::widgetForAction ( QAction * action ) { QHBoxLayout *lo = (QHBoxLayout *)layout(); ActionLineEditButton *btn; for (int i=1, count=lo->count(); iitemAt(i)->widget(); if (btn->defaultAction() == action) { return btn; } } return 0; } void ActionLineEdit::actionEvent ( QActionEvent * event ) { QHBoxLayout *lo = (QHBoxLayout *)layout(); QAction *act = event->action(); ActionLineEditButton *btn; if (event->type() == QEvent::ActionAdded) { btn = new ActionLineEditButton(this); QAction *before = event->before(); int beforeInd; if (before && (beforeInd = actions().indexOf(before)) >= 0) { //TODO test it lo->insertWidget(beforeInd + 1, btn); //1 - first item is spacer. skip it } else { lo->addWidget(btn); } btn->setDefaultAction(act); } else if (event->type() == QEvent::ActionRemoved) { for (int i=1, count=lo->count(); iitemAt(i)->widget(); if (btn->defaultAction() == act) { lo->removeWidget(btn); delete btn; break; } } } int sumWidth = 0; for (int i=1, count=lo->count(); iitemAt(i)->widget(); if (btn->defaultAction()->isVisible()) { sumWidth += btn->width(); } } sumWidth += 4; //+4px padding between text and buttons. should looks better (magic number) #if QT_VERSION >= 0x040500 int mLeft, mTop, mRight, mBottom; getTextMargins(&mLeft, &mTop, &mRight, &mBottom); setTextMargins(mLeft, mTop, sumWidth, mBottom); #else setStyleSheet(QString("padding-right:%1px").arg(sumWidth)); //this breaks height of widget.. Qt bug? #endif } psi-0.14/src/widgets/iconaction.h0000644000175000017500000000554611305557613015107 0ustar janjan/* * iconaction.h - the QAction subclass that uses Icons and supports animation * Copyright (C) 2003-2005 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONACTION_H #define ICONACTION_H #include #include class QToolButton; class QPixmap; class QIcon; class PsiIcon; class IconToolButton; class QChildEvent; class IconAction : public QAction { Q_OBJECT public: IconAction(QObject *parent, const QString &name = QString()); IconAction(const QString &statusTip, const QString &icon, const QString &text, QKeySequence accel, QObject *parent, const QString &name = QString(), bool checkable = FALSE); IconAction(const QString &statusTip, const QString &text, QKeySequence accel, QObject *parent, const QString &name = QString(), bool checkable = FALSE); ~IconAction(); virtual bool addTo(QWidget *); const PsiIcon *psiIcon() const; void setPsiIcon(const PsiIcon *); void setPsiIcon(const QString &); QString psiIconName() const; void setMenu( QMenu * ); void setIcon( const QIcon & ); void setVisible( bool ); virtual IconAction *copy() const; virtual IconAction &operator=( const IconAction & ); public slots: void setEnabled(bool); void setChecked(bool); void setText(const QString &); protected: virtual void doSetMenu(QMenu* menu); virtual void addingToolButton(IconToolButton *) { } //virtual void addingMenuItem(QPopupMenu *, int id) { Q_UNUSED(id); } QList buttonList(); QString toolTipFromMenuText() const; private slots: void objectDestroyed(); void iconUpdated(); void toolButtonToggled(bool); public: class Private; private: Private *d; friend class Private; }; class IconActionGroup : public IconAction { Q_OBJECT public: IconActionGroup(QObject *parent, const char *name = 0, bool exclusive = false); ~IconActionGroup(); void setExclusive( bool ); bool isExclusive() const; void add( QAction * ); void addSeparator(); bool addTo( QWidget * ); void setUsesDropDown( bool ); bool usesDropDown() const; void childEvent(QChildEvent *); void addingToolButton(IconToolButton *); IconAction *copy() const; public: class Private; private: Private *d; friend class Private; }; #endif psi-0.14/src/widgets/psitextview.cpp0000644000175000017500000001615611305557613015706 0ustar janjan/* * psitextview.cpp - PsiIcon-aware QTextView subclass widget * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psitextview.h" #include #include #include #include #include #include "urlobject.h" #include "psirichtext.h" //---------------------------------------------------------------------------- // PsiTextView::Private //---------------------------------------------------------------------------- //! \if _hide_doc_ class PsiTextView::Private : public QObject { Q_OBJECT public: Private(QObject *parent) : QObject(parent) { anchorOnMousePress = QString(); hadSelectionOnMousePress = false; } QString anchorOnMousePress; bool hadSelectionOnMousePress; QString fragmentToPlainText(const QTextFragment &fragment); QString blockToPlainText(const QTextBlock &block); QString documentFragmentToPlainText(const QTextDocument &doc, QTextFrame::Iterator frameIt); }; //!endif //---------------------------------------------------------------------------- // PsiTextView //---------------------------------------------------------------------------- /** * \class PsiTextView * \brief PsiIcon-aware QTextView-subclass widget */ /** * Default constructor. */ PsiTextView::PsiTextView(QWidget *parent) : QTextEdit(parent) { d = new Private(this); setReadOnly(true); PsiRichText::install(document()); viewport()->setMouseTracking(true); // we want to get all mouseMoveEvents } /** * This function returns true if vertical scroll bar is * at its maximum position. */ bool PsiTextView::atBottom() { // '32' is 32 pixels margin, which was used in the old code return (verticalScrollBar()->maximum() - verticalScrollBar()->value()) <= 32; } /** * Scrolls the vertical scroll bar to its maximum position i.e. to the bottom. */ void PsiTextView::scrollToBottom() { verticalScrollBar()->setValue(verticalScrollBar()->maximum()); } /** * Scrolls the vertical scroll bar to its minimum position i.e. to the top. */ void PsiTextView::scrollToTop() { verticalScrollBar()->setValue(verticalScrollBar()->minimum()); } /** * This function is provided for convenience. Please see * PsiRichText::appendText() documentation for usage details. */ void PsiTextView::appendText(const QString &text) { QTextCursor cursor = textCursor(); PsiRichText::Selection selection = PsiRichText::saveSelection(this, cursor); PsiRichText::appendText(document(), cursor, text); PsiRichText::restoreSelection(this, cursor, selection); setTextCursor(cursor); } QString PsiTextView::getTextHelper(bool html) const { PsiTextView *ptv = (PsiTextView *)this; QTextCursor cursor = ptv->textCursor(); int position = ptv->verticalScrollBar()->value(); bool unselectAll = false; if (!textCursor().hasSelection()) { ptv->selectAll(); unselectAll = true; } QMimeData *mime = createMimeDataFromSelection(); QString result; if (html) result = mime->html(); else result = mime->text(); delete mime; // we need to restore original position if selectAll() // was called, because setTextCursor() (which is necessary // to clear selection) will move vertical scroll bar if (unselectAll) { cursor.clearSelection(); ptv->setTextCursor(cursor); ptv->verticalScrollBar()->setValue(position); } return result; } /** * Returns HTML markup for selected text. If no text is selected, returns * HTML markup for all text. */ QString PsiTextView::getHtml() const { return getTextHelper(true); } QString PsiTextView::getPlainText() const { return getTextHelper(false); } void PsiTextView::contextMenuEvent(QContextMenuEvent *e) { QMenu *menu; if (!anchorAt(e->pos()).isEmpty()) menu = URLObject::getInstance()->createPopupMenu(anchorAt(e->pos())); else menu = createStandardContextMenu(); menu->exec(e->globalPos()); e->accept(); delete menu; } // Copied (with modifications) from QTextBrowser void PsiTextView::mouseMoveEvent(QMouseEvent *e) { QTextEdit::mouseMoveEvent(e); QString anchor = anchorAt(e->pos()); viewport()->setCursor(anchor.isEmpty() ? Qt::ArrowCursor : Qt::PointingHandCursor); } // Copied (with modifications) from QTextBrowser void PsiTextView::mousePressEvent(QMouseEvent *e) { d->anchorOnMousePress = anchorAt(e->pos()); if (!textCursor().hasSelection() && !d->anchorOnMousePress.isEmpty()) { QTextCursor cursor = textCursor(); QPoint mapped = QPoint(e->pos().x() + horizontalScrollBar()->value(), e->pos().y() + verticalScrollBar()->value()); // from QTextEditPrivate::mapToContents const int cursorPos = document()->documentLayout()->hitTest(mapped, Qt::FuzzyHit); if (cursorPos != -1) cursor.setPosition(cursorPos); setTextCursor(cursor); } QTextEdit::mousePressEvent(e); d->hadSelectionOnMousePress = textCursor().hasSelection(); } // Copied (with modifications) from QTextBrowser void PsiTextView::mouseReleaseEvent(QMouseEvent *e) { QTextEdit::mouseReleaseEvent(e); if (!(e->button() & Qt::LeftButton)) return; const QString anchor = anchorAt(e->pos()); if (anchor.isEmpty()) return; if (!textCursor().hasSelection() || (anchor == d->anchorOnMousePress && d->hadSelectionOnMousePress)) URLObject::getInstance()->popupAction(anchor); } /** * This is overridden in order to properly convert Icons back * to their original text. */ QMimeData *PsiTextView::createMimeDataFromSelection() const { QTextDocument *doc = new QTextDocument(); QTextCursor cursor(doc); cursor.insertFragment(textCursor().selection()); QString text = PsiRichText::convertToPlainText(doc); delete doc; QMimeData *data = new QMimeData; data->setText(text); data->setHtml(Qt::convertFromPlainText(text)); return data; } /** * Ensures that if PsiTextView was scrolled to bottom when resize * operation happened, it will still be scrolled to bottom after the fact. */ void PsiTextView::resizeEvent(QResizeEvent *e) { bool atEnd = verticalScrollBar()->value() == verticalScrollBar()->maximum(); bool atStart = verticalScrollBar()->value() == verticalScrollBar()->minimum(); double value = 0; if (!atEnd && !atStart) value = (double)verticalScrollBar()->maximum() / (double)verticalScrollBar()->value(); QTextEdit::resizeEvent(e); if (atEnd) verticalScrollBar()->setValue(verticalScrollBar()->maximum()); else if (value != 0) verticalScrollBar()->setValue((int) ((double)verticalScrollBar()->maximum() / value)); } #include "psitextview.moc" psi-0.14/src/widgets/actionlineedit.h0000644000175000017500000000367311305557613015753 0ustar janjan/* * actionlineedit.h - QLineEdit widget with buttons on right side * Copyright (C) 2009 Sergey Il'inykh * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACTIONLINEEDIT_H #define ACTIONLINEEDIT_H #include #include #include #include class ActionLineEditButton : public QAbstractButton { Q_OBJECT public: ActionLineEditButton( QWidget *parent ); void setDefaultAction(QAction *); QAction * defaultAction(); void setPopup(QWidget *); public slots: void updateFromAction(); //FIXME private void showPopup(); protected: void paintEvent ( QPaintEvent * event ); QSize sizeHint () const; private: QAction *action_; QWidget *popup_; }; class ActionLineEdit : public QLineEdit { Q_OBJECT Q_PROPERTY(Qt::ToolButtonStyle toolButtonStyle READ toolButtonStyle WRITE setToolButtonStyle) Q_ENUMS(Qt::ToolButtonStyle) public: ActionLineEdit( QWidget *parent ); ActionLineEditButton * widgetForAction ( QAction * action ); void actionEvent ( QActionEvent * event ); Qt::ToolButtonStyle toolButtonStyle() const { return toolButtonStyle_; } void setToolButtonStyle(const Qt::ToolButtonStyle newStyle) { toolButtonStyle_ = newStyle; } private: Qt::ToolButtonStyle toolButtonStyle_; }; #endif // ACTIONLINEEDIT_H psi-0.14/src/registrationdlg.cpp0000644000175000017500000002132611305557613015041 0ustar janjan/* * registrationdlg.cpp * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include "jidutil.h" #include "psiaccount.h" #include "registrationdlg.h" #include "busywidget.h" #include "common.h" #include "xdata_widget.h" #include "xmpp_tasks.h" #include "textutil.h" #include "xmpp_xdata.h" #include "xmpp_xmlcommon.h" using namespace XMPP; //---------------------------------------------------------------------------- // JT_XRegister //---------------------------------------------------------------------------- class JT_XRegister : public JT_Register { Q_OBJECT public: JT_XRegister(Task *parent); void setXForm(const Form &frm, const XData &_form); bool take(const QDomElement &); QDomElement iq() const; QDomElement xdataElement() const; void onGo(); private: QDomElement _iq; }; JT_XRegister::JT_XRegister( Task *parent ) : JT_Register( parent ) { } bool JT_XRegister::take( const QDomElement &x ) { _iq = x; return JT_Register::take( x ); } QDomElement JT_XRegister::iq() const { return _iq; } void JT_XRegister::setXForm(const Form &frm, const XData &_form) { JT_Register::setForm( frm ); _iq = createIQ(doc(), "set", frm.jid().full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); _iq.appendChild(query); XData form( _form ); form.setType( XData::Data_Submit ); query.appendChild( form.toXml( doc() ) ); } void JT_XRegister::onGo() { if ( !_iq.isNull() ) send( _iq ); else JT_Register::onGo(); } QDomElement JT_XRegister::xdataElement() const { QDomNode n = queryTag(iq()).firstChild(); for (; !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if (i.isNull()) continue; if (i.attribute("xmlns") == "jabber:x:data") return i; } return QDomElement(); } //---------------------------------------------------------------------------- // RegistrationDlg //---------------------------------------------------------------------------- class RegistrationDlg::Private { public: Private() {} Jid jid; PsiAccount *pa; QPushButton *pb_close, *pb_reg; QPointer jt; int type; BusyWidget *busy; QLabel *lb_top; QWidget *gr_form; QGridLayout *gr_form_layout; Form form; QList lb_field; QList le_field; XDataWidget *xdata; }; RegistrationDlg::RegistrationDlg(const Jid &jid, PsiAccount *pa) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); d = new Private; d->jid = jid; d->pa = pa; d->pa->dialogRegister(this, d->jid); d->jt = 0; d->xdata = 0; setWindowTitle(tr("Registration: %1").arg(d->jid.full())); QVBoxLayout *vb1 = new QVBoxLayout(this); vb1->setMargin(4); d->lb_top = new QLabel(this); d->lb_top->setFrameStyle( QFrame::Panel | QFrame::Sunken ); d->lb_top->hide(); vb1->addWidget(d->lb_top); d->gr_form = new QWidget(this); d->gr_form_layout = new QGridLayout(d->gr_form); d->gr_form_layout->setSpacing(4); vb1->addWidget(d->gr_form); d->gr_form->hide(); QFrame *line = new QFrame(this); line->setFixedHeight(2); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); vb1->addWidget(line); QHBoxLayout *hb1 = new QHBoxLayout; vb1->addLayout(hb1); d->busy = new BusyWidget(this); hb1->addWidget(d->busy); hb1->addStretch(1); d->pb_reg = new QPushButton(tr("&Register"), this); d->pb_reg->setDefault(true); connect(d->pb_reg, SIGNAL(clicked()), SLOT(doRegSet())); hb1->addWidget(d->pb_reg); d->pb_close = new QPushButton(tr("&Close"), this); connect(d->pb_close, SIGNAL(clicked()), SLOT(close())); hb1->addWidget(d->pb_close); d->pb_reg->hide(); doRegGet(); } RegistrationDlg::~RegistrationDlg() { delete d->jt; d->pa->dialogUnregister(this); delete d; } /*void RegistrationDlg::closeEvent(QCloseEvent *e) { e->ignore(); reject(); }*/ void RegistrationDlg::done(int r) { if(d->busy->isActive() && d->type == 1) { int n = QMessageBox::information(this, tr("Busy"), tr("Registration has already been submitted, so closing this window will not prevent the registration from happening. Do you still wish to close?"), tr("&Yes"), tr("&No")); if(n != 0) return; } QDialog::done(r); } void RegistrationDlg::doRegGet() { d->lb_top->setText(tr("Fetching registration form for %1 ...").arg(d->jid.full())); d->lb_top->show(); d->busy->start(); d->type = 0; d->jt = new JT_XRegister(d->pa->client()->rootTask()); connect(d->jt, SIGNAL(finished()), SLOT(jt_finished())); d->jt->getForm(d->jid); d->jt->go(true); } void RegistrationDlg::doRegSet() { if(!d->pa->checkConnected(this)) return; d->jt = new JT_XRegister(d->pa->client()->rootTask()); if ( !d->xdata ) { Form submitForm = d->form; Q_ASSERT(d->le_field.count() == submitForm.count()); // import the changes back into the form. // the QPtrList of QLineEdits should be in the same order for (int i = 0; i < submitForm.count(); ++i) { submitForm[i].setValue(d->le_field[i]->text()); } d->jt->setForm(submitForm); } else { XData form; form.setFields( d->xdata->fields() ); d->jt->setXForm( d->form, form ); } d->gr_form->setEnabled(false); d->pb_reg->setEnabled(false); d->busy->start(); d->type = 1; connect(d->jt, SIGNAL(finished()), SLOT(jt_finished())); d->jt->go(true); } void RegistrationDlg::setInstructions(const QString& jid, const QString& instructions) { QString str = tr("Registration for \"%1\":

").arg(jid); str += TextUtil::plain2rich(instructions); d->lb_top->setText(str); } /** * Returns true if the function was able to successfully process XData. */ bool RegistrationDlg::processXData(const QDomElement& iq) { if (!iq.isNull()) { XData form; form.fromXml(iq); if (!form.title().isEmpty()) setWindowTitle(form.title()); setInstructions(d->jid.full(), form.instructions()); if (d->xdata) delete d->xdata; d->xdata = new XDataWidget(d->gr_form); d->gr_form_layout->addWidget(d->xdata); // FIXME d->xdata->setFields(form.fields()); d->xdata->show(); return true; } return false; } /** * This is used as a fallback when processXData returns true. */ void RegistrationDlg::processLegacyForm(const XMPP::Form& form) { setInstructions(d->jid.full(), form.instructions()); for (Form::ConstIterator it = d->form.begin(); it != d->form.end(); ++it) { const FormField &f = *it; QLabel *lb = new QLabel(f.fieldName(), d->gr_form); QLineEdit *le = new QLineEdit(d->gr_form); d->gr_form_layout->addWidget(lb); // FIXME d->gr_form_layout->addWidget(le); // FIXME if (f.isSecret()) le->setEchoMode(QLineEdit::Password); le->setText(f.value()); d->lb_field.append(lb); d->le_field.append(le); } if (!d->le_field.isEmpty()) d->le_field.first()->setFocus(); } void RegistrationDlg::setData(JT_XRegister* jt) { d->form = jt->form(); if (!processXData(jt->xdataElement())) processLegacyForm(jt->form()); } void RegistrationDlg::updateData(JT_XRegister* jt) { if (d->xdata) { QDomElement iq = jt->xdataElement(); if (!iq.isNull()) { XData form; form.fromXml(iq); d->xdata->setFields(form.fields()); } } } void RegistrationDlg::jt_finished() { d->busy->stop(); d->gr_form->setEnabled(true); d->pb_reg->setEnabled(true); JT_XRegister *jt = d->jt; d->jt = 0; if(jt->success()) { if(d->type == 0) { setData(jt); d->gr_form->show(); d->pb_reg->show(); show(); qApp->processEvents(); resize(sizeHint()); } else { closeDialogs(this); QMessageBox::information(this, tr("Success"), tr("Registration successful.")); close(); } } else { if(d->type == 0) { QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve registration form.\nReason: %1").arg(jt->statusString())); close(); } else { QMessageBox::critical(this, tr("Error"), tr("Error submitting registration form.\nReason: %1").arg(jt->statusString())); if (jt->statusCode() == 406) { // updateData(jt); } else { closeDialogs(this); close(); } } } } #include "registrationdlg.moc" psi-0.14/src/httpauthmanager.h0000644000175000017500000000245611305557613014504 0ustar janjan/* * httpauthmanager.h - Classes managing incoming HTTP-Auth requests * Copyright (C) 2006 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef HTTPAUTHMANAGER_H #define HTTPAUTHMANAGER_H #include class HttpAuthListener; namespace XMPP { class Task; } class PsiHttpAuthRequest; class HttpAuthManager : public QObject { Q_OBJECT public: HttpAuthManager(XMPP::Task *); ~HttpAuthManager(); public slots: void confirm(const PsiHttpAuthRequest &req); void deny(const PsiHttpAuthRequest &req); signals: void confirmationRequest(const PsiHttpAuthRequest &); private: HttpAuthListener *listener_; }; #endif psi-0.14/src/psipopup.h0000644000175000017500000000325311305557613013163 0ustar janjan/* * psipopup.h - the Psi passive popup class * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIPOPUP_H #define PSIPOPUP_H #include class PsiCon; class PsiAccount; class UserListItem; class FancyPopup; class PsiIcon; class PsiEvent; namespace XMPP { class Jid; class Resource; } using namespace XMPP; class PsiPopup : public QObject { Q_OBJECT public: PsiPopup(const PsiIcon *titleIcon, QString titleText, PsiAccount *acc); ~PsiPopup(); enum PopupType { AlertNone = 0, AlertOnline, AlertOffline, AlertStatusChange, AlertMessage, AlertChat, AlertHeadline, AlertFile, AlertAvCall }; PsiPopup(PopupType type, PsiAccount *acc); void setData(const PsiIcon *icon, QString text); void setData(const Jid &, const Resource &, const UserListItem * = 0, const PsiEvent * = 0); void show(); QString id() const; FancyPopup *popup(); static void deleteAll(); public: class Private; private: Private *d; friend class Private; }; #endif psi-0.14/src/accountscombobox.h0000644000175000017500000000271411305557613014655 0ustar janjan/* * accountscombobox.h * Copyright (C) 2001-2008 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACCOUNTSCOMBOBOX_H #define ACCOUNTSCOMBOBOX_H #include class PsiCon; class PsiAccount; class AccountsComboBox : public QComboBox { Q_OBJECT public: AccountsComboBox(QWidget* parent); ~AccountsComboBox(); PsiAccount* account() const; void setAccount(PsiAccount* account); PsiCon* controller() const; void setController(PsiCon* controller); bool onlineOnly() const; void setOnlineOnly(bool onlineOnly); signals: void activated(PsiAccount* account); private slots: void changeAccount(); void updateAccounts(); private: PsiCon* controller_; PsiAccount* account_; bool onlineOnly_; QList accounts() const; }; #endif psi-0.14/src/voicecaller.h0000644000175000017500000000467411305557613013604 0ustar janjan/* * voicecaller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef VOICECALLER_H #define VOICECALLER_H #include class PsiAccount; namespace XMPP { class Jid; } using namespace XMPP; /** * \brief An abstract class for a voice call implementation. */ class VoiceCaller : public QObject { Q_OBJECT public: /** * \brief Base constructor. * * \param account the account to which this voice caller belongs */ VoiceCaller(PsiAccount* account) : account_(account) { }; /** * \brief Retrieves the account to which this voice caller belongs. */ PsiAccount* account() { return account_; } /** * \brief Initializes the voice caller. * This should be called when the connection is open. */ virtual void initialize() = 0; /** * \brief De-initializes the voice caller. * This should be called when the connection is about to be closed. */ virtual void deinitialize() = 0; /** * \brief Call the given JID. */ virtual void call(const Jid&) = 0; /** * \brief Accept a call from the given JID. */ virtual void accept(const Jid&) = 0; /** * \brief Reject the call from the given JID. */ virtual void reject(const Jid&) = 0; /** * \brief Terminate the call from the given JID. */ virtual void terminate(const Jid&) = 0; signals: /** * \brief Incoming call from the given JID. */ void incoming(const Jid&); /** * \brief Contact accepted an incoming call. */ void accepted(const Jid&); /** * \brief Contact rejected an incoming call. */ void rejected(const Jid&); /** * \brief Call with given JID is in progress. */ void in_progress(const Jid&); /** * \brief Call with given JID is terminated. */ void terminated(const Jid&); private: PsiAccount* account_; }; #endif psi-0.14/src/bookmarkmanage.ui0000644000175000017500000001045611305557613014453 0ustar janjan BookmarkManage 0 0 539 257 Manage Bookmarks QAbstractItemView::InternalMove QDialogButtonBox::NoButton Host: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Room: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Nickname: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Password: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QLineEdit::Password Auto-join Qt::Vertical 66 31 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok buttonBox accepted() BookmarkManage accept() 475 252 454 259 buttonBox rejected() BookmarkManage reject() 384 252 352 259 psi-0.14/src/serverinfomanager.cpp0000644000175000017500000000426411305557613015357 0ustar janjan/* * serverinfomanager.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "serverinfomanager.h" #include "xmpp_tasks.h" using namespace XMPP; ServerInfoManager::ServerInfoManager(Client* client) : client_(client) { deinitialize(); connect(client_, SIGNAL(rosterRequestFinished(bool, int, const QString &)), SLOT(initialize())); connect(client_, SIGNAL(disconnected()), SLOT(deinitialize())); } void ServerInfoManager::reset() { hasPEP_ = false; multicastService_ = QString(); } void ServerInfoManager::initialize() { JT_DiscoInfo *jt = new JT_DiscoInfo(client_->rootTask()); connect(jt, SIGNAL(finished()), SLOT(disco_finished())); jt->get(client_->jid().domain()); jt->go(true); } void ServerInfoManager::deinitialize() { reset(); emit featuresChanged(); } const QString& ServerInfoManager::multicastService() const { return multicastService_; } bool ServerInfoManager::hasPEP() const { return hasPEP_; } void ServerInfoManager::disco_finished() { JT_DiscoInfo *jt = (JT_DiscoInfo *)sender(); if (jt->success()) { // Features Features f = jt->item().features(); if (f.canMulticast()) multicastService_ = client_->jid().domain(); // TODO: Remove this, this is legacy if (f.test(QStringList("http://jabber.org/protocol/pubsub#pep"))) hasPEP_ = true; // Identities DiscoItem::Identities is = jt->item().identities(); foreach(DiscoItem::Identity i, is) { if (i.category == "pubsub" && i.type == "pep") hasPEP_ = true; } emit featuresChanged(); } } psi-0.14/src/ahcommanddlg.cpp0000644000175000017500000001141311305557613014252 0ustar janjan/* * ahcommanddlg.cpp - Ad-Hoc Command Dialog * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "ahcommanddlg.h" #include #include #include #include #include #include "ahcexecutetask.h" #include "busywidget.h" #include "psiaccount.h" #include "xmpp_xmlcommon.h" #include "xmpp_client.h" using namespace XMPP; #define AHC_NS "http://jabber.org/protocol/commands" // -------------------------------------------------------------------------- static bool operator<(const AHCommandItem &ci1, const AHCommandItem &ci2) { return ci1.name < ci2.name; } // -------------------------------------------------------------------------- // JT_AHCGetList: A Task to retreive the available commands of a client // -------------------------------------------------------------------------- class JT_AHCGetList : public Task { public: JT_AHCGetList(Task* t, const Jid& j); void onGo(); bool take(const QDomElement &x); const QList& commands() const { return commands_; } private: Jid receiver_; QList commands_; }; JT_AHCGetList::JT_AHCGetList(Task* t, const Jid& j) : Task(t), receiver_(j) { } void JT_AHCGetList::onGo() { QDomElement e = createIQ(doc(), "get", receiver_.full(), id()); QDomElement q = doc()->createElement("query"); q.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); q.setAttribute("node", AHC_NS); e.appendChild(q); send(e); } bool JT_AHCGetList::take(const QDomElement& e) { if(!iqVerify(e, receiver_, id())) { return false; } if (e.attribute("type") == "result") { // Extract commands commands_.clear(); bool found; QDomElement commands = findSubTag(e, "query", &found); if(found) { for(QDomNode n = commands.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { AHCommandItem ci; ci.node = i.attribute("node"); ci.name = i.attribute("name"); ci.jid = i.attribute("jid"); commands_ += ci; } } qSort(commands_); } setSuccess(); return true; } else { setError(e); return false; } } // -------------------------------------------------------------------------- // JT_AHCommandDlg: Initial command dialog // -------------------------------------------------------------------------- AHCommandDlg::AHCommandDlg(PsiAccount* pa, const Jid& receiver) : QDialog(0), pa_(pa), receiver_(receiver) { ui_.setupUi(this); setAttribute(Qt::WA_DeleteOnClose); pb_close = ui_.buttonBox->button(QDialogButtonBox::Cancel); pb_execute = ui_.buttonBox->addButton(tr("Execute"), QDialogButtonBox::AcceptRole); connect(pb_execute, SIGNAL(clicked()), SLOT(executeCommand())); connect(pb_close, SIGNAL(clicked()), SLOT(close())); pb_execute->setDefault(true); setWindowTitle(QString("Execute Command (%1)").arg(receiver.full())); refreshCommands(); adjustSize(); } void AHCommandDlg::refreshCommands() { ui_.cb_commands->clear(); pb_execute->setEnabled(false); ui_.busy->start(); JT_AHCGetList* t= new JT_AHCGetList(pa_->client()->rootTask(),receiver_); connect(t,SIGNAL(finished()),SLOT(listReceived())); t->go(true); } void AHCommandDlg::listReceived() { JT_AHCGetList* task_list = (JT_AHCGetList*) sender(); foreach(AHCommandItem i, task_list->commands()) { ui_.cb_commands->addItem(i.name); commands_.append(i); } pb_execute->setEnabled(ui_.cb_commands->count()>0); ui_.busy->stop(); } void AHCommandDlg::executeCommand() { if (ui_.cb_commands->count() > 0) { ui_.busy->start(); Jid to(commands_[ui_.cb_commands->currentIndex()].jid); QString node = commands_[ui_.cb_commands->currentIndex()].node; AHCExecuteTask* t = new AHCExecuteTask(to,AHCommand(node),pa_->client()->rootTask()); connect(t,SIGNAL(finished()),SLOT(commandExecuted())); t->go(true); } } void AHCommandDlg::commandExecuted() { ui_.busy->stop(); close(); } void AHCommandDlg::executeCommand(XMPP::Client* c, const XMPP::Jid& to, const QString &node) { AHCExecuteTask* t = new AHCExecuteTask(to,AHCommand(node),c->rootTask()); t->go(true); } psi-0.14/src/psiapplication.h0000644000175000017500000000277611305557613014334 0ustar janjan/* * psiapplication.h - subclass of QApplication to do some workarounds * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIAPPLICATION_H #define PSIAPPLICATION_H #include #ifdef Q_WS_MAC #include #endif class QEvent; class PsiApplication : public QApplication { Q_OBJECT public: PsiApplication(int &argc, char **argv, bool GUIenabled = true); ~PsiApplication(); bool notify(QObject *receiver, QEvent *event); #ifdef Q_WS_X11 bool x11EventFilter(XEvent *event); #endif #ifdef Q_WS_MAC bool macEventFilter(EventHandlerCallRef, EventRef); #endif // reimplemented void commitData(QSessionManager& manager); signals: void forceSavePreferences(); void dockActivated(); void newTrayOwner(); void trayOwnerDied(); private: void init(bool GUIenabled); }; #endif psi-0.14/src/mooddlg.cpp0000644000175000017500000000343711305557613013270 0ustar janjan/* * mooddlg.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_pubsubitem.h" #include "xmpp_client.h" #include "xmpp_task.h" #include "mooddlg.h" #include "moodcatalog.h" #include "psiaccount.h" #include "pepmanager.h" MoodDlg::MoodDlg(PsiAccount* pa) : QDialog(0), pa_(pa) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); setModal(false); connect(ui_.pb_cancel, SIGNAL(clicked()), SLOT(close())); connect(ui_.pb_ok, SIGNAL(clicked()), SLOT(setMood())); ui_.cb_type->addItem(tr("")); foreach(MoodCatalog::Entry e, MoodCatalog::instance()->entries()) { ui_.cb_type->addItem(e.text()); } } void MoodDlg::setMood() { QString moodstr = ui_.cb_type->currentText(); if (moodstr == tr("")) { pa_->pepManager()->retract("http://jabber.org/protocol/mood", "current"); } else { Mood::Type type = MoodCatalog::instance()->findEntryByText(moodstr).type(); pa_->pepManager()->publish("http://jabber.org/protocol/mood", PubSubItem("current",Mood(type,ui_.le_text->text()).toXml(*pa_->client()->rootTask()->doc())), PEPManager::PresenceAccess); } close(); } psi-0.14/src/desktoputil.cpp0000644000175000017500000000727111305557613014212 0ustar janjan/* * desktoputil.cpp - url-opening routines * Copyright (C) 2007 Maciej Niedzielski, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "desktoputil.h" #include #include #include #include #include #include #include #ifdef Q_WS_WIN #include QString defaultBrowser() { QSettings settings("HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command", QSettings::NativeFormat); QString command = settings.value(".").toString(); QRegExp rx("\"(.+)\""); if (rx.indexIn(command) != -1) return rx.capturedTexts()[1]; return command; } #endif static QSet handlers; static bool doOpenUrl(const QUrl& url) { #ifdef Q_WS_WIN if (!handlers.contains(url.scheme())) { // on Vista it always returns iexplore.exe as default browser bool oldStyleDefaultBrowserInfo = QSysInfo::WindowsVersion < QSysInfo::WV_VISTA; QFileInfo browserFileInfo(defaultBrowser()); if (oldStyleDefaultBrowserInfo && browserFileInfo.fileName() == "iexplore.exe") { return QProcess::startDetached(browserFileInfo.absoluteFilePath(), QStringList() << "-new" << url.toEncoded()); } else { // FIXME: This is necessary for Qt 4.3.3 to handle all URLs correctly QT_WA( ShellExecuteW(0, 0, (WCHAR *)QString(url.toEncoded()).utf16(), 0, 0, SW_SHOWNORMAL); , QByteArray a = QString(url.toEncoded()).toLocal8Bit(); // must not call constData() of a temp object ShellExecuteA(0, 0, (CHAR *)a.constData(), 0, 0, SW_SHOWNORMAL); ) return true; } } #endif return QDesktopServices::openUrl(url); } /** * \brief Opens URL using OS default handler * \param url the url to open * * \a url may be either percent encoded or not. * If it contains only ASCII characters, it is decoded, * else it is converted to QUrl in QUrl::TolerantMode mode. * Resulting QUrl object is passed to QDesktopServices::openUrl(). * * \sa QDesktopServices::openUrl() */ bool DesktopUtil::openUrl(const QString& url) { QByteArray ascii = url.toAscii(); if (ascii == url) return doOpenUrl(QUrl::fromEncoded(ascii)); else return doOpenUrl(QUrl(url, QUrl::TolerantMode)); } /** * \brief Sets the handler for the given \a scheme to be the \a handler method provided by the \a receiver object. * * Handler is set in QDesktopServices and DesktopUtil will always use QDesktopServices to open URLs of this type. * * Note: Always manage handlers via DesktopUtil. Using QDestopServices directly may lead to unexpected behavior. */ void DesktopUtil::setUrlHandler(const QString& scheme, QObject* receiver, const char* method) { QDesktopServices::setUrlHandler(scheme, receiver, method); handlers.insert(scheme); } /** * Removes a previously set URL handler for the specified \a scheme. * * Handler is unset in QDesktopServices. * * Note: Always manage handlers via DesktopUtil. Using QDestopServices directly may lead to unexpected behavior. */ void DesktopUtil::unsetUrlHandler(const QString& scheme) { handlers.remove(scheme); QDesktopServices::unsetUrlHandler(scheme); } psi-0.14/src/adduserdlg.cpp0000644000175000017500000002116511305557613013757 0ustar janjan/* * adduserdlg.cpp - dialog for adding contacts * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "adduserdlg.h" #include #include #include #include #include #include #include #include #include "xmpp_tasks.h" #include "psiaccount.h" #include "psiiconset.h" #include "contactview.h" #include "busywidget.h" #include "common.h" #include "iconwidget.h" #include "tasklist.h" #include "xmpp_vcard.h" #include "vcardfactory.h" #include "infodlg.h" class AddUserDlg::Private { public: Private() {} PsiAccount *pa; BusyWidget *busy; QStringList services; JT_Gateway *jt; TaskList *tasks; }; AddUserDlg::AddUserDlg(const QStringList &services, const QStringList &names, const QStringList &groups, PsiAccount *pa) : QDialog(0) { init(groups, pa); d->services = services; QStringList::ConstIterator it1 = services.begin(); QStringList::ConstIterator it2 = names.begin(); for(; it1 != services.end(); ++it1, ++it2) cb_service->addItem(PsiIconset::instance()->status(*it1, STATUS_ONLINE).icon(), *it2); connect(cb_service, SIGNAL(activated(int)), SLOT(serviceActivated(int))); connect(le_transPrompt, SIGNAL(textChanged(const QString &)), SLOT(le_transPromptChanged(const QString &))); pb_transGet->setEnabled(false); } AddUserDlg::AddUserDlg(const XMPP::Jid &jid, const QString &nick, const QString &group, const QStringList &groups, PsiAccount *pa) { init(groups, pa); le_jid->setText(jid.full()); // TODO: do we want to encourage adding jids with resource? le_nick->setText(nick); QStringList suggestedGroups = groups.filter(group, Qt::CaseInsensitive); if (suggestedGroups.size() > 0) { cb_group->lineEdit()->setText(suggestedGroups[0]); } else { cb_group->lineEdit()->setText(group); } QSize s(te_info->width(), w_serviceTranslation->sizeHint().height()); w_serviceTranslation->hide(); w_serviceTranslation->setEnabled(false); te_info->hide(); resize(size() - s); } void AddUserDlg::init(const QStringList &groups, PsiAccount *pa) { setupUi(this); setModal(false); d = new Private; d->pa = pa; d->pa->dialogRegister(this); d->jt = 0; d->tasks = new TaskList; connect(d->tasks, SIGNAL(started()), busy, SLOT(start())); connect(d->tasks, SIGNAL(finished()), busy, SLOT(stop())); setWindowTitle(CAP(windowTitle())); setWindowIcon(IconsetFactory::icon("psi/addContact").icon()); d->busy = busy; QString str = tr(""); cb_group->addItem(str); QStringList temp=groups; temp.sort(); cb_group->addItems(temp); str = ContactView::tr("Hidden"); if (!groups.contains(str)) { cb_group->addItem(str); } cb_group->setAutoCompletion(true); pb_add->setDefault(true); connect(pb_add, SIGNAL(clicked()), SLOT(ok())); connect(pb_close, SIGNAL(clicked()), SLOT(cancel())); connect(pb_transGet, SIGNAL(clicked()), SLOT(getTransID())); connect(tb_vCard, SIGNAL(clicked()), SLOT(getVCardActivated())); connect(tb_resolveNick, SIGNAL(clicked()), SLOT(resolveNickActivated())); connect(le_jid, SIGNAL(textChanged(QString)), SLOT(jid_Changed())); ck_authreq->setChecked(true); ck_close->setChecked(true); le_jid->setFocus(); } AddUserDlg::~AddUserDlg() { delete d->tasks; d->pa->dialogUnregister(this); delete d; } Jid AddUserDlg::jid() const { return Jid(le_jid->text().trimmed()); } void AddUserDlg::cancel() { le_jid->setText(""); le_nick->setText(""); cb_group->setCurrentIndex(0); reject(); } void AddUserDlg::ok() { if (!d->pa->checkConnected()) { return; } if(le_jid->text().isEmpty()) { QMessageBox::information(this, tr("Add User: Error"), tr("Please fill in the Jabber ID of the person you wish to add.")); return; } if(!jid().isValid()) { QMessageBox::information(this, tr("Add User: Error"), tr("The Jabber ID you entered is not valid!\nMake sure you enter a fully qualified Jabber ID.")); return; } QString gname = cb_group->currentText(); QStringList list; if(gname != tr("")) { list += gname; } add(jid(), le_nick->text(), list, ck_authreq->isChecked()); QMessageBox::information(this, tr("Add User: Success"), tr("Added %1 to your roster.").arg(jid().full())); le_jid->setText(""); le_nick->setText(""); if(ck_close->isChecked()) { cb_group->setCurrentIndex(0); accept(); } else { le_jid->setFocus(); } } void AddUserDlg::serviceActivated(int x) { if(d->jt) { delete d->jt; d->jt = 0; d->busy->stop(); } gb_trans->setEnabled(false); le_transPrompt->setText(""); // Jabber entry if(x == 0) return; --x; if(x >= 0 && x < (int)d->services.count()) { d->jt = new JT_Gateway(d->pa->client()->rootTask()); connect(d->jt, SIGNAL(finished()), SLOT(jt_getFinished())); d->jt->get(Jid(d->services[x])); d->jt->go(true); d->tasks->append( d->jt ); } } void AddUserDlg::le_transPromptChanged(const QString &str) { pb_transGet->setEnabled(!str.isEmpty()); } void AddUserDlg::getTransID() { cb_service->setEnabled(false); le_transPrompt->setEnabled(false); pb_transGet->setEnabled(false); d->jt = new JT_Gateway(d->pa->client()->rootTask()); connect(d->jt, SIGNAL(finished()), SLOT(jt_setFinished())); d->jt->set(Jid(d->services[cb_service->currentIndex()-1]), le_transPrompt->text()); d->jt->go(true); d->tasks->append( d->jt ); } void AddUserDlg::jt_getFinished() { JT_Gateway *jt = d->jt; d->jt = 0; if(jt->success()) { gb_trans->setEnabled(true); lb_transDesc->setText(jt->desc()); } else { errorGateway(cb_service->currentText(), jt->statusString()); } } void AddUserDlg::jt_setFinished() { cb_service->setEnabled(true); le_transPrompt->setEnabled(true); pb_transGet->setEnabled(true); JT_Gateway *jt = d->jt; d->jt = 0; if(jt->success()) { QString jid = jt->translatedJid().full(); if (jid.isEmpty()) { jid = jt->prompt(); // we used to read only prompt() in the past, // and many gateways still send it } le_jid->setText(jid); le_nick->setText(le_transPrompt->text()); le_transPrompt->setText(""); le_jid->setCursorPosition(0); le_nick->setCursorPosition(0); le_nick->setFocus(); le_nick->selectAll(); } else { errorGateway(cb_service->currentText(), jt->statusString()); le_transPrompt->setFocus(); } } void AddUserDlg::errorGateway(const QString &str, const QString &err) { QMessageBox::information(this, CAP(tr("Error")), tr("\n" "There was an error getting the Service ID translation information from \"%1\".
" "Reason: %2
" "
" "The service may not support this feature. In this case you " "will need to enter the Jabber ID manually for the contact you wish " "to add. Examples:
" "
" "  jabberuser@somehost.com
" "  aoluser@[Jabber ID of AIM Transport]
" "  1234567@[Jabber ID of ICQ Transport]
" "  joe%hotmail.com@[Jabber ID of MSN Transport]
" "  yahooUser@[Jabber ID of Yahoo Transport]
" "
" ).arg(str).arg(QString(err).replace('\n', "
"))); } void AddUserDlg::getVCardActivated() { const VCard *vcard = VCardFactory::instance()->vcard(jid()); VCard tmp; if ( vcard ) tmp = *vcard; InfoDlg *w = new InfoDlg(InfoDlg::Contact, jid(), tmp, d->pa, 0, false); w->show(); // automatically retrieve info if it doesn't exist if(!vcard) w->doRefresh(); } void AddUserDlg::resolveNickActivated() { JT_VCard *jt = VCardFactory::instance()->getVCard(jid(), d->pa->client()->rootTask(), this, SLOT(resolveNickFinished()), false); d->tasks->append( jt ); } void AddUserDlg::resolveNickFinished() { JT_VCard *jt = (JT_VCard *)sender(); if(jt->success()) { if ( !jt->vcard().nickName().isEmpty() ) le_nick->setText( jt->vcard().nickName() ); else if( !jt->vcard().fullName().isEmpty() ) le_nick->setText( jt->vcard().fullName() ); } } /** * Called when the Jid changes to enable the vcard and nick resolution buttons. */ void AddUserDlg::jid_Changed() { bool enableVCardButtons = jid().isValid(); tb_vCard->setEnabled(enableVCardButtons); tb_resolveNick->setEnabled(enableVCardButtons); } psi-0.14/src/pgptransaction.cpp0000644000175000017500000000340211305557613014667 0ustar janjan/* * pgptransaction.cpp * Copyright (C) 2001-2005 Justin Karneges * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "pgptransaction.h" using namespace XMPP; PGPTransaction::PGPTransaction(QCA::SecureMessageSystem* system) : QCA::SecureMessage(system), system_(system) { id_ = idCounter_++; } PGPTransaction::~PGPTransaction() { delete system_; } int PGPTransaction::id() const { return id_; } void PGPTransaction::setMessage(const XMPP::Message &m) { message_ = m; } const XMPP::Message & PGPTransaction::message() const { return message_; } const QDomElement & PGPTransaction::xml() const { return xml_; } void PGPTransaction::setXml(const QDomElement &xml) { xml_ = xml; } Jid PGPTransaction::jid() const { return jid_; } void PGPTransaction::setJid(const Jid &j) { jid_ = j; } int PGPTransaction::idCounter_ = 0; psi-0.14/src/pgpkeydlg.h0000644000175000017500000000335311305557613013273 0ustar janjan/* * pgpkeydlg.h * Copyright (C) 2001-2009 Justin Karneges, Michail Pishchagin * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PGPKEYDLG_H #define PGPKEYDLG_H #include #include "ui_pgpkey.h" class QStandardItemModel; class QSortFilterProxyModel; class PGPKeyDlg : public QDialog { Q_OBJECT public: enum Type { Public, Secret }; PGPKeyDlg(Type, const QString& defaultKeyID, QWidget *parent = 0); const QCA::KeyStoreEntry& keyStoreEntry() const; private slots: void doubleClicked(const QModelIndex& index); void filterTextChanged(); void do_accept(); void show_ksm_dtext(); protected: // reimplemented bool eventFilter(QObject* watched, QEvent* event); private: Ui::PGPKey ui_; QCA::KeyStoreEntry entry_; QPushButton* pb_dtext_; QStandardItemModel* model_; QSortFilterProxyModel* proxy_; }; #endif psi-0.14/src/pgputil.cpp0000644000175000017500000001727311305557613013332 0ustar janjan#include "pgputil.h" #include #include #include #include #include "passphrasedlg.h" #include "showtextdlg.h" PGPUtil* PGPUtil::instance_ = 0; PGPUtil::PGPUtil() : qcaEventHandler_(NULL), passphraseDlg_(NULL), cache_no_pgp_(false) { qcaEventHandler_ = new QCA::EventHandler(this); connect(qcaEventHandler_,SIGNAL(eventReady(int,const QCA::Event&)),SLOT(handleEvent(int,const QCA::Event&))); qcaEventHandler_->start(); qcaKeyStoreManager_.waitForBusyFinished(); // FIXME get rid of this connect(&qcaKeyStoreManager_, SIGNAL(keyStoreAvailable(const QString&)), SLOT(keyStoreAvailable(const QString&))); foreach(QString k, qcaKeyStoreManager_.keyStores()) { QCA::KeyStore* ks = new QCA::KeyStore(k, &qcaKeyStoreManager_); connect(ks, SIGNAL(updated()), SIGNAL(pgpKeysUpdated())); keystores_ += ks; } connect(QCoreApplication::instance(),SIGNAL(aboutToQuit()),SLOT(deleteLater())); } PGPUtil::~PGPUtil() { foreach(QCA::KeyStore* ks,keystores_) { delete ks; } keystores_.clear(); } PGPUtil& PGPUtil::instance() { if (!instance_) { instance_ = new PGPUtil(); } return *instance_; } void PGPUtil::handleEvent(int id, const QCA::Event& event) { if (event.type() == QCA::Event::Password) { QCA::KeyStoreEntry entry = event.keyStoreEntry(); if(!entry.isNull() && passphrases_.contains(entry.id())) { qcaEventHandler_->submitPassword(id, QCA::SecureArray(passphrases_[entry.id()].toUtf8())); } else if (passphraseDlg_) { EventItem i; i.id = id; i.event = event; pendingEvents_.push_back(i); } else { promptPassphrase(id,event); } } } void PGPUtil::promptPassphrase(int id, const QCA::Event& event) { QString name; currentEventId_ = id; QCA::KeyStoreEntry entry = event.keyStoreEntry(); if(!entry.isNull()) { name = entry.name(); currentEntryId_ = entry.id(); } else { name = event.keyStoreInfo().name(); currentEntryId_ = QString(); } if (!passphraseDlg_) { passphraseDlg_ = new PassphraseDlg(); connect(passphraseDlg_,SIGNAL(finished(int)),SLOT(passphraseDone(int))); } passphraseDlg_->promptPassphrase(name); passphraseDlg_->show(); } void PGPUtil::passphraseDone(int result) { // Process the result if (result == QDialog::Accepted) { QString passphrase = passphraseDlg_->getPassphrase(); if (!currentEntryId_.isEmpty()) { passphrases_[currentEntryId_] = passphrase; } qcaEventHandler_->submitPassword(currentEventId_,passphrase.toUtf8()); } else if (result == QDialog::Rejected) { qcaEventHandler_->reject(currentEventId_); } else { qWarning() << "PGPUtil: Unexpected passphrase dialog result"; } // Process the queue if (!pendingEvents_.isEmpty()) { EventItem eventItem; bool handlePendingEvent = false; while (!pendingEvents_.isEmpty() && !handlePendingEvent) { eventItem = pendingEvents_.takeFirst(); QCA::KeyStoreEntry entry = eventItem.event.keyStoreEntry(); if(!entry.isNull() && passphrases_.contains(entry.id())) { qcaEventHandler_->submitPassword(eventItem.id, QCA::SecureArray(passphrases_[entry.id()].toUtf8())); } else { handlePendingEvent = true; } } if (handlePendingEvent) { promptPassphrase(eventItem.id,eventItem.event); return; } } passphraseDlg_->deleteLater(); passphraseDlg_ = NULL; } bool PGPUtil::pgpAvailable() { bool have_openpgp = false; if(!cache_no_pgp_) { have_openpgp = QCA::isSupported("openpgp"); if(!have_openpgp) cache_no_pgp_ = true; } return (have_openpgp && keystores_.count() > 0); } void PGPUtil::clearPGPAvailableCache() { cache_no_pgp_ = false; } QString PGPUtil::stripHeaderFooter(const QString &str) { QString s; if (str.isEmpty()) { qWarning("pgputil.cpp: Empty PGP message"); return ""; } if(str.at(0) != '-') return str; QStringList lines = str.split('\n'); QStringList::ConstIterator it = lines.begin(); // skip the first line ++it; if(it == lines.end()) return str; // skip the header for(; it != lines.end(); ++it) { if((*it).isEmpty()) break; } if(it == lines.end()) return str; ++it; if(it == lines.end()) return str; bool first = true; for(; it != lines.end(); ++it) { if((*it).at(0) == '-') break; if(!first) s += '\n'; s += (*it); first = false; } return s; } QString PGPUtil::addHeaderFooter(const QString &str, int type) { QString stype; if(type == 0) stype = "MESSAGE"; else stype = "SIGNATURE"; QString s; s += QString("-----BEGIN PGP %1-----\n").arg(stype); s += "Version: PGP\n"; s += '\n'; s += str + '\n'; s += QString("-----END PGP %1-----\n").arg(stype); return s; } QCA::KeyStoreEntry PGPUtil::getSecretKeyStoreEntry(const QString& keyID) { foreach(QCA::KeyStore *ks, keystores_) { if (ks->type() == QCA::KeyStore::PGPKeyring && ks->holdsIdentities()) { foreach(QCA::KeyStoreEntry ke, ks->entryList()) { if (ke.type() == QCA::KeyStoreEntry::TypePGPSecretKey && ke.pgpSecretKey().keyId() == keyID) { return ke; } } } } return QCA::KeyStoreEntry(); } QCA::KeyStoreEntry PGPUtil::getPublicKeyStoreEntry(const QString& keyID) { foreach(QCA::KeyStore *ks, keystores_) { if (ks->type() == QCA::KeyStore::PGPKeyring && ks->holdsIdentities()) { foreach(QCA::KeyStoreEntry ke, ks->entryList()) { if ((ke.type() == QCA::KeyStoreEntry::TypePGPSecretKey || ke.type() == QCA::KeyStoreEntry::TypePGPPublicKey) && ke.pgpPublicKey().keyId() == keyID) { return ke; } } } } return QCA::KeyStoreEntry(); } QString PGPUtil::messageErrorString(enum QCA::SecureMessage::Error e) { QString msg; switch(e) { case QCA::SecureMessage::ErrorPassphrase: msg = QObject::tr("Invalid passphrase"); break; case QCA::SecureMessage::ErrorFormat: msg = QObject::tr("Invalid input format"); break; case QCA::SecureMessage::ErrorSignerExpired: msg = QObject::tr("Signing key expired"); break; case QCA::SecureMessage::ErrorSignerInvalid: msg = QObject::tr("Invalid key"); break; case QCA::SecureMessage::ErrorEncryptExpired: msg = QObject::tr("Encrypting key expired"); break; case QCA::SecureMessage::ErrorEncryptUntrusted: msg = QObject::tr("Encrypting key is untrusted"); break; case QCA::SecureMessage::ErrorEncryptInvalid: msg = QObject::tr("Encrypting key is invalid"); break; case QCA::SecureMessage::ErrorNeedCard: msg = QObject::tr("PGP card is missing"); break; default: msg = QObject::tr("Unknown error"); } return msg; } bool PGPUtil::equals(QCA::PGPKey k1, QCA::PGPKey k2) { if (k1.isNull()) { return k2.isNull(); } else if (k2.isNull()) { return false; } else { return k1.keyId() == k2.keyId(); } } void PGPUtil::removePassphrase(const QString& id) { passphrases_.remove(id); } void PGPUtil::keyStoreAvailable(const QString& k) { QCA::KeyStore* ks = new QCA::KeyStore(k, &qcaKeyStoreManager_); connect(ks, SIGNAL(updated()), SIGNAL(pgpKeysUpdated())); keystores_ += ks; } void PGPUtil::showDiagnosticText(const QString& event, const QString& diagnostic) { while (1) { QMessageBox msgbox(QMessageBox::Critical, tr("Error"), event, QMessageBox::Ok, 0); QPushButton *diag = msgbox.addButton(tr("Diagnostics"), QMessageBox::HelpRole); msgbox.exec(); if (msgbox.clickedButton() == diag) { ShowTextDlg* w = new ShowTextDlg(diagnostic, true, false, 0); w->setWindowTitle(tr("OpenPGP Diagnostic Text")); w->resize(560, 240); w->exec(); continue; } else { break; } } } void PGPUtil::showDiagnosticText(QCA::SecureMessage::Error error, const QString& diagnostic) { showDiagnosticText(tr("There was an error trying to send the message encrypted.\nReason: %1.") .arg(PGPUtil::instance().messageErrorString(error)), diagnostic); } psi-0.14/src/pongserver.cpp0000644000175000017500000000255011305557613014030 0ustar janjan/* * pongserver.cpp - XMPP Ping server * Copyright (C) 2007 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "pongserver.h" #include "xmpp_xmlcommon.h" using namespace XMPP; /** * \class PongServer * \brief Answers XMPP Pings */ PongServer::PongServer(Task* parent) : Task(parent) {} bool PongServer::take(const QDomElement& e) { if (e.tagName() != "iq" || e.attribute("type") != "get") return false; bool found = false; QDomElement ping = findSubTag(e, "ping", &found); if (found && ping.attribute("xmlns") == "urn:xmpp:ping") { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); send(iq); return true; } return false; } psi-0.14/src/ahcformdlg.ui0000644000175000017500000000312411305557613013575 0ustar janjan AHCFormDlg 0 0 327 241 Form true 0 0 Qt::ScrollBarAlwaysOff QDialogButtonBox::NoButton BusyWidget QWidget
busywidget.h
1
psi-0.14/src/serverlistquerier.h0000644000175000017500000000224111305557613015077 0ustar janjan/* * serverlistquerier.h * Copyright (C) 2007 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SERVERLISTQUERIER #define SERVERLISTQUERIER #include class QHttp; class ServerListQuerier : public QObject { Q_OBJECT public: ServerListQuerier(QObject* parent = NULL); void getList(); signals: void listReceived(const QStringList&); void error(const QString&); protected slots: void get_finished(int,bool); private: QHttp* http_; int redirectCount_; }; #endif psi-0.14/src/gcuserview.h0000644000175000017500000000526711305557613013476 0ustar janjan/* * gcuserview.h - groupchat roster * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GCUSERVIEW_H #define GCUSERVIEW_H #include #include "xmpp_status.h" using namespace XMPP; class QPainter; class GCMainDlg; class GCUserView; class GCUserViewGroupItem; namespace XMPP { class Jid; } class GCUserViewItem : public QObject, public Q3ListViewItem { public: GCUserViewItem(GCUserViewGroupItem *); void paintFocus(QPainter *, const QColorGroup &, const QRect &); void paintBranches(QPainter *p, const QColorGroup &cg, int w, int, int h); Status s; }; class GCUserViewGroupItem : public Q3ListViewItem { public: GCUserViewGroupItem(GCUserView *, const QString&, int); void paintFocus(QPainter *, const QColorGroup &, const QRect &); void paintBranches(QPainter *p, const QColorGroup &cg, int w, int, int h); void paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int alignment); int compare(Q3ListViewItem *i, int col, bool ascending ) const; void updateText(); private: int key_; QString baseText; }; class GCUserView : public Q3ListView { Q_OBJECT public: GCUserView(QWidget* parent); ~GCUserView(); void setMainDlg(GCMainDlg* mainDlg); Q3DragObject* dragObject(); void clear(); void updateAll(); bool hasJid(const Jid&); Q3ListViewItem *findEntry(const QString &); void updateEntry(const QString &, const Status &); void removeEntry(const QString &); QStringList nickList() const; protected: enum Role { Moderator = 0, Participant = 1, Visitor = 2 }; GCUserViewGroupItem* findGroup(XMPP::MUCItem::Role a) const; bool maybeTip(const QPoint &); bool event(QEvent* e); signals: void action(const QString &nick, const Status &, int actionType); void insertNick(const QString& nick); private slots: void qlv_doubleClicked(Q3ListViewItem *); void qlv_contextMenuRequested(Q3ListViewItem *, const QPoint &, int); void qlv_mouseButtonClicked(int button, Q3ListViewItem* item, const QPoint& pos, int c); private: GCMainDlg* gcDlg_; }; #endif psi-0.14/src/voicecall.ui0000644000175000017500000000423111305557613013430 0ustar janjan VoiceCall 0 0 290 79 Voice Call Qt::AlignCenter 0 Accept Reject 90 32 Expanding Horizontal Hang Up qPixmapFromMimeSource psi-0.14/src/avcall/0000755000175000017500000000000011305557613012372 5ustar janjanpsi-0.14/src/avcall/jinglertptasks.cpp0000644000175000017500000003236011305557613016146 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #include "jinglertptasks.h" #include "xmpp_xmlcommon.h" static QDomElement candidateToElement(QDomDocument *doc, const XMPP::Ice176::Candidate &c) { QDomElement e = doc->createElement("candidate"); e.setAttribute("component", QString::number(c.component)); e.setAttribute("foundation", c.foundation); e.setAttribute("generation", QString::number(c.generation)); if(!c.id.isEmpty()) e.setAttribute("id", c.id); e.setAttribute("ip", c.ip.toString()); if(c.network != -1) e.setAttribute("network", QString::number(c.network)); else // weird? e.setAttribute("network", QString::number(0)); e.setAttribute("port", QString::number(c.port)); e.setAttribute("priority", QString::number(c.priority)); e.setAttribute("protocol", c.protocol); if(!c.rel_addr.isNull()) e.setAttribute("rel-addr", c.rel_addr.toString()); if(c.rel_port != -1) e.setAttribute("rel-port", QString::number(c.rel_port)); // TODO: remove this? //if(!c.rem_addr.isNull()) // e.setAttribute("rem-addr", c.rem_addr.toString()); //if(c.rem_port != -1) // e.setAttribute("rem-port", QString::number(c.rem_port)); e.setAttribute("type", c.type); return e; } static XMPP::Ice176::Candidate elementToCandidate(const QDomElement &e) { if(e.tagName() != "candidate") return XMPP::Ice176::Candidate(); XMPP::Ice176::Candidate c; c.component = e.attribute("component").toInt(); c.foundation = e.attribute("foundation"); c.generation = e.attribute("generation").toInt(); c.id = e.attribute("id"); c.ip = QHostAddress(e.attribute("ip")); c.network = e.attribute("network").toInt(); c.port = e.attribute("port").toInt(); c.priority = e.attribute("priority").toInt(); c.protocol = e.attribute("protocol"); c.rel_addr = QHostAddress(e.attribute("rel-addr")); c.rel_port = e.attribute("rel-port").toInt(); // TODO: remove this? //c.rem_addr = QHostAddress(e.attribute("rem-addr")); //c.rem_port = e.attribute("rem-port").toInt(); c.type = e.attribute("type"); return c; } static QDomElement payloadTypeToElement(QDomDocument *doc, const JingleRtpPayloadType &type) { QDomElement e = doc->createElement("payload-type"); e.setAttribute("id", QString::number(type.id)); if(!type.name.isEmpty()) e.setAttribute("name", type.name); e.setAttribute("clockrate", QString::number(type.clockrate)); if(type.channels > 1) e.setAttribute("channels", QString::number(type.channels)); if(type.ptime != -1) e.setAttribute("ptime", QString::number(type.ptime)); if(type.maxptime != -1) e.setAttribute("maxptime", QString::number(type.maxptime)); foreach(const JingleRtpPayloadType::Parameter &p, type.parameters) { QDomElement pe = doc->createElement("parameter"); pe.setAttribute("name", p.name); pe.setAttribute("value", p.value); e.appendChild(pe); } return e; } static JingleRtpPayloadType elementToPayloadType(const QDomElement &e) { if(e.tagName() != "payload-type") return JingleRtpPayloadType(); JingleRtpPayloadType out; bool ok; int x; x = e.attribute("id").toInt(&ok); if(!ok) return JingleRtpPayloadType(); out.id = x; out.name = e.attribute("name"); x = e.attribute("clockrate").toInt(&ok); if(!ok) return JingleRtpPayloadType(); out.clockrate = x; x = e.attribute("channels").toInt(&ok); if(ok) out.channels = x; x = e.attribute("ptime").toInt(&ok); if(ok) out.ptime = x; x = e.attribute("maxptime").toInt(&ok); if(ok) out.maxptime = x; QList plist; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; QDomElement pe = n.toElement(); if(pe.tagName() == "parameter") { JingleRtpPayloadType::Parameter p; p.name = pe.attribute("name"); p.value = pe.attribute("value"); plist += p; } } out.parameters = plist; return out; } struct JingleCondEntry { const char *str; int cond; }; static JingleCondEntry jingleCondTable[] = { { "alternative-session", JingleRtpReason::AlternativeSession }, { "busy", JingleRtpReason::Busy }, { "cancel", JingleRtpReason::Cancel }, { "connectivity-error", JingleRtpReason::ConnectivityError }, { "decline", JingleRtpReason::Decline }, { "expired", JingleRtpReason::Expired }, { "failed-application", JingleRtpReason::FailedApplication }, { "failed-transport", JingleRtpReason::FailedTransport }, { "general-error", JingleRtpReason::GeneralError }, { "gone", JingleRtpReason::Gone }, { "incompatible-parameters", JingleRtpReason::IncompatibleParameters }, { "media-error", JingleRtpReason::MediaError }, { "security-error", JingleRtpReason::SecurityError }, { "success", JingleRtpReason::Success }, { "timeout", JingleRtpReason::Timeout }, { "unsupported-applications", JingleRtpReason::UnsupportedApplications }, { "unsupported-transports", JingleRtpReason::UnsupportedTransports }, { 0, 0 } }; static QString conditionToElementName(JingleRtpReason::Condition cond) { for(int n = 0; jingleCondTable[n].str; ++n) { if(jingleCondTable[n].cond == cond) return QString::fromLatin1(jingleCondTable[n].str); } return QString(); } static int elementNameToCondition(const QString &in) { for(int n = 0; jingleCondTable[n].str; ++n) { if(QLatin1String(jingleCondTable[n].str) == in) return jingleCondTable[n].cond; } return -1; } static QDomElement reasonToElement(QDomDocument *doc, const JingleRtpReason &reason) { QDomElement e = doc->createElement("reason"); e.appendChild(doc->createElement(conditionToElementName(reason.condition))); if(!reason.text.isEmpty()) { QDomElement text = doc->createElement("text"); text.appendChild(doc->createTextNode(reason.text)); e.appendChild(text); } return e; } static QDomElement firstChildElement(const QDomElement &in) { for(QDomNode n = in.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; return n.toElement(); } return QDomElement(); } static JingleRtpReason elementToReason(const QDomElement &e) { if(e.tagName() != "reason") return JingleRtpReason(); QDomElement condElement = firstChildElement(e); if(condElement.isNull()) return JingleRtpReason(); int x = elementNameToCondition(condElement.tagName()); if(x == -1) return JingleRtpReason(); JingleRtpReason out; out.condition = (JingleRtpReason::Condition)x; bool found; QDomElement text = findSubTag(e, "text", &found); if(found) out.text = tagContent(text); return out; } //---------------------------------------------------------------------------- // JT_JingleRtp //---------------------------------------------------------------------------- JT_JingleRtp::JT_JingleRtp(XMPP::Task *parent) : XMPP::Task(parent) { } JT_JingleRtp::~JT_JingleRtp() { } void JT_JingleRtp::request(const XMPP::Jid &to, const JingleRtpEnvelope &envelope) { to_ = to; iq_ = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("jingle"); query.setAttribute("xmlns", "urn:xmpp:jingle:1"); query.setAttribute("action", envelope.action); if(!envelope.initiator.isEmpty()) query.setAttribute("initiator", envelope.initiator); if(!envelope.responder.isEmpty()) query.setAttribute("responder", envelope.responder); query.setAttribute("sid", envelope.sid); if(envelope.action == "session-terminate") { // for session terminate, there is no content list, just // a reason for termination query.appendChild(reasonToElement(doc(), envelope.reason)); } else { foreach(const JingleRtpContent &c, envelope.contentList) { QDomElement content = doc()->createElement("content"); content.setAttribute("creator", c.creator); if(!c.disposition.isEmpty()) content.setAttribute("disposition", c.disposition); content.setAttribute("name", c.name); if(!c.senders.isEmpty()) content.setAttribute("senders", c.senders); if(!c.desc.media.isEmpty()) { // TODO: ssrc, bitrate, crypto QDomElement description = doc()->createElement("description"); description.setAttribute("xmlns", "urn:xmpp:jingle:apps:rtp:1"); description.setAttribute("media", c.desc.media); foreach(const JingleRtpPayloadType &pt, c.desc.payloadTypes) { QDomElement p = payloadTypeToElement(doc(), pt); if(!p.isNull()) description.appendChild(p); } content.appendChild(description); } if(!c.trans.user.isEmpty()) { QDomElement transport = doc()->createElement("transport"); transport.setAttribute("xmlns", "urn:xmpp:jingle:transports:ice-udp:1"); transport.setAttribute("ufrag", c.trans.user); transport.setAttribute("pwd", c.trans.pass); foreach(const XMPP::Ice176::Candidate &ic, c.trans.candidates) { QDomElement e = candidateToElement(doc(), ic); if(!e.isNull()) transport.appendChild(e); } content.appendChild(transport); } query.appendChild(content); } } iq_.appendChild(query); } void JT_JingleRtp::onGo() { send(iq_); } bool JT_JingleRtp::take(const QDomElement &x) { if(!iqVerify(x, to_, id())) return false; if(x.attribute("type") == "result") setSuccess(); else setError(x); return true; } //---------------------------------------------------------------------------- // JT_PushJingleRtp //---------------------------------------------------------------------------- JT_PushJingleRtp::JT_PushJingleRtp(XMPP::Task *parent) : XMPP::Task(parent) { } JT_PushJingleRtp::~JT_PushJingleRtp() { } void JT_PushJingleRtp::respondSuccess(const XMPP::Jid &to, const QString &id) { QDomElement iq = createIQ(doc(), "result", to.full(), id); send(iq); } void JT_PushJingleRtp::respondError(const XMPP::Jid &to, const QString &id, int code, const QString &str) { QDomElement iq = createIQ(doc(), "error", to.full(), id); QDomElement err = textTag(doc(), "error", str); err.setAttribute("code", QString::number(code)); iq.appendChild(err); send(iq); } bool JT_PushJingleRtp::take(const QDomElement &e) { // must be an iq-set tag if(e.tagName() != "iq") return false; if(e.attribute("type") != "set") return false; QDomElement je; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; QDomElement e = n.toElement(); if(e.tagName() == "jingle" && e.attribute("xmlns") == "urn:xmpp:jingle:1") { je = e; break; } } if(je.isNull()) return false; XMPP::Jid from = e.attribute("from"); QString iq_id = e.attribute("id"); JingleRtpEnvelope envelope; envelope.action = je.attribute("action"); envelope.initiator = je.attribute("initiator"); envelope.responder = je.attribute("responder"); envelope.sid = je.attribute("sid"); if(envelope.action == "session-terminate") { bool found; QDomElement re = findSubTag(je, "reason", &found); if(!found) { respondError(from, iq_id, 400, QString()); return true; } envelope.reason = elementToReason(re); if((int)envelope.reason.condition == -1) { respondError(from, iq_id, 400, QString()); return true; } } else { for(QDomNode n = je.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; QDomElement e = n.toElement(); if(e.tagName() != "content") continue; JingleRtpContent c; c.creator = e.attribute("creator"); c.disposition = e.attribute("disposition"); c.name = e.attribute("name"); c.senders = e.attribute("senders"); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; QDomElement e = n.toElement(); if(e.tagName() == "description" && e.attribute("xmlns") == "urn:xmpp:jingle:apps:rtp:1") { c.desc.media = e.attribute("media"); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; QDomElement e = n.toElement(); JingleRtpPayloadType pt = elementToPayloadType(e); if(pt.id == -1) { respondError(from, iq_id, 400, QString()); return true; } c.desc.payloadTypes += pt; } } else if(e.tagName() == "transport" && e.attribute("xmlns") == "urn:xmpp:jingle:transports:ice-udp:1") { c.trans.user = e.attribute("ufrag"); c.trans.pass = e.attribute("pwd"); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { if(!n.isElement()) continue; QDomElement e = n.toElement(); XMPP::Ice176::Candidate ic = elementToCandidate(e); if(ic.type.isEmpty()) { respondError(from, iq_id, 400, QString()); return true; } c.trans.candidates += ic; } } } envelope.contentList += c; } } emit incomingRequest(from, iq_id, envelope); return true; } psi-0.14/src/avcall/jinglertp.cpp0000755000175000017500000010131111305557613015074 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #include "jinglertp.h" #include #include #include #include "iris/netnames.h" #include "xmpp_client.h" // TODO: reject offers that don't contain at least one of audio or video // TODO: support candidate negotiations over the JingleRtpChannel thread // boundary, so we can change candidates after the stream is active static QChar randomPrintableChar() { // 0-25 = a-z // 26-51 = A-Z // 52-61 = 0-9 uchar c = QCA::Random::randomChar() % 62; if(c <= 25) return 'a' + c; else if(c <= 51) return 'A' + (c - 26); else return '0' + (c - 52); } static QString randomCredential(int len) { QString out; for(int n = 0; n < len; ++n) out += randomPrintableChar(); return out; } // resolve external address and stun server // FIXME: when/if our ICE engine supports adding these dynamically, we should // not have the lookups block on each other class Resolver : public QObject { Q_OBJECT private: XMPP::NameResolver dnsA; XMPP::NameResolver dnsB; QString extHost; QString stunHost; bool extDone; bool stunDone; public: QHostAddress extAddr; QHostAddress stunAddr; Resolver(QObject *parent = 0) : QObject(parent), dnsA(parent), dnsB(parent) { connect(&dnsA, SIGNAL(resultsReady(const QList &)), SLOT(dns_resultsReady(const QList &))); connect(&dnsA, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error))); connect(&dnsB, SIGNAL(resultsReady(const QList &)), SLOT(dns_resultsReady(const QList &))); connect(&dnsB, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error))); } void start(const QString &_extHost, const QString &_stunHost) { extHost = _extHost; stunHost = _stunHost; if(!extHost.isEmpty()) { extDone = false; dnsA.start(extHost.toLatin1()); } else extDone = true; if(!stunHost.isEmpty()) { stunDone = false; dnsB.start(stunHost.toLatin1()); } else stunDone = true; if(extDone && stunDone) QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } signals: void finished(); private slots: void dns_resultsReady(const QList &results) { XMPP::NameResolver *dns = (XMPP::NameResolver *)sender(); // FIXME: support more than one address? QHostAddress addr = results.first().address(); if(dns == &dnsA) { extAddr = addr; extDone = true; tryFinish(); } else // dnsB { stunAddr = addr; stunDone = true; tryFinish(); } } void dns_error(XMPP::NameResolver::Error e) { Q_UNUSED(e); XMPP::NameResolver *dns = (XMPP::NameResolver *)sender(); if(dns == &dnsA) { extDone = true; tryFinish(); } else // dnsB { stunDone = true; tryFinish(); } } private: void tryFinish() { if(extDone && stunDone) emit finished(); } }; //---------------------------------------------------------------------------- // JingleRtp //---------------------------------------------------------------------------- class JingleRtpChannelPrivate : public QObject { Q_OBJECT public: JingleRtpChannel *q; QMutex m; XMPP::Ice176 *iceA; XMPP::Ice176 *iceV; QTimer *rtpActivityTimer; QList in; JingleRtpChannelPrivate(JingleRtpChannel *_q); ~JingleRtpChannelPrivate(); void setIceObjects(XMPP::Ice176 *_iceA, XMPP::Ice176 *_iceV); void restartRtpActivityTimer(); private slots: void start(); void ice_readyRead(int componentIndex); void ice_datagramsWritten(int componentIndex, int count); void rtpActivity_timeout(); }; class JingleRtpManagerPrivate : public QObject { Q_OBJECT public: JingleRtpManager *q; XMPP::Client *client; QHostAddress selfAddr; QString extHost; QString stunHost; int stunPort; int basePort; QList sessions; QList pending; JT_PushJingleRtp *push_task; JingleRtpManagerPrivate(XMPP::Client *_client, JingleRtpManager *_q); ~JingleRtpManagerPrivate(); QString createSid(const XMPP::Jid &peer) const; void unlink(JingleRtp *sess); private slots: void push_task_incomingRequest(const XMPP::Jid &from, const QString &iq_id, const JingleRtpEnvelope &envelope); }; class JingleRtpPrivate : public QObject { Q_OBJECT public: JingleRtp *q; JingleRtpManagerPrivate *manager; bool incoming; XMPP::Jid peer; QString sid; int types; QList localAudioPayloadTypes; QList localVideoPayloadTypes; QList remoteAudioPayloadTypes; QList remoteVideoPayloadTypes; int localMaximumBitrate; int remoteMaximumBitrate; QString audioName; QString videoName; QString init_iq_id; JT_JingleRtp *jt; Resolver resolver; QHostAddress extAddr; QHostAddress stunAddr; int stunPort; XMPP::Ice176 *iceA; XMPP::Ice176 *iceV; JingleRtpChannel *rtpChannel; class IceStatus { public: bool started; QString remoteUfrag; QString remotePassword; // for queuing up candidates before using them QList localCandidates; QList remoteCandidates; QVector channelsReady; }; IceStatus iceA_status; IceStatus iceV_status; bool local_media_ready; bool prov_accepted; bool ice_connected; bool session_accepted; bool session_activated; QTimer *handshakeTimer; JingleRtp::Error errorCode; JingleRtpPrivate(JingleRtp *_q) : QObject(_q), q(_q), manager(0), localMaximumBitrate(-1), remoteMaximumBitrate(-1), jt(0), resolver(this), iceA(0), iceV(0), local_media_ready(false), prov_accepted(false), ice_connected(false), session_accepted(false), session_activated(false) { connect(&resolver, SIGNAL(finished()), SLOT(resolver_finished())); handshakeTimer = new QTimer(this); connect(handshakeTimer, SIGNAL(timeout()), SLOT(handshake_timeout())); handshakeTimer->setSingleShot(true); rtpChannel = new JingleRtpChannel; } ~JingleRtpPrivate() { cleanup(); manager->unlink(q); handshakeTimer->setParent(0); handshakeTimer->disconnect(this); handshakeTimer->deleteLater(); delete rtpChannel; } void startOutgoing() { local_media_ready = true; types = 0; if(!localAudioPayloadTypes.isEmpty()) { printf("there are audio payload types\n"); types |= JingleRtp::Audio; } if(!localVideoPayloadTypes.isEmpty()) { printf("there are video payload types\n"); types |= JingleRtp::Video; } printf("types=%d\n", types); resolver.start(manager->extHost, manager->stunHost); } void accept(int _types) { types = _types; // TODO: cancel away whatever media type is not used resolver.start(manager->extHost, manager->stunHost); } void reject() { if(!incoming) { bool ok = true; if((types & JingleRtp::Audio) && !iceA_status.started) ok = false; if((types & JingleRtp::Video) && !iceV_status.started) ok = false; // we haven't even sent session-initiate if(!ok) { cleanup(); return; } } else { // send iq-result if we haven't done so yet if(!prov_accepted) { prov_accepted = true; manager->push_task->respondSuccess(peer, init_iq_id); } } JingleRtpEnvelope envelope; envelope.action = "session-terminate"; envelope.sid = sid; envelope.reason.condition = JingleRtpReason::Gone; JT_JingleRtp *task = new JT_JingleRtp(manager->client->rootTask()); task->request(peer, envelope); task->go(true); cleanup(); } void localMediaUpdate() { local_media_ready = true; tryAccept(); tryActivated(); } // called by manager when request is received, including // session-initiate. // note: manager will never send session-initiate twice. bool incomingRequest(const QString &iq_id, const JingleRtpEnvelope &envelope) { // TODO: jingle has a lot of fields, and we kind of skip over // most of them just to grab what we need. perhaps in the // future we could do more integrity checking. if(envelope.action == "session-initiate") { // initially flag both types, so we don't drop any // transport-info before we accept (at which point // we specify what types we actually want) types = JingleRtp::Audio | JingleRtp::Video; init_iq_id = iq_id; const JingleRtpContent *audioContent = 0; const JingleRtpContent *videoContent = 0; // find content foreach(const JingleRtpContent &c, envelope.contentList) { if((types & JingleRtp::Audio) && c.desc.media == "audio" && !audioContent) { audioContent = &c; break; } else if((types & JingleRtp::Video) && c.desc.media == "video" && !videoContent) { videoContent = &c; break; } } if(audioContent) { audioName = audioContent->name; remoteAudioPayloadTypes = audioContent->desc.payloadTypes; if(!audioContent->trans.user.isEmpty()) { iceA_status.remoteUfrag = audioContent->trans.user; iceA_status.remotePassword = audioContent->trans.pass; } iceA_status.remoteCandidates += audioContent->trans.candidates; } if(videoContent) { videoName = videoContent->name; remoteVideoPayloadTypes = videoContent->desc.payloadTypes; if(!videoContent->trans.user.isEmpty()) { iceV_status.remoteUfrag = videoContent->trans.user; iceV_status.remotePassword = videoContent->trans.pass; } iceV_status.remoteCandidates += videoContent->trans.candidates; } // must offer at least one audio or video payload if(remoteAudioPayloadTypes.isEmpty() && remoteVideoPayloadTypes.isEmpty()) return false; } else if(envelope.action == "session-accept" && !incoming) { manager->push_task->respondSuccess(peer, iq_id); const JingleRtpContent *audioContent = 0; const JingleRtpContent *videoContent = 0; // find content foreach(const JingleRtpContent &c, envelope.contentList) { if((types & JingleRtp::Audio) && c.desc.media == "audio" && c.name == audioName && !audioContent) { audioContent = &c; break; } else if((types & JingleRtp::Video) && c.desc.media == "video" && c.name == videoName && !videoContent) { videoContent = &c; break; } } // we support audio, peer doesn't if((types & JingleRtp::Audio) && !audioContent) types &= ~JingleRtp::Audio; // we support video, peer doesn't if((types & JingleRtp::Video) && !videoContent) types &= ~JingleRtp::Video; if(types == 0) { reject(); emit q->rejected(); return false; } if(audioContent) { remoteAudioPayloadTypes = audioContent->desc.payloadTypes; if(!audioContent->trans.user.isEmpty()) { iceA_status.remoteUfrag = audioContent->trans.user; iceA_status.remotePassword = audioContent->trans.pass; } iceA_status.remoteCandidates += audioContent->trans.candidates; } if(videoContent) { remoteVideoPayloadTypes = videoContent->desc.payloadTypes; if(!videoContent->trans.user.isEmpty()) { iceV_status.remoteUfrag = videoContent->trans.user; iceV_status.remotePassword = videoContent->trans.pass; } iceV_status.remoteCandidates += videoContent->trans.candidates; } restartHandshakeTimer(); flushRemoteCandidates(); session_accepted = true; QMetaObject::invokeMethod(this, "after_session_accept", Qt::QueuedConnection); emit q->remoteMediaUpdated(); } else if(envelope.action == "session-terminate") { manager->push_task->respondSuccess(peer, iq_id); cleanup(); emit q->rejected(); } else if(envelope.action == "transport-info") { manager->push_task->respondSuccess(peer, iq_id); const JingleRtpContent *audioContent = 0; const JingleRtpContent *videoContent = 0; // find content foreach(const JingleRtpContent &c, envelope.contentList) { if((types & JingleRtp::Audio) && c.name == audioName && !audioContent) { audioContent = &c; break; } else if((types & JingleRtp::Video) && c.name == videoName && !videoContent) { videoContent = &c; break; } } if(audioContent) { if(!audioContent->trans.user.isEmpty()) { iceA_status.remoteUfrag = audioContent->trans.user; iceA_status.remotePassword = audioContent->trans.pass; } printf("audio candidates=%d\n", audioContent->trans.candidates.count()); iceA_status.remoteCandidates += audioContent->trans.candidates; } if(videoContent) { if(!videoContent->trans.user.isEmpty()) { iceV_status.remoteUfrag = videoContent->trans.user; iceV_status.remotePassword = videoContent->trans.pass; } printf("video candidates=%d\n", videoContent->trans.candidates.count()); iceV_status.remoteCandidates += videoContent->trans.candidates; } // don't process the candidates unless our ICE engine // is started if(prov_accepted) flushRemoteCandidates(); } else { manager->push_task->respondError(peer, iq_id, 400, QString()); return false; } return true; } private: void cleanup() { resolver.disconnect(this); handshakeTimer->stop(); delete jt; jt = 0; if(iceA) { iceA->disconnect(this); iceA->setParent(0); iceA->deleteLater(); iceA = 0; } if(iceV) { iceV->disconnect(this); iceV->setParent(0); iceV->deleteLater(); iceV = 0; } // prevent delivery of events by manager peer = XMPP::Jid(); sid.clear(); } void start_ice() { stunPort = manager->stunPort; if(!stunAddr.isNull() && stunPort > 0) printf("STUN service: %s:%d\n", qPrintable(stunAddr.toString()), stunPort); if(types & JingleRtp::Audio) { iceA = new XMPP::Ice176(this); setup_ice(iceA); if(manager->basePort != -1) iceA->setBasePort(manager->basePort); iceA_status.started = false; iceA_status.channelsReady.resize(2); iceA_status.channelsReady[0] = false; iceA_status.channelsReady[1] = false; } if(types & JingleRtp::Video) { iceV = new XMPP::Ice176(this); setup_ice(iceV); if(manager->basePort != -1) iceV->setBasePort(manager->basePort + 2); iceV_status.started = false; iceV_status.channelsReady.resize(2); iceV_status.channelsReady[0] = false; iceV_status.channelsReady[1] = false; } XMPP::Ice176::Mode m; if(!incoming) m = XMPP::Ice176::Initiator; else m = XMPP::Ice176::Responder; if(iceA) { printf("starting ice for audio\n"); iceA->start(m); } if(iceV) { printf("starting ice for video\n"); iceV->start(m); } } void setup_ice(XMPP::Ice176 *ice) { connect(ice, SIGNAL(started()), SLOT(ice_started())); connect(ice, SIGNAL(error()), SLOT(ice_error())); connect(ice, SIGNAL(localCandidatesReady(const QList &)), SLOT(ice_localCandidatesReady(const QList &))); connect(ice, SIGNAL(componentReady(int)), SLOT(ice_componentReady(int)), Qt::QueuedConnection); // signal is not DOR-SS // RTP+RTCP ice->setComponentCount(2); QList localAddrs; XMPP::Ice176::LocalAddress addr; // a local address is required to use ice. however, if // we don't have a local address, we won't handle it as // an error here. instead, we'll start Ice176 anyway, // which should immediately error back at us. if(manager->selfAddr.isNull()) { printf("no self address to use. this will fail.\n"); return; } addr.addr = manager->selfAddr; localAddrs += addr; ice->setLocalAddresses(localAddrs); if(!extAddr.isNull()) { QList extAddrs; XMPP::Ice176::ExternalAddress eaddr; eaddr.base = addr; eaddr.addr = extAddr; extAddrs += eaddr; ice->setExternalAddresses(extAddrs); } if(!stunAddr.isNull() && stunPort > 0) { // TODO: relay support XMPP::Ice176::StunServiceType stunType; //if(opt_is_relay) // stunType = XMPP::Ice176::Relay; //else stunType = XMPP::Ice176::Basic; ice->setStunService(stunType, stunAddr, stunPort); /*if(!opt_user.isEmpty()) { ice->setStunUsername(opt_user); ice->setStunPassword(opt_pass.toUtf8()); }*/ } } // called when all ICE objects are started void after_ice_started() { printf("after_ice_started\n"); // for outbound, send the session-initiate if(!incoming) { sid = manager->createSid(peer); JingleRtpEnvelope envelope; envelope.action = "session-initiate"; envelope.initiator = manager->client->jid().full(); envelope.sid = sid; if(types & JingleRtp::Audio) { audioName = "A"; JingleRtpContent content; content.creator = "initiator"; content.name = audioName; content.senders = "both"; content.desc.media = "audio"; content.desc.payloadTypes = localAudioPayloadTypes; content.trans.user = iceA->localUfrag(); content.trans.pass = iceA->localPassword(); envelope.contentList += content; } if(types & JingleRtp::Video) { videoName = "V"; JingleRtpContent content; content.creator = "initiator"; content.name = videoName; content.senders = "both"; content.desc.media = "video"; content.desc.payloadTypes = localVideoPayloadTypes; content.trans.user = iceV->localUfrag(); content.trans.pass = iceV->localPassword(); envelope.contentList += content; } jt = new JT_JingleRtp(manager->client->rootTask()); connect(jt, SIGNAL(finished()), SLOT(task_finished())); jt->request(peer, envelope); jt->go(true); } else { restartHandshakeTimer(); prov_accepted = true; manager->push_task->respondSuccess(peer, init_iq_id); flushRemoteCandidates(); } } // received iq-result to session-initiate void prov_accept() { prov_accepted = true; flushLocalCandidates(); } // received iq-error to session-initiate void prov_reject() { cleanup(); emit q->rejected(); } void flushLocalCandidates() { printf("flushing local candidates\n"); QList contentList; // according to xep-166, creator is always whoever added // the content type, which in our case is always the // initiator if((types & JingleRtp::Audio) && !iceA_status.localCandidates.isEmpty()) { JingleRtpContent content; //if(!incoming) content.creator = "initiator"; //else // content.creator = "responder"; content.name = audioName; content.trans.user = iceA->localUfrag(); content.trans.pass = iceA->localPassword(); content.trans.candidates = iceA_status.localCandidates; iceA_status.localCandidates.clear(); contentList += content; } if((types & JingleRtp::Video) && !iceV_status.localCandidates.isEmpty()) { JingleRtpContent content; //if(!incoming) content.creator = "initiator"; //else // content.creator = "responder"; content.name = videoName; content.trans.user = iceV->localUfrag(); content.trans.pass = iceV->localPassword(); content.trans.candidates = iceV_status.localCandidates; iceV_status.localCandidates.clear(); contentList += content; } if(!contentList.isEmpty()) { JingleRtpEnvelope envelope; envelope.action = "transport-info"; envelope.sid = sid; envelope.contentList = contentList; JT_JingleRtp *task = new JT_JingleRtp(manager->client->rootTask()); task->request(peer, envelope); task->go(true); } } void flushRemoteCandidates() { // FIXME: currently, new candidates are ignored after the // session is activated (iceA/iceV are passed to // JingleRtpChannel and our local pointers are nulled). // unfortunately this means we can't upgrade to better // candidates on the fly. if(types & JingleRtp::Audio && iceA) { iceA->setPeerUfrag(iceA_status.remoteUfrag); iceA->setPeerPassword(iceA_status.remotePassword); if(!iceA_status.remoteCandidates.isEmpty()) { iceA->addRemoteCandidates(iceA_status.remoteCandidates); iceA_status.remoteCandidates.clear(); } } if(types & JingleRtp::Video && iceV) { iceV->setPeerUfrag(iceV_status.remoteUfrag); iceV->setPeerPassword(iceV_status.remotePassword); if(!iceV_status.remoteCandidates.isEmpty()) { iceV->addRemoteCandidates(iceV_status.remoteCandidates); iceV_status.remoteCandidates.clear(); } } } // called when all ICE components are established void after_ice_connected() { if(incoming) tryAccept(); tryActivated(); } void tryAccept() { if(local_media_ready && ice_connected && !session_accepted) { JingleRtpEnvelope envelope; envelope.action = "session-accept"; envelope.responder = manager->client->jid().full(); envelope.sid = sid; if(types & JingleRtp::Audio) { JingleRtpContent content; content.creator = "initiator"; content.name = audioName; content.senders = "both"; content.desc.media = "audio"; content.desc.payloadTypes = localAudioPayloadTypes; content.trans.user = iceA->localUfrag(); content.trans.pass = iceA->localPassword(); envelope.contentList += content; } if(types & JingleRtp::Video) { JingleRtpContent content; content.creator = "initiator"; content.name = videoName; content.senders = "both"; content.desc.media = "video"; content.desc.payloadTypes = localVideoPayloadTypes; content.trans.user = iceV->localUfrag(); content.trans.pass = iceV->localPassword(); envelope.contentList += content; } session_accepted = true; JT_JingleRtp *task = new JT_JingleRtp(manager->client->rootTask()); task->request(peer, envelope); task->go(true); } } void tryActivated() { if(session_accepted && ice_connected) { if(session_activated) { printf("warning: attempting to activate an already active session\n"); return; } printf("activating!\n"); session_activated = true; handshakeTimer->stop(); if(iceA) { iceA->disconnect(this); iceA->setParent(0); } if(iceV) { iceV->disconnect(this); iceV->setParent(0); } rtpChannel->d->setIceObjects(iceA, iceV); iceA = 0; iceV = 0; emit q->activated(); } } void restartHandshakeTimer() { // there better be some activity in 10 seconds handshakeTimer->start(10000); } private slots: void resolver_finished() { extAddr = resolver.extAddr; stunAddr = resolver.stunAddr; printf("resolver finished\n"); start_ice(); } void handshake_timeout() { reject(); errorCode = JingleRtp::ErrorTimeout; emit q->error(); } void ice_started() { XMPP::Ice176 *ice = (XMPP::Ice176 *)sender(); printf("ice_started\n"); if(ice == iceA) iceA_status.started = true; else // iceV iceV_status.started = true; bool ok = true; if((types & JingleRtp::Audio) && !iceA_status.started) ok = false; if((types & JingleRtp::Video) && !iceV_status.started) ok = false; if(ok) after_ice_started(); } void ice_error() { errorCode = JingleRtp::ErrorICE; emit q->error(); } void ice_localCandidatesReady(const QList &list) { XMPP::Ice176 *ice = (XMPP::Ice176 *)sender(); if(ice == iceA) iceA_status.localCandidates += list; else // iceV iceV_status.localCandidates += list; printf("local candidate ready\n"); if(prov_accepted) flushLocalCandidates(); } void ice_componentReady(int index) { XMPP::Ice176 *ice = (XMPP::Ice176 *)sender(); if(ice == iceA) { Q_ASSERT(!iceA_status.channelsReady[index]); iceA_status.channelsReady[index] = true; } else // iceV { Q_ASSERT(!iceV_status.channelsReady[index]); iceV_status.channelsReady[index] = true; } bool allReady = true; if(types & JingleRtp::Audio) { for(int n = 0; n < iceA_status.channelsReady.count(); ++n) { if(!iceA_status.channelsReady[n]) { allReady = false; break; } } } if(types & JingleRtp::Video) { for(int n = 0; n < iceV_status.channelsReady.count(); ++n) { if(!iceV_status.channelsReady[n]) { allReady = false; break; } } } if(allReady) { ice_connected = true; after_ice_connected(); } } void task_finished() { if(!jt) return; JT_JingleRtp *task = jt; jt = 0; if(task->success()) prov_accept(); else prov_reject(); } void after_session_accept() { tryActivated(); } }; JingleRtp::JingleRtp() { d = new JingleRtpPrivate(this); } JingleRtp::~JingleRtp() { delete d; } XMPP::Jid JingleRtp::jid() const { return d->peer; } QList JingleRtp::remoteAudioPayloadTypes() const { return d->remoteAudioPayloadTypes; } QList JingleRtp::remoteVideoPayloadTypes() const { return d->remoteVideoPayloadTypes; } int JingleRtp::remoteMaximumBitrate() const { return d->remoteMaximumBitrate; } void JingleRtp::setLocalAudioPayloadTypes(const QList &types) { d->localAudioPayloadTypes = types; } void JingleRtp::setLocalVideoPayloadTypes(const QList &types) { d->localVideoPayloadTypes = types; } void JingleRtp::setLocalMaximumBitrate(int kbps) { d->localMaximumBitrate = kbps; } void JingleRtp::connectToJid(const XMPP::Jid &jid) { d->peer = jid; d->startOutgoing(); } void JingleRtp::accept(int types) { d->accept(types); } void JingleRtp::reject() { d->reject(); } void JingleRtp::localMediaUpdate() { d->localMediaUpdate(); } JingleRtp::Error JingleRtp::errorCode() const { return d->errorCode; } JingleRtpChannel *JingleRtp::rtpChannel() { return d->rtpChannel; } //---------------------------------------------------------------------------- // JingleRtpChannel //---------------------------------------------------------------------------- JingleRtpChannelPrivate::JingleRtpChannelPrivate(JingleRtpChannel *_q) : QObject(_q), q(_q), iceA(0), iceV(0) { rtpActivityTimer = new QTimer(this); connect(rtpActivityTimer, SIGNAL(timeout()), SLOT(rtpActivity_timeout())); } JingleRtpChannelPrivate::~JingleRtpChannelPrivate() { if(iceA) { iceA->disconnect(this); iceA->setParent(0); iceA->deleteLater(); } if(iceV) { iceV->disconnect(this); iceV->setParent(0); iceV->deleteLater(); } rtpActivityTimer->setParent(0); rtpActivityTimer->disconnect(this); rtpActivityTimer->deleteLater(); } void JingleRtpChannelPrivate::setIceObjects(XMPP::Ice176 *_iceA, XMPP::Ice176 *_iceV) { if(QThread::currentThread() != thread()) { // if called from another thread, safely change ownership QMutexLocker locker(&m); iceA = _iceA; iceV = _iceV; if(iceA) { iceA->moveToThread(thread()); connect(iceA, SIGNAL(readyRead(int)), SLOT(ice_readyRead(int))); connect(iceA, SIGNAL(datagramsWritten(int, int)), SLOT(ice_datagramsWritten(int, int))); } if(iceV) { iceV->moveToThread(thread()); connect(iceV, SIGNAL(readyRead(int)), SLOT(ice_readyRead(int))); connect(iceV, SIGNAL(datagramsWritten(int, int)), SLOT(ice_datagramsWritten(int, int))); } QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); } else { iceA = _iceA; iceV = _iceV; if(iceA) { connect(iceA, SIGNAL(readyRead(int)), SLOT(ice_readyRead(int))); connect(iceA, SIGNAL(datagramsWritten(int, int)), SLOT(ice_datagramsWritten(int, int))); } if(iceV) { connect(iceV, SIGNAL(readyRead(int)), SLOT(ice_readyRead(int))); connect(iceV, SIGNAL(datagramsWritten(int, int)), SLOT(ice_datagramsWritten(int, int))); } start(); } } void JingleRtpChannelPrivate::restartRtpActivityTimer() { // if we go 5 seconds without an RTP packet, then that's // pretty bad rtpActivityTimer->start(5000); } void JingleRtpChannelPrivate::start() { if(iceA) iceA->setParent(this); if(iceV) iceV->setParent(this); restartRtpActivityTimer(); } void JingleRtpChannelPrivate::ice_readyRead(int componentIndex) { XMPP::Ice176 *ice = (XMPP::Ice176 *)sender(); if(ice == iceA && componentIndex == 0) restartRtpActivityTimer(); if(ice == iceA) { while(iceA->hasPendingDatagrams(componentIndex)) { JingleRtp::RtpPacket packet; packet.type = JingleRtp::Audio; packet.portOffset = componentIndex; packet.value = iceA->readDatagram(componentIndex); in += packet; } } else // iceV { while(iceV->hasPendingDatagrams(componentIndex)) { JingleRtp::RtpPacket packet; packet.type = JingleRtp::Video; packet.portOffset = componentIndex; packet.value = iceV->readDatagram(componentIndex); in += packet; } } emit q->readyRead(); } void JingleRtpChannelPrivate::ice_datagramsWritten(int componentIndex, int count) { Q_UNUSED(componentIndex); emit q->packetsWritten(count); } void JingleRtpChannelPrivate::rtpActivity_timeout() { printf("warning: 5 seconds passed without receiving audio RTP\n"); } JingleRtpChannel::JingleRtpChannel() { d = new JingleRtpChannelPrivate(this); } JingleRtpChannel::~JingleRtpChannel() { delete d; } bool JingleRtpChannel::packetsAvailable() const { return !d->in.isEmpty(); } JingleRtp::RtpPacket JingleRtpChannel::read() { return d->in.takeFirst(); } void JingleRtpChannel::write(const JingleRtp::RtpPacket &packet) { QMutexLocker locker(&d->m); if(packet.type == JingleRtp::Audio && d->iceA) d->iceA->writeDatagram(packet.portOffset, packet.value); else if(packet.type == JingleRtp::Video && d->iceV) d->iceV->writeDatagram(packet.portOffset, packet.value); } //---------------------------------------------------------------------------- // JingleRtpManager //---------------------------------------------------------------------------- JingleRtpManagerPrivate::JingleRtpManagerPrivate(XMPP::Client *_client, JingleRtpManager *_q) : QObject(_q), q(_q), client(_client), stunPort(-1), basePort(-1) { push_task = new JT_PushJingleRtp(client->rootTask()); connect(push_task, SIGNAL(incomingRequest(const XMPP::Jid &, const QString &, const JingleRtpEnvelope &)), SLOT(push_task_incomingRequest(const XMPP::Jid &, const QString &, const JingleRtpEnvelope &))); } JingleRtpManagerPrivate::~JingleRtpManagerPrivate() { delete push_task; } QString JingleRtpManagerPrivate::createSid(const XMPP::Jid &peer) const { while(1) { QString out = randomCredential(16); bool found = false; for(int n = 0; n < sessions.count(); ++n) { if(sessions[n]->d->peer == peer && sessions[n]->d->sid == out) { found = true; break; } } if(!found) return out; } } void JingleRtpManagerPrivate::unlink(JingleRtp *sess) { sessions.removeAll(sess); } void JingleRtpManagerPrivate::push_task_incomingRequest(const XMPP::Jid &from, const QString &iq_id, const JingleRtpEnvelope &envelope) { printf("incoming request: [%s]\n", qPrintable(envelope.action)); // don't allow empty sid if(envelope.sid.isEmpty()) { push_task->respondError(from, iq_id, 400, QString()); return; } if(envelope.action == "session-initiate") { int at = -1; for(int n = 0; n < sessions.count(); ++n) { if(sessions[n]->d->peer == from && sessions[n]->d->sid == envelope.sid) { at = n; break; } } // duplicate session if(at != -1) { push_task->respondError(from, iq_id, 400, QString()); return; } JingleRtp *sess = new JingleRtp; sess->d->manager = this; sess->d->incoming = true; sess->d->peer = from; sess->d->sid = envelope.sid; sessions += sess; printf("new initiate, from=[%s] sid=[%s]\n", qPrintable(from.full()), qPrintable(envelope.sid)); if(!sess->d->incomingRequest(iq_id, envelope)) { delete sess; push_task->respondError(from, iq_id, 400, QString()); return; } pending += sess; emit q->incomingReady(); } else { int at = -1; for(int n = 0; n < sessions.count(); ++n) { if(sessions[n]->d->peer == from && sessions[n]->d->sid == envelope.sid) { at = n; break; } } // session not found if(at == -1) { push_task->respondError(from, iq_id, 400, QString()); return; } sessions[at]->d->incomingRequest(iq_id, envelope); } } JingleRtpManager::JingleRtpManager(XMPP::Client *client) : QObject(0) { d = new JingleRtpManagerPrivate(client, this); } JingleRtpManager::~JingleRtpManager() { delete d; } JingleRtp *JingleRtpManager::createOutgoing() { JingleRtp *sess = new JingleRtp; sess->d->manager = d; sess->d->incoming = false; d->sessions += sess; return sess; } JingleRtp *JingleRtpManager::takeIncoming() { return d->pending.takeFirst(); } void JingleRtpManager::setSelfAddress(const QHostAddress &addr) { d->selfAddr = addr; } void JingleRtpManager::setExternalAddress(const QString &host) { d->extHost = host; } void JingleRtpManager::setStunHost(const QString &host, int port) { d->stunHost = host; d->stunPort = port; } void JingleRtpManager::setBasePort(int port) { d->basePort = port; } #include "jinglertp.moc" psi-0.14/src/avcall/avcall.h0000644000175000017500000000463611305557613014016 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #ifndef AVCALL_H #define AVCALL_H #include class QHostAddress; namespace XMPP { class Jid; } namespace PsiMedia { class VideoWidget; } class PsiAccount; class AvCallPrivate; class AvCallManagerPrivate; class AvCall : public QObject { Q_OBJECT public: enum Mode { Audio, Video, Both }; AvCall(const AvCall &from); ~AvCall(); XMPP::Jid jid() const; Mode mode() const; void connectToJid(const XMPP::Jid &jid, Mode mode, int kbps = -1); void accept(Mode mode, int kbps = -1); void reject(); void setIncomingVideo(PsiMedia::VideoWidget *widget); QString errorString() const; // if we use deleteLater() on a call, then it won't detach from the // manager until the deletion resolves. use unlink() to immediately // detach, and then call deleteLater(). void unlink(); signals: void activated(); void error(); private: friend class AvCallPrivate; friend class AvCallManager; friend class AvCallManagerPrivate; AvCall(); AvCallPrivate *d; }; class AvCallManager : public QObject { Q_OBJECT public: AvCallManager(PsiAccount *pa); ~AvCallManager(); AvCall *createOutgoing(); AvCall *takeIncoming(); static void config(); static bool isSupported(); static bool isVideoSupported(); void setSelfAddress(const QHostAddress &addr); void setStunHost(const QString &host, int port); static void setBasePort(int port); static void setExternalAddress(const QString &host); static void setAudioOutDevice(const QString &id); static void setAudioInDevice(const QString &id); static void setVideoInDevice(const QString &id); signals: void incomingReady(); private: friend class AvCallManagerPrivate; friend class AvCall; friend class AvCallPrivate; AvCallManagerPrivate *d; }; #endif psi-0.14/src/avcall/avcall.cpp0000644000175000017500000004673311305557613014355 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #include "avcall.h" #include #include #include #include #include #include #include "xmpp_jid.h" #include "jinglertp.h" #include "../psimedia/psimedia.h" #include "applicationinfo.h" #include "psiaccount.h" #define USE_THREAD class Configuration { public: bool liveInput; QString audioOutDeviceId, audioInDeviceId, videoInDeviceId; QString file; bool loopFile; PsiMedia::AudioParams audioParams; PsiMedia::VideoParams videoParams; int basePort; QString extHost; Configuration() : liveInput(false), loopFile(false), basePort(-1) { } }; // get default settings static Configuration getDefaultConfiguration() { Configuration config; config.liveInput = true; config.loopFile = true; return config; } static Configuration *g_config = 0; static void ensureConfig() { if(!g_config) { g_config = new Configuration; *g_config = getDefaultConfiguration(); } } #ifdef GSTPROVIDER_STATIC Q_IMPORT_PLUGIN(gstprovider) #endif #ifndef GSTPROVIDER_STATIC static QString findPlugin(const QString &relpath, const QString &basename) { QDir dir(QCoreApplication::applicationDirPath()); if(!dir.cd(relpath)) return QString(); foreach(const QString &fileName, dir.entryList()) { if(fileName.contains(basename)) { QString filePath = dir.filePath(fileName); if(QLibrary::isLibrary(filePath)) return filePath; } } return QString(); } #endif static bool g_loaded = false; static void ensureLoaded() { if(!g_loaded) { #ifndef GSTPROVIDER_STATIC QString pluginFile; QString resourcePath; pluginFile = qgetenv("PSI_MEDIA_PLUGIN"); if(pluginFile.isEmpty()) { #if defined(Q_OS_WIN) pluginFile = findPlugin(".", "gstprovider"); resourcePath = QCoreApplication::applicationDirPath() + "/gstreamer-0.10"; #elif defined(Q_OS_MAC) pluginFile = findPlugin("../Plugins", "gstprovider"); resourcePath = QCoreApplication::applicationDirPath() + "/../Frameworks/gstreamer-0.10"; #else pluginFile = findPlugin(ApplicationInfo::libDir() + "/plugins", "gstprovider"); #endif } PsiMedia::PluginResult r = PsiMedia::loadPlugin(pluginFile, resourcePath); if(r == PsiMedia::PluginSuccess) g_loaded = true; #else g_loaded = true; #endif if(g_loaded) ensureConfig(); } } static JingleRtpPayloadType payloadInfoToPayloadType(const PsiMedia::PayloadInfo &pi) { JingleRtpPayloadType out; out.id = pi.id(); out.name = pi.name(); out.clockrate = pi.clockrate(); out.channels = pi.channels(); out.ptime = pi.ptime(); out.maxptime = pi.maxptime(); foreach(const PsiMedia::PayloadInfo::Parameter &pip, pi.parameters()) { JingleRtpPayloadType::Parameter ptp; ptp.name = pip.name; ptp.value = pip.value; out.parameters += ptp; } return out; } static PsiMedia::PayloadInfo payloadTypeToPayloadInfo(const JingleRtpPayloadType &pt) { PsiMedia::PayloadInfo out; out.setId(pt.id); out.setName(pt.name); out.setClockrate(pt.clockrate); out.setChannels(pt.channels); out.setPtime(pt.ptime); out.setMaxptime(pt.maxptime); QList list; foreach(const JingleRtpPayloadType::Parameter &ptp, pt.parameters) { PsiMedia::PayloadInfo::Parameter pip; pip.name = ptp.name; pip.value = ptp.value; list += pip; } out.setParameters(list); return out; } class AvTransmit : public QObject { Q_OBJECT public: PsiMedia::RtpChannel *audio, *video; JingleRtpChannel *transport; AvTransmit(PsiMedia::RtpChannel *_audio, PsiMedia::RtpChannel *_video, JingleRtpChannel *_transport, QObject *parent = 0) : QObject(parent), audio(_audio), video(_video), transport(_transport) { if(audio) { audio->setParent(this); connect(audio, SIGNAL(readyRead()), SLOT(audio_readyRead())); } if(video) { video->setParent(this); connect(video, SIGNAL(readyRead()), SLOT(video_readyRead())); } transport->setParent(this); connect(transport, SIGNAL(readyRead()), SLOT(transport_readyRead())); connect(transport, SIGNAL(packetsWritten(int)), SLOT(transport_packetsWritten(int))); } ~AvTransmit() { if(audio) audio->setParent(0); if(video) video->setParent(0); transport->setParent(0); } private slots: void audio_readyRead() { while(audio->packetsAvailable() > 0) { PsiMedia::RtpPacket packet = audio->read(); JingleRtp::RtpPacket jpacket; jpacket.type = JingleRtp::Audio; jpacket.portOffset = packet.portOffset(); jpacket.value = packet.rawValue(); transport->write(jpacket); } } void video_readyRead() { while(video->packetsAvailable() > 0) { PsiMedia::RtpPacket packet = video->read(); JingleRtp::RtpPacket jpacket; jpacket.type = JingleRtp::Video; jpacket.portOffset = packet.portOffset(); jpacket.value = packet.rawValue(); transport->write(jpacket); } } void transport_readyRead() { while(transport->packetsAvailable()) { JingleRtp::RtpPacket jpacket = transport->read(); if(jpacket.type == JingleRtp::Audio) audio->write(PsiMedia::RtpPacket(jpacket.value, jpacket.portOffset)); else if(jpacket.type == JingleRtp::Video) video->write(PsiMedia::RtpPacket(jpacket.value, jpacket.portOffset)); } } void transport_packetsWritten(int count) { Q_UNUSED(count); // nothing } }; class AvTransmitHandler : public QObject { Q_OBJECT public: AvTransmit *avTransmit; QThread *previousThread; AvTransmitHandler(QObject *parent = 0) : QObject(parent), avTransmit(0) { } ~AvTransmitHandler() { if(avTransmit) releaseAvTransmit(); } // NOTE: the handler never touches these variables except here // and on destruction, so it's safe to call this function from // another thread if you know what you're doing. void setAvTransmit(AvTransmit *_avTransmit) { avTransmit = _avTransmit; previousThread = avTransmit->thread(); avTransmit->moveToThread(thread()); } void releaseAvTransmit() { Q_ASSERT(avTransmit); avTransmit->moveToThread(previousThread); avTransmit = 0; } }; class AvTransmitThread : public QCA::SyncThread { Q_OBJECT public: AvTransmitHandler *handler; AvTransmitThread(QObject *parent = 0) : QCA::SyncThread(parent), handler(0) { } ~AvTransmitThread() { stop(); } protected: virtual void atStart() { handler = new AvTransmitHandler; } virtual void atEnd() { delete handler; } }; //---------------------------------------------------------------------------- // AvCall //---------------------------------------------------------------------------- class AvCallManagerPrivate : public QObject { Q_OBJECT public: AvCallManager *q; PsiAccount *pa; JingleRtpManager *rtpManager; QList sessions; QList pending; AvCallManagerPrivate(PsiAccount *_pa, AvCallManager *_q); ~AvCallManagerPrivate(); void unlink(AvCall *call); private slots: void rtp_incomingReady(); }; class AvCallPrivate : public QObject { Q_OBJECT public: AvCall *q; AvCallManagerPrivate *manager; bool incoming; JingleRtp *sess; PsiMedia::RtpSession rtp; XMPP::Jid peer; AvCall::Mode mode; int bitrate; bool allowVideo; QString errorString; bool transmitAudio; bool transmitVideo; bool transmitting; AvTransmit *avTransmit; AvTransmitThread *avTransmitThread; AvCallPrivate(AvCall *_q) : QObject(_q), q(_q), manager(0), sess(0), transmitAudio(false), transmitVideo(false), transmitting(false), avTransmit(0), avTransmitThread(0) { allowVideo = AvCallManager::isVideoSupported(); connect(&rtp, SIGNAL(started()), SLOT(rtp_started())); connect(&rtp, SIGNAL(preferencesUpdated()), SLOT(rtp_preferencesUpdated())); connect(&rtp, SIGNAL(stopped()), SLOT(rtp_stopped())); connect(&rtp, SIGNAL(error()), SLOT(rtp_error())); } ~AvCallPrivate() { rtp.disconnect(this); cleanup(); unlink(); } void unlink() { if(manager) { // note that the object remains active, just // dissociated from the manager manager->unlink(q); manager = 0; } } void startOutgoing() { if(!manager) return; manager->rtpManager->setBasePort(g_config->basePort); manager->rtpManager->setExternalAddress(g_config->extHost); start_rtp(); } bool initIncoming() { setup_sess(); // JingleRtp guarantees there will be at least one of audio or video bool offeredAudio = false; bool offeredVideo = false; if(!sess->remoteAudioPayloadTypes().isEmpty()) offeredAudio = true; if(allowVideo && !sess->remoteVideoPayloadTypes().isEmpty()) offeredVideo = true; if(offeredAudio && offeredVideo) mode = AvCall::Both; else if(offeredAudio) mode = AvCall::Audio; else if(offeredVideo) mode = AvCall::Video; else { // this could happen if only video is offered but // we don't allow it return false; } return true; } void accept() { if(!manager) return; manager->rtpManager->setBasePort(g_config->basePort); manager->rtpManager->setExternalAddress(g_config->extHost); // kick off the acceptance negotiation while simultaneously // initializing the rtp engine. note that session-accept // won't actually get sent to the peer until we call // localMediaUpdated() int types; if(mode == AvCall::Both) types = JingleRtp::Audio | JingleRtp::Video; else if(mode == AvCall::Audio) types = JingleRtp::Audio; else // Video types = JingleRtp::Video; sess->accept(types); start_rtp(); } void reject() { if(sess) sess->reject(); cleanup(); } private: static QString rtpSessionErrorToString(PsiMedia::RtpSession::Error e) { QString str; switch(e) { case PsiMedia::RtpSession::ErrorSystem: str = tr("System error"); break; case PsiMedia::RtpSession::ErrorCodec: str = tr("Codec error"); break; default: // generic str = tr("Generic error"); break; } return str; } void cleanup() { // if we had a thread, this will move the object back delete avTransmitThread; avTransmitThread = 0; delete avTransmit; avTransmit = 0; rtp.reset(); delete sess; sess = 0; } void start_rtp() { Configuration &config = *g_config; transmitAudio = false; transmitVideo = false; if(config.liveInput) { if(config.audioInDeviceId.isEmpty() && config.videoInDeviceId.isEmpty()) { errorString = tr("Cannot call without selecting a device. Do you have a microphone? Check the Psi options."); cleanup(); emit q->error(); return; } if((mode == AvCall::Audio || mode == AvCall::Both) && !config.audioInDeviceId.isEmpty()) { rtp.setAudioInputDevice(config.audioInDeviceId); transmitAudio = true; } else rtp.setAudioInputDevice(QString()); if((mode == AvCall::Video || mode == AvCall::Both) && !config.videoInDeviceId.isEmpty() && allowVideo) { rtp.setVideoInputDevice(config.videoInDeviceId); transmitVideo = true; } else rtp.setVideoInputDevice(QString()); } else // non-live (file) input { rtp.setFileInput(config.file); rtp.setFileLoopEnabled(config.loopFile); // we just assume the file has both audio and video. // if it doesn't, no big deal, it'll still work. // update: after starting, we can correct these // variables. transmitAudio = true; transmitVideo = true; } if(!config.audioOutDeviceId.isEmpty()) rtp.setAudioOutputDevice(config.audioOutDeviceId); // media types are flagged by params, even if empty QList audioParamsList; if(transmitAudio) audioParamsList += PsiMedia::AudioParams(); rtp.setLocalAudioPreferences(audioParamsList); QList videoParamsList; if(transmitVideo) videoParamsList += PsiMedia::VideoParams(); rtp.setLocalVideoPreferences(videoParamsList); // for incoming sessions, we have the remote media info at // the start, so use it if(incoming) setup_remote_media(); if(bitrate != -1) rtp.setMaximumSendingBitrate(bitrate); transmitting = false; rtp.start(); } void setup_sess() { connect(sess, SIGNAL(rejected()), SLOT(sess_rejected())); connect(sess, SIGNAL(error()), SLOT(sess_error())); connect(sess, SIGNAL(activated()), SLOT(sess_activated())); connect(sess, SIGNAL(remoteMediaUpdated()), SLOT(sess_remoteMediaUpdated())); } void setup_remote_media() { if(transmitAudio) { QList payloadTypes = sess->remoteAudioPayloadTypes(); QList list; foreach(const JingleRtpPayloadType &pt, payloadTypes) list += payloadTypeToPayloadInfo(pt); rtp.setRemoteAudioPreferences(list); } if(transmitVideo) { QList payloadTypes = sess->remoteVideoPayloadTypes(); QList list; foreach(const JingleRtpPayloadType &pt, payloadTypes) list += payloadTypeToPayloadInfo(pt); rtp.setRemoteVideoPreferences(list); } // FIXME: if the remote side doesn't support a media type, // then we need to downgrade locally } private slots: void rtp_started() { if(!manager) return; printf("rtp_started\n"); PsiMedia::PayloadInfo audio, *pAudio; PsiMedia::PayloadInfo video, *pVideo; pAudio = 0; pVideo = 0; if(transmitAudio) { // confirm transmitting of audio is actually possible, // in the case that a file is used as input if(rtp.canTransmitAudio()) { audio = rtp.localAudioPayloadInfo().first(); pAudio = &audio; } else transmitAudio = false; } if(transmitVideo) { // same for video if(rtp.canTransmitVideo()) { video = rtp.localVideoPayloadInfo().first(); pVideo = &video; } else transmitVideo = false; } if(transmitAudio && transmitVideo) mode = AvCall::Both; else if(transmitAudio && !transmitVideo) mode = AvCall::Audio; else if(transmitVideo && !transmitAudio) mode = AvCall::Video; else { // can't happen? Q_ASSERT(0); } if(!incoming) { sess = manager->rtpManager->createOutgoing(); setup_sess(); } if(pAudio) { JingleRtpPayloadType pt = payloadInfoToPayloadType(*pAudio); sess->setLocalAudioPayloadTypes(QList() << pt); } if(pVideo) { JingleRtpPayloadType pt = payloadInfoToPayloadType(*pVideo); sess->setLocalVideoPayloadTypes(QList() << pt); } if(!incoming) sess->connectToJid(peer); else sess->localMediaUpdate(); } void rtp_preferencesUpdated() { // nothing? } void rtp_stopped() { // nothing for now, until we do async shutdown } void rtp_error() { errorString = tr("An error occurred while trying to send:\n%1.").arg(rtpSessionErrorToString(rtp.errorCode())); reject(); emit q->error(); } void sess_rejected() { errorString = tr("Call was rejected or terminated."); cleanup(); emit q->error(); } void sess_error() { JingleRtp::Error e = sess->errorCode(); if(e == JingleRtp::ErrorTimeout) { errorString = tr("Call negotiation timed out."); cleanup(); } else if(e == JingleRtp::ErrorICE) { errorString = tr("Unable to establish peer-to-peer connection."); reject(); } else { errorString = tr("Call negotiation failed."); cleanup(); } emit q->error(); } void sess_activated() { PsiMedia::RtpChannel *audio = 0; PsiMedia::RtpChannel *video = 0; if(transmitAudio) audio = rtp.audioRtpChannel(); if(transmitVideo) video = rtp.videoRtpChannel(); avTransmit = new AvTransmit(audio, video, sess->rtpChannel()); #ifdef USE_THREAD avTransmitThread = new AvTransmitThread(this); avTransmitThread->start(); avTransmitThread->handler->setAvTransmit(avTransmit); #endif if(transmitAudio) rtp.transmitAudio(); if(transmitVideo) rtp.transmitVideo(); transmitting = true; emit q->activated(); } void sess_remoteMediaUpdated() { setup_remote_media(); rtp.updatePreferences(); } }; AvCall::AvCall() { d = new AvCallPrivate(this); } AvCall::AvCall(const AvCall &from) : QObject(0) { Q_UNUSED(from); fprintf(stderr, "AvCall copy not supported\n"); abort(); } AvCall::~AvCall() { delete d; } XMPP::Jid AvCall::jid() const { if(d->sess) return d->sess->jid(); else return XMPP::Jid(); } AvCall::Mode AvCall::mode() const { return d->mode; } void AvCall::connectToJid(const XMPP::Jid &jid, Mode mode, int kbps) { d->peer = jid; d->mode = mode; d->bitrate = kbps; d->startOutgoing(); } void AvCall::accept(Mode mode, int kbps) { d->mode = mode; d->bitrate = kbps; d->accept(); } void AvCall::reject() { d->reject(); } void AvCall::setIncomingVideo(PsiMedia::VideoWidget *widget) { d->rtp.setVideoOutputWidget(widget); } QString AvCall::errorString() const { return d->errorString; } void AvCall::unlink() { d->unlink(); } //---------------------------------------------------------------------------- // AvCallManager //---------------------------------------------------------------------------- AvCallManagerPrivate::AvCallManagerPrivate(PsiAccount *_pa, AvCallManager *_q) : QObject(_q), q(_q), pa(_pa) { rtpManager = new JingleRtpManager(pa->client()); connect(rtpManager, SIGNAL(incomingReady()), SLOT(rtp_incomingReady())); } AvCallManagerPrivate::~AvCallManagerPrivate() { delete rtpManager; } void AvCallManagerPrivate::unlink(AvCall *call) { sessions.removeAll(call); } void AvCallManagerPrivate::rtp_incomingReady() { AvCall *call = new AvCall; call->d->manager = this; call->d->incoming = true; call->d->sess = rtpManager->takeIncoming(); sessions += call; if(!call->d->initIncoming()) { call->d->sess->reject(); delete call->d->sess; call->d->sess = 0; delete call; return; } pending += call; emit q->incomingReady(); } AvCallManager::AvCallManager(PsiAccount *pa) : QObject(0) { d = new AvCallManagerPrivate(pa, this); } AvCallManager::~AvCallManager() { delete d; } AvCall *AvCallManager::createOutgoing() { AvCall *call = new AvCall; call->d->manager = d; call->d->incoming = false; return call; } AvCall *AvCallManager::takeIncoming() { return d->pending.takeFirst(); } void AvCallManager::config() { // TODO: remove this function? } bool AvCallManager::isSupported() { ensureLoaded(); if(!QCA::isSupported("hmac(sha1)")) { printf("hmac support missing for voice calls, install qca-ossl\n"); return false; } return PsiMedia::isSupported(); } bool AvCallManager::isVideoSupported() { if(!isSupported()) return false; if(!QString::fromLatin1(qgetenv("PSI_ENABLE_VIDEO")).isEmpty()) return true; else return false; } void AvCallManager::setSelfAddress(const QHostAddress &addr) { d->rtpManager->setSelfAddress(addr); } void AvCallManager::setStunHost(const QString &host, int port) { d->rtpManager->setStunHost(host, port); } void AvCallManager::setBasePort(int port) { if(port == 0) port = -1; g_config->basePort = port; } void AvCallManager::setExternalAddress(const QString &host) { g_config->extHost = host; } void AvCallManager::setAudioOutDevice(const QString &id) { g_config->audioOutDeviceId = id; } void AvCallManager::setAudioInDevice(const QString &id) { g_config->audioInDeviceId = id; } void AvCallManager::setVideoInDevice(const QString &id) { g_config->videoInDeviceId = id; } #include "avcall.moc" psi-0.14/src/avcall/call.ui0000644000175000017500000000561111305557613013647 0ustar janjan Call 0 0 354 180 Dialog To: Use video Sending bandwidth: Call status Qt::Vertical 336 16 Qt::Horizontal Qt::Horizontal 111 28 &Reject &Accept BusyWidget QWidget
busywidget.h
1
le_to ck_useVideo cb_bandwidth pb_reject pb_accept
psi-0.14/src/avcall/calldlg.cpp0000644000175000017500000001367511305557613014514 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #include "calldlg.h" #include #include "ui_call.h" #include "avcall.h" #include "xmpp_client.h" #include "../psimedia/psimedia.h" #include "common.h" #include "psiaccount.h" #include "psioptions.h" // from opt_avcall.cpp extern void options_avcall_update(); // we have this so if the user plugs in a device, but never goes to the // options screen to select it, and then starts a call, it'll get used static void prep_device_opts() { options_avcall_update(); AvCallManager::setAudioOutDevice(PsiOptions::instance()->getOption("options.media.devices.audio-output").toString()); AvCallManager::setAudioInDevice(PsiOptions::instance()->getOption("options.media.devices.audio-input").toString()); AvCallManager::setVideoInDevice(PsiOptions::instance()->getOption("options.media.devices.video-input").toString()); } class CallDlg::Private : public QObject { Q_OBJECT public: CallDlg *q; Ui::Call ui; PsiAccount *pa; bool incoming; bool active; bool activated; AvCall *sess; PsiMedia::VideoWidget *vw_remote; Private(CallDlg *_q) : QObject(_q), q(_q), active(false), activated(false), sess(0) { ui.setupUi(q); q->setWindowTitle(tr("Voice Call")); ui.lb_bandwidth->setEnabled(false); ui.cb_bandwidth->setEnabled(false); connect(ui.ck_useVideo, SIGNAL(toggled(bool)), ui.lb_bandwidth, SLOT(setEnabled(bool))); connect(ui.ck_useVideo, SIGNAL(toggled(bool)), ui.cb_bandwidth, SLOT(setEnabled(bool))); ui.cb_bandwidth->addItem(tr("High (1Mbps)"), 1000); ui.cb_bandwidth->addItem(tr("Average (400Kbps)"), 400); ui.cb_bandwidth->addItem(tr("Low (160Kbps)"), 160); ui.cb_bandwidth->setCurrentIndex(1); if(!AvCallManager::isVideoSupported()) { ui.ck_useVideo->hide(); ui.lb_bandwidth->hide(); ui.cb_bandwidth->hide(); } connect(ui.pb_accept, SIGNAL(clicked()), SLOT(ok_clicked())); connect(ui.pb_reject, SIGNAL(clicked()), SLOT(cancel_clicked())); ui.pb_accept->setDefault(true); ui.pb_accept->setFocus(); q->resize(q->minimumSizeHint()); } ~Private() { if(sess) { if(active) sess->reject(); sess->setIncomingVideo(0); sess->disconnect(this); sess->unlink(); sess->deleteLater(); } } void setOutgoing(const XMPP::Jid &jid) { incoming = false; ui.le_to->setText(jid.full()); ui.pb_reject->setText(tr("&Close")); ui.pb_accept->setText(tr("C&all")); ui.lb_status->setText(tr("Ready")); } void setIncoming(AvCall *_sess) { incoming = true; sess = _sess; connect(sess, SIGNAL(activated()), SLOT(sess_activated())); connect(sess, SIGNAL(error()), SLOT(sess_error())); ui.lb_to->setText(tr("From:")); ui.le_to->setText(sess->jid().full()); ui.le_to->setReadOnly(true); if(sess->mode() == AvCall::Video || sess->mode() == AvCall::Both) { ui.ck_useVideo->setChecked(true); // video-only session, don't allow deselecting video if(sess->mode() == AvCall::Video) ui.ck_useVideo->setEnabled(false); } ui.lb_status->setText(tr("Accept call?")); } private slots: void ok_clicked() { AvCall::Mode mode = AvCall::Audio; int kbps = -1; if(ui.ck_useVideo->isChecked()) { mode = AvCall::Both; kbps = ui.cb_bandwidth->itemData(ui.cb_bandwidth->currentIndex()).toInt(); } if(!incoming) { ui.le_to->setReadOnly(true); ui.le_to->setEnabled(false); ui.ck_useVideo->setEnabled(false); ui.cb_bandwidth->setEnabled(false); ui.pb_accept->setEnabled(false); ui.pb_reject->setText(tr("&Cancel")); ui.pb_reject->setFocus(); ui.busy->start(); ui.lb_status->setText(tr("Calling...")); sess = pa->avCallManager()->createOutgoing(); connect(sess, SIGNAL(activated()), SLOT(sess_activated())); connect(sess, SIGNAL(error()), SLOT(sess_error())); active = true; sess->connectToJid(ui.le_to->text(), mode, kbps); } else { ui.le_to->setEnabled(false); ui.ck_useVideo->setEnabled(false); ui.cb_bandwidth->setEnabled(false); ui.pb_accept->setEnabled(false); ui.pb_reject->setText(tr("&Cancel")); ui.pb_reject->setFocus(); ui.busy->start(); ui.lb_status->setText(tr("Accepting...")); active = true; sess->accept(mode, kbps); } } void cancel_clicked() { if(sess && incoming && !active) sess->reject(); q->close(); } void sess_activated() { ui.le_to->setEnabled(true); ui.lb_bandwidth->hide(); ui.cb_bandwidth->hide(); if(sess->mode() == AvCall::Video || sess->mode() == AvCall::Both) { vw_remote = new PsiMedia::VideoWidget(q); replaceWidget(ui.ck_useVideo, vw_remote); sess->setIncomingVideo(vw_remote); vw_remote->setMinimumSize(320, 240); } else ui.ck_useVideo->hide(); ui.busy->stop(); ui.busy->hide(); ui.pb_accept->hide(); ui.pb_reject->setText(tr("&Hang up")); ui.lb_status->setText(tr("Call active")); activated = true; } void sess_error() { if(!activated) ui.busy->stop(); QMessageBox::information(q, tr("Call ended"), sess->errorString()); q->close(); } }; CallDlg::CallDlg(PsiAccount *pa, QWidget *parent) : QDialog(parent) { d = new Private(this); d->pa = pa; d->pa->dialogRegister(this); prep_device_opts(); } CallDlg::~CallDlg() { d->pa->dialogUnregister(this); delete d; } void CallDlg::setOutgoing(const XMPP::Jid &jid) { d->setOutgoing(jid); } void CallDlg::setIncoming(AvCall *sess) { d->setIncoming(sess); } #include "calldlg.moc" psi-0.14/src/avcall/jinglertp.h0000644000175000017500000000731511305557613014547 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #ifndef JINGLERTP_H #define JINGLERTP_H #include "jinglertptasks.h" class JingleRtpChannel; class JingleRtpPrivate; class JingleRtpChannelPrivate; class JingleRtpManagerPrivate; class JingleRtp : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, ErrorTimeout, ErrorICE }; enum Type { Audio = 0x01, Video = 0x02 }; class RtpPacket { public: Type type; int portOffset; QByteArray value; }; ~JingleRtp(); XMPP::Jid jid() const; QList remoteAudioPayloadTypes() const; QList remoteVideoPayloadTypes() const; int remoteMaximumBitrate() const; void setLocalAudioPayloadTypes(const QList &types); void setLocalVideoPayloadTypes(const QList &types); void setLocalMaximumBitrate(int kbps); void connectToJid(const XMPP::Jid &jid); void accept(int types); // intended types, so ICE knows what to do void reject(); // indicates that local media settings have changed. note that for // incoming sessions, this MUST be called. local media settings // are not assumed to be ready when accept() is called (basically // this allows ICE negotiation to run in parallel to the RTP engine // initialization). void localMediaUpdate(); Error errorCode() const; // this object is valid at construction time and initially lives in // JingleRtp's thread. it can be moved to another thread as long // it is moved back to JingleRtp's thread before destructing // JingleRtp. JingleRtpChannel *rtpChannel(); signals: void rejected(); void error(); void activated(); // indicates that remote media settings have changed. note that for // outgoing sessions, this must be listened to in order to get the // initial values. void remoteMediaUpdated(); private: Q_DISABLE_COPY(JingleRtp); friend class JingleRtpPrivate; friend class JingleRtpManager; friend class JingleRtpManagerPrivate; JingleRtp(); JingleRtpPrivate *d; }; class JingleRtpChannel : public QObject { Q_OBJECT public: bool packetsAvailable() const; JingleRtp::RtpPacket read(); void write(const JingleRtp::RtpPacket &packet); signals: void readyRead(); // note: this says nothing about the order packets were written void packetsWritten(int count); private: Q_DISABLE_COPY(JingleRtpChannel); friend class JingleRtpChannelPrivate; friend class JingleRtpPrivate; JingleRtpChannel(); ~JingleRtpChannel(); JingleRtpChannelPrivate *d; }; class JingleRtpManager : public QObject { Q_OBJECT public: JingleRtpManager(XMPP::Client *client); ~JingleRtpManager(); JingleRtp *createOutgoing(); JingleRtp *takeIncoming(); void setSelfAddress(const QHostAddress &addr); void setExternalAddress(const QString &host); // resolved locally void setStunHost(const QString &host, int port); void setBasePort(int port); signals: void incomingReady(); private: Q_DISABLE_COPY(JingleRtpManager); friend class JingleRtpManagerPrivate; friend class JingleRtp; friend class JingleRtpPrivate; JingleRtpManagerPrivate *d; }; #endif psi-0.14/src/avcall/calldlg.h0000644000175000017500000000205311305557613014145 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #ifndef CALLDLG_H #define CALLDLG_H #include namespace XMPP { class Jid; } class PsiAccount; class AvCall; class CallDlg : public QDialog { Q_OBJECT public: CallDlg(PsiAccount *pa, QWidget *parent = 0); ~CallDlg(); void setOutgoing(const XMPP::Jid &jid); void setIncoming(AvCall *sess); private: class Private; Private *d; }; #endif psi-0.14/src/avcall/avcall.pri0000644000175000017500000000036111305557613014350 0ustar janjanQT *= network HEADERS += \ $$PWD/jinglertptasks.h \ $$PWD/jinglertp.h \ $$PWD/avcall.h \ $$PWD/calldlg.h SOURCES += \ $$PWD/jinglertptasks.cpp \ $$PWD/jinglertp.cpp \ $$PWD/avcall.cpp \ $$PWD/calldlg.cpp FORMS += \ $$PWD/call.ui psi-0.14/src/avcall/jinglertptasks.h0000644000175000017500000000655311305557613015620 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #ifndef JINGLERTPTASKS_H #define JINGLERTPTASKS_H #include #include #include "xmpp_jid.h" #include "xmpp_task.h" #include "iris/ice176.h" class JingleRtpPayloadType { public: class Parameter { public: QString name; QString value; }; int id; QString name; int clockrate; int channels; int ptime; int maxptime; QList parameters; JingleRtpPayloadType() : id(-1), clockrate(-1), channels(-1), ptime(-1), maxptime(-1) { } }; class JingleRtpCrypto { public: QString suite; QString keyParams; QString sessionParams; int tag; }; class JingleRtpDesc { public: QString media; bool haveSsrc; quint32 ssrc; QList payloadTypes; int bitrate; // in Kbps bool encryptionRequired; QList cryptoList; JingleRtpDesc() : haveSsrc(false), ssrc(0), bitrate(-1), encryptionRequired(false) { } }; class JingleRtpRemoteCandidate { public: int component; QHostAddress addr; int port; JingleRtpRemoteCandidate() : component(-1), port(-1) { } }; class JingleRtpTrans { public: QString user; QString pass; QList candidates; QList remoteCandidates; }; class JingleRtpContent { public: QString creator; QString disposition; QString name; QString senders; JingleRtpDesc desc; JingleRtpTrans trans; }; class JingleRtpReason { public: enum Condition { AlternativeSession, Busy, Cancel, ConnectivityError, Decline, Expired, FailedApplication, FailedTransport, GeneralError, Gone, IncompatibleParameters, MediaError, SecurityError, Success, Timeout, UnsupportedApplications, UnsupportedTransports }; Condition condition; QString text; JingleRtpReason() : condition((Condition)-1) { } }; class JingleRtpEnvelope { public: QString action; QString initiator; QString responder; QString sid; QList contentList; JingleRtpReason reason; }; class JT_JingleRtp : public XMPP::Task { Q_OBJECT public: JT_JingleRtp(XMPP::Task *parent); ~JT_JingleRtp(); void request(const XMPP::Jid &to, const JingleRtpEnvelope &envelope); virtual void onGo(); virtual bool take(const QDomElement &x); private: QDomElement iq_; XMPP::Jid to_; }; class JT_PushJingleRtp : public XMPP::Task { Q_OBJECT public: JT_PushJingleRtp(XMPP::Task *parent); ~JT_PushJingleRtp(); void respondSuccess(const XMPP::Jid &to, const QString &id); void respondError(const XMPP::Jid &to, const QString &id, int code, const QString &str); virtual bool take(const QDomElement &e); signals: void incomingRequest(const XMPP::Jid &from, const QString &iq_id, const JingleRtpEnvelope &envelope); }; #endif psi-0.14/src/passphrasedlg.cpp0000644000175000017500000000252011305557613014473 0ustar janjan/* * passphrasedlg.cpp - class to handle entering of OpenPGP passphrase * Copyright (C) 2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "passphrasedlg.h" PassphraseDlg::PassphraseDlg(QWidget *parent) : QDialog (parent) { ui_.setupUi(this); setModal(false); connect(ui_.pb_ok, SIGNAL(clicked()), SLOT(accept())); connect(ui_.pb_cancel, SIGNAL(clicked()), SLOT(reject())); } void PassphraseDlg::promptPassphrase(const QString& name) { setWindowTitle(tr("%1: OpenPGP Passphrase").arg(name)); resize(minimumSizeHint()); } QString PassphraseDlg::getPassphrase() const { return ui_.le_pass->text(); } psi-0.14/src/adhoc_fileserver.cpp0000644000175000017500000000522011305557613015137 0ustar janjan/* * adhoc_fileserver.cpp - Implementation of a personal ad-hoc fileserver * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "psiaccount.h" #include "adhoc_fileserver.h" #include "xmpp_xdata.h" using namespace XMPP; bool AHFileServer::isAllowed(const Jid& j) const { return manager()->account()->jid().compare(j,false); } AHCommand AHFileServer::execute(const AHCommand& c, const Jid& requester) { // Extract the file QString file; if (c.hasData()) { QString fileName, curDir; XData::FieldList fl = c.data().fields(); for (unsigned int i=0; i < fl.count(); i++) { if (fl[i].var() == "file" && !(fl[i].value().isEmpty())) { file = fl[i].value().first(); } } } else { file = QDir::currentDirPath(); } if (QFileInfo(file).isDir()) { // Return a form with a filelist XData form; form.setTitle(QObject::tr("Choose file")); form.setInstructions(QObject::tr("Choose a file")); form.setType(XData::Data_Form); XData::FieldList fields; XData::Field files_field; files_field.setType(XData::Field::Field_ListSingle); files_field.setVar("file"); files_field.setLabel(QObject::tr("File")); files_field.setRequired(true); XData::Field::OptionList file_options; QDir d(file); //d.setFilter(QDir::Files|QDir::Hidden|QDir::NoSymLinks); QStringList l = d.entryList(); for (QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { XData::Field::Option file_option; QFileInfo fi(QDir(file).filePath(*it)); file_option.label = *it + (fi.isDir() ? QString(" [DIR]") : QString(" (%1 bytes)").arg(QString::number(fi.size()))); file_option.value = QDir(file).absFilePath(*it); file_options += file_option; } files_field.setOptions(file_options); fields += files_field; form.setFields(fields); return AHCommand::formReply(c, form); } else { QStringList l(file); manager()->account()->sendFiles(requester,l,true); return AHCommand::completedReply(c); } } psi-0.14/src/ahcformdlg.cpp0000644000175000017500000001217611305557613013751 0ustar janjan/* * ahcformdlg.cpp - Ad-Hoc Command Form Dialog * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "ahcformdlg.h" #include #include #include #include #include "ahcommand.h" #include "ahcexecutetask.h" #include "xdata_widget.h" #include "xmpp_client.h" #include "psiaccount.h" #include "busywidget.h" AHCFormDlg::AHCFormDlg(const AHCommand& r, const Jid& receiver, XMPP::Client* client, bool final) : QDialog(0) , pb_prev_(0) , pb_next_(0) , pb_complete_(0) , pb_cancel_(0) , xdata_(0) , receiver_(receiver) , client_(client) { ui_.setupUi(this); setAttribute(Qt::WA_DeleteOnClose); // Save node node_ = r.node(); sessionId_ = r.sessionId(); ui_.lb_instructions->setText(r.data().instructions()); ui_.lb_instructions->setVisible(!r.data().instructions().isEmpty()); // XData form xdata_ = new XDataWidget(this); xdata_->setFields(r.data().fields()); ui_.scrollArea->setWidget(xdata_); ui_.busy->setVisible(!final); if (!final) { if (r.actions().empty()) { // Single stage dialog pb_complete_ = ui_.buttonBox->addButton(tr("Finish"), QDialogButtonBox::AcceptRole); connect(pb_complete_,SIGNAL(clicked()),SLOT(doExecute())); } else { // Multi-stage dialog // Previous pb_prev_ = ui_.buttonBox->addButton(tr("Previous"), QDialogButtonBox::ActionRole); if (r.actions().contains(AHCommand::Prev)) { if (r.defaultAction() == AHCommand::Prev) { pb_prev_->setDefault(true); pb_prev_->setFocus(); } connect(pb_prev_,SIGNAL(clicked()),SLOT(doPrev())); pb_prev_->setEnabled(true); } else { pb_prev_->setEnabled(false); } // Next pb_next_ = ui_.buttonBox->addButton(tr("Next"), QDialogButtonBox::ActionRole); if (r.actions().contains(AHCommand::Next)) { if (r.defaultAction() == AHCommand::Next) { connect(pb_next_,SIGNAL(clicked()),SLOT(doExecute())); pb_next_->setDefault(true); pb_next_->setFocus(); } else { connect(pb_next_,SIGNAL(clicked()),SLOT(doNext())); } pb_next_->setEnabled(true); } else { pb_next_->setEnabled(false); } // Complete pb_complete_ = ui_.buttonBox->addButton(tr("Finish"), QDialogButtonBox::AcceptRole); if (r.actions().contains(AHCommand::Complete)) { if (r.defaultAction() == AHCommand::Complete) { connect(pb_complete_,SIGNAL(clicked()),SLOT(doExecute())); pb_complete_->setDefault(true); pb_complete_->setFocus(); } else { connect(pb_complete_,SIGNAL(clicked()),SLOT(doComplete())); } pb_complete_->setEnabled(true); } else { pb_complete_->setEnabled(false); } } pb_cancel_ = ui_.buttonBox->addButton(QDialogButtonBox::Cancel); connect(pb_cancel_, SIGNAL(clicked()),SLOT(doCancel())); } else { pb_complete_ = ui_.buttonBox->addButton(QDialogButtonBox::Ok); connect(pb_complete_,SIGNAL(clicked()),SLOT(close())); } if (!r.data().title().isEmpty()) { setWindowTitle(QString("%1 (%2)").arg(r.data().title()).arg(receiver.full())); } else { setWindowTitle(QString("%1").arg(receiver.full())); } adjustSize(); } void AHCFormDlg::doPrev() { ui_.busy->start(); AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_,AHCommand::Prev), client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(commandExecuted())); t->go(true); } void AHCFormDlg::doNext() { ui_.busy->start(); AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_,AHCommand::Next),client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(commandExecuted())); t->go(true); } void AHCFormDlg::doExecute() { ui_.busy->start(); AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_),client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(commandExecuted())); t->go(true); } void AHCFormDlg::doComplete() { ui_.busy->start(); AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_,AHCommand::Complete), client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(commandExecuted())); t->go(true); } void AHCFormDlg::doCancel() { ui_.busy->start(); AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,sessionId_,AHCommand::Cancel), client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(commandExecuted())); t->go(true); } void AHCFormDlg::commandExecuted() { ui_.busy->stop(); close(); } XData AHCFormDlg::data() const { XData x; x.setFields(xdata_->fields()); x.setType(XData::Data_Submit); return x; } psi-0.14/src/pubsubsubscription.h0000644000175000017500000000261211305557613015247 0ustar janjan/* * pubsubsubscription.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PUBSUBSUBSCRIPTION_H #define PUBSUBSUBSCRIPTION_H #include class QDomElement; class QDomDocument; class PubSubSubscription { public: enum State { None, Pending, Unconfigured, Subscribed }; PubSubSubscription(); PubSubSubscription(const QDomElement& e); const QString& jid() const; const QString& node() const; State state() const; bool isNull() const; void fromXml(const QDomElement& e); QDomElement toXml(QDomDocument& doc) const; bool operator==(const PubSubSubscription&) const; bool operator!=(const PubSubSubscription&) const; private: QString jid_, node_; State state_; }; #endif psi-0.14/src/actionlist.cpp0000644000175000017500000001023011305557613014001 0ustar janjan/* * actionlist.cpp - the customizeable action list * Copyright (C) 2004 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "actionlist.h" #include #include "iconaction.h" //---------------------------------------------------------------------------- // ActionList //---------------------------------------------------------------------------- class ActionList::Private : public QObject { Q_OBJECT public: Private() { } Private( const Private & ); QString name; int id; QStringList sortedActions; QHash actions; bool autoDeleteActions; public slots: void actionDestroyed(QObject *); }; ActionList::ActionList( QString name, int id, bool autoDelete ) : QObject() { d = new Private(); d->autoDeleteActions = autoDelete; d->name = name; d->id = id; } ActionList::ActionList( const ActionList &from ) : QObject() { d = new Private( *from.d ); } ActionList::~ActionList() { delete d; } QString ActionList::name() const { return d->name; } int ActionList::id() const { return d->id; } IconAction *ActionList::action( QString name ) const { return d->actions[name]; } QStringList ActionList::actions() const { return d->sortedActions; } void ActionList::addAction( QString name, IconAction *action ) { d->sortedActions << name; if ( action ) { action->setObjectName( name ); d->actions.insert( name, action ); d->connect( action, SIGNAL( destroyed(QObject *) ), d, SLOT( actionDestroyed(QObject *) ) ); } } void ActionList::clear() { if (d->autoDeleteActions) qDeleteAll(d->actions); d->actions.clear(); } ActionList::Private::Private( const Private &from ) : QObject() { name = from.name; id = from.id; actions = from.actions; autoDeleteActions = from.autoDeleteActions; sortedActions = from.sortedActions; } void ActionList::Private::actionDestroyed(QObject *obj) { actions.remove( obj->objectName() ); } //---------------------------------------------------------------------------- // MetaActionList //---------------------------------------------------------------------------- class MetaActionList::Private { public: Private() { } QList lists; }; MetaActionList::MetaActionList() : QObject() { d = new Private(); } MetaActionList::~MetaActionList() { while (!d->lists.isEmpty()) delete d->lists.takeFirst(); delete d; } ActionList *MetaActionList::actionList( QString name ) const { foreach(ActionList* a, d->lists) { if (a->name() == name) return a; } return 0; } QList MetaActionList::actionLists( int id ) const { QList list; for ( int i = 0; i < 32; i++ ) { if ( !(id & ( 1 << i )) ) continue; foreach(ActionList* a, d->lists) { if ( a->id() & ( 1 << i ) ) list.append(a); } } return list; } ActionList MetaActionList::suitableActions( int id ) const { QList lists = actionLists( id ); ActionList actions("", 0, false); foreach(ActionList* list, lists) { QStringList actionList = list->actions(); QStringList::Iterator it2 = actionList.begin(); for ( ; it2 != actionList.end(); ++it2 ) actions.addAction( *it2, list->action( *it2 ) ); } return actions; } QStringList MetaActionList::actionLists() const { QStringList names; foreach(ActionList* l, d->lists) names << l->name(); return names; } void MetaActionList::addList( ActionList *list ) { if ( list ) d->lists.append( list ); } void MetaActionList::clear() { foreach(ActionList* l, d->lists) { l->clear(); } } #include "actionlist.moc" psi-0.14/src/psihttpauthrequest.h0000644000175000017500000000065411305557613015274 0ustar janjan#ifndef PSIHTTPAUTHREQUEST_H #define PSIHTTPAUTHREQUEST_H #include "xmpp_stanza.h" #include "xmpp_httpauthrequest.h" class PsiHttpAuthRequest : public XMPP::HttpAuthRequest { public: PsiHttpAuthRequest() {} PsiHttpAuthRequest(const XMPP::HttpAuthRequest &request, const XMPP::Stanza &stanza) : HttpAuthRequest(request), s(stanza) {} const XMPP::Stanza & stanza() const { return s; } private: XMPP::Stanza s; }; #endif psi-0.14/src/plugins/0000755000175000017500000000000011305557613012611 5ustar janjanpsi-0.14/src/plugins/windows/0000755000175000017500000000000011305557613014303 5ustar janjanpsi-0.14/src/plugins/windows/snarl/0000755000175000017500000000000011305557613015422 5ustar janjanpsi-0.14/src/plugins/windows/snarl/SnarlInterface.h0000644000175000017500000000257611305557613020505 0ustar janjan#ifndef SNARL_INTERFACE #define SNARL_INTERFACE #include #include class SnarlInterface { public: static const unsigned int SNARL_STRING_LENGTH = 1024; static const int SNARL_LAUNCHED = 1; static const int SNARL_QUIT = 2; static const int SNARL_NOTIFICATION_CLICKED = 32; static const int SNARL_NOTIFICATION_TIMED_OUT = 33; static const int SNARL_NOTIFICATION_ACK = 34; enum SNARL_COMMANDS { SNARL_SHOW = 1, SNARL_HIDE, SNARL_UPDATE, SNARL_IS_VISIBLE, SNARL_GET_VERSION, SNARL_REGISTER_CONFIG_WINDOW, SNARL_REVOKE_CONFIG_WINDOW }; struct SNARLSTRUCT { SNARL_COMMANDS cmd; long id; long timeout; long lngData2; char title[SNARL_STRING_LENGTH]; char text[SNARL_STRING_LENGTH]; char icon[SNARL_STRING_LENGTH]; }; SnarlInterface(); ~SnarlInterface(); long snShowMessage(std::string title, std::string text, long timeout, std::string iconPath, HWND hWndReply, long uReplyMsg); bool snHideMessage(long id); bool snIsMessageVisible(long id); bool snUpdateMessage(long id, std::string title, std::string text); bool snRegisterConfig(HWND hWnd, std::string appName, long replyMsg); bool snRevokeConfig(HWND hWnd); bool snGetVersion(int* major, int* minor); long snGetGlobalMsg(); private: std::string SNARL_GLOBAL_MESSAGE; long send(SNARLSTRUCT snarlStruct); }; #endif // SNARL_INTERFACE psi-0.14/src/plugins/windows/snarl/SnarlInterface.cpp0000644000175000017500000000746211305557613021037 0ustar janjan#include "SnarlInterface.h" #include #include #include using namespace std; SnarlInterface::SnarlInterface() { SNARL_GLOBAL_MESSAGE = "SnarlGlobalMessage"; } SnarlInterface::~SnarlInterface() { } long SnarlInterface::snShowMessage(std::string title, std::string text, long timeout, std::string iconPath, HWND hWndReply, long uReplyMsg) { SNARLSTRUCT snarlStruct; snarlStruct.cmd = SNARL_SHOW; if (title.length() > SNARL_STRING_LENGTH) { strcpy(snarlStruct.title, (title.substr(0, SNARL_STRING_LENGTH-1)).c_str()); } else { strcpy(snarlStruct.title, title.c_str()); } if (text.length() > SNARL_STRING_LENGTH) { strcpy(snarlStruct.text, (text.substr(0, SNARL_STRING_LENGTH-1)).c_str()); } else { strcpy(snarlStruct.text, text.c_str()); } if (iconPath.length() > SNARL_STRING_LENGTH) { strcpy(snarlStruct.icon, (iconPath.substr(0, SNARL_STRING_LENGTH-1)).c_str()); } else { strcpy(snarlStruct.icon, iconPath.c_str()); } snarlStruct.timeout = timeout; snarlStruct.lngData2 = reinterpret_cast(hWndReply); snarlStruct.id = uReplyMsg; return send(snarlStruct); } bool SnarlInterface::snHideMessage(long id) { SNARLSTRUCT snarlStruct; snarlStruct.id = id; snarlStruct.cmd = SNARL_HIDE; return static_cast(send(snarlStruct)); } bool SnarlInterface::snIsMessageVisible(long id) { SNARLSTRUCT snarlStruct; snarlStruct.id = id; snarlStruct.cmd = SNARL_IS_VISIBLE; return static_cast(send(snarlStruct)); } bool SnarlInterface::snUpdateMessage(long id, std::string title, std::string text) { SNARLSTRUCT snarlStruct; snarlStruct.id = id; snarlStruct.cmd = SNARL_UPDATE; if (title.length() > SNARL_STRING_LENGTH) { strcpy(snarlStruct.title, (title.substr(0, SNARL_STRING_LENGTH-1)).c_str()); } else { strcpy(snarlStruct.title, title.c_str()); } if (text.length() > SNARL_STRING_LENGTH) { strcpy(snarlStruct.text, (text.substr(0, SNARL_STRING_LENGTH-1)).c_str()); } else { strcpy(snarlStruct.text, text.c_str()); } return static_cast(send(snarlStruct)); } bool SnarlInterface::snRegisterConfig(HWND hWnd, std::string appName, long replyMsg) { SNARLSTRUCT snarlStruct; snarlStruct.cmd = SNARL_REGISTER_CONFIG_WINDOW; snarlStruct.lngData2 = reinterpret_cast(hWnd); snarlStruct.id = replyMsg; if (appName.length() > SNARL_STRING_LENGTH) { strcpy(snarlStruct.title, (appName.substr(0, SNARL_STRING_LENGTH-1)).c_str()); } else { strcpy(snarlStruct.title, appName.c_str()); } return static_cast(send(snarlStruct)); } bool SnarlInterface::snRevokeConfig(HWND hWnd) { SNARLSTRUCT snarlStruct; snarlStruct.cmd = SNARL_REVOKE_CONFIG_WINDOW; snarlStruct.lngData2 = reinterpret_cast(hWnd); return static_cast(send(snarlStruct)); } bool SnarlInterface::snGetVersion(int* major, int* minor) { SNARLSTRUCT snarlStruct; snarlStruct.cmd = SNARL_GET_VERSION; long versionInfo = send(snarlStruct); if (versionInfo) { int maj = static_cast(HIWORD(versionInfo)); *major = maj; int min = static_cast(LOWORD(versionInfo)); *minor = min; return true; } return false; } long SnarlInterface::snGetGlobalMsg() { std::wstring tmp; tmp= QString(SNARL_GLOBAL_MESSAGE.c_str()).toStdWString(); return RegisterWindowMessage(tmp.c_str()); } long SnarlInterface::send(SNARLSTRUCT snarlStruct) { HWND hWnd = FindWindow(NULL, QString("Snarl").toStdWString().c_str()); if (IsWindow(hWnd)) { COPYDATASTRUCT cds; cds.dwData = 2; cds.cbData = sizeof(snarlStruct); cds.lpData = &snarlStruct; LRESULT lr = SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&cds); if (lr) { return lr; } } return 0; } psi-0.14/src/plugins/windows/snarl/snarlplugin.pro0000644000175000017500000000031511305557613020501 0ustar janjaninclude(../../plugins.pri) SNARL_PATH = D:/devel/snarl/1.1/sdk/include/C++-kev INCLUDEPATH += $$PSI_PATH \ $$SNARL_PATH SOURCES += snarlplugin.cpp \ SnarlInterface.cpp HEADERS += SnarlInterface.h psi-0.14/src/plugins/windows/snarl/snarlplugin.cpp0000644000175000017500000000461511305557613020472 0ustar janjan/* * snarlplugin.cpp - Psi plugin to display notifs via snarl * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "psiplugin.h" #include "SnarlInterface.h" class SnarlPlugin : public QObject, public PsiPlugin { Q_OBJECT Q_INTERFACES(PsiPlugin) public: SnarlPlugin(); ~SnarlPlugin(); virtual QString name() const; virtual QString shortName() const; virtual void message( const QString& message, const QString& fromJid, const QString& fromDisplay); private: SnarlInterface* snarl_; }; Q_EXPORT_PLUGIN(SnarlPlugin); SnarlPlugin::SnarlPlugin() : PsiPlugin() { snarl_ = new SnarlInterface(); int major=0; int minor=0; snarl_->snGetVersion(&major, &minor); if (major==0 && minor==0) QMessageBox::information(0,"Snarl",QString("Snarl is not running, so notifications are disabled until it is started")); } SnarlPlugin::~SnarlPlugin() { delete snarl_; } QString SnarlPlugin::name() const { return "Snarl Plugin"; } QString SnarlPlugin::shortName() const { return "snarl"; } void SnarlPlugin::message( const QString& message, const QString& fromJid, const QString& fromDisplay) { QString text=QString("%1 says\n %2").arg(fromDisplay).arg(message); QString caption=QString("Received message"); QString icon= "D:\\devel\\psi-plugins\\win32\\psi\\iconsets\\system\\default\\icon_48.png"; snarl_->snShowMessage(caption.toStdString(), text.toStdString(), 10, icon.toStdString(), 0, 0); } #include "snarlplugin.moc" psi-0.14/src/plugins/plugins.pri0000644000175000017500000000057011305557613015010 0ustar janjanINCLUDEPATH += $$PWD/include HEADERS += \ $$PWD/include/psiplugin.h \ $$PWD/include/stanzafilter.h \ $$PWD/include/stanzasender.h \ $$PWD/include/stanzasendinghost.h \ $$PWD/include/iqfilter.h \ $$PWD/include/iqnamespacefilter.h \ $$PWD/include/iqfilteringhost.h \ $$PWD/include/eventfilter.h \ $$PWD/include/optionaccessor.h \ $$PWD/include/optionaccessinghost.h psi-0.14/src/plugins/include/0000755000175000017500000000000011305557613014234 5ustar janjanpsi-0.14/src/plugins/include/psiplugin.h0000644000175000017500000000510311305557613016416 0ustar janjan/* * psiplugin.h - Psi plugin interface * Copyright (C) 2006-2008 Kevin Smith, Maciej Niedzielski * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIPLUGIN_H #define PSIPLUGIN_H class QWidget; #include /** * \brief An abstract class for implementing a plugin */ class PsiPlugin { public: virtual ~PsiPlugin() {} /** * \brief Plugin Name * The full name of the plugin. * \return Plugin name */ virtual QString name() const = 0; /** * \brief Short name for the plugin * This is the short name of the plugin, used for options structures. * It must consist of only alphanumerics (no spaces or punctuation). * \return Short plugin name */ virtual QString shortName() const = 0; /** * \brief Plugin version * Free-form string of the plugin version. Human readable * \return Plugin version string */ virtual QString version() const = 0; /** * \brief Plugin options widget * This method is called by the Psi options system to retrieve * a widget containing the options for this plugin. * This will then be embedded in the options dialog, so this * should be considered when designing the widget. Should return * NULL when there are no user-configurable options. The calling method * is responsible for deleting the options. * * TODO: make sure this is really deleted, etc */ virtual QWidget* options() const = 0; /** * \brief Enable plugin * \return true if plugin was successfully enabled */ virtual bool enable() = 0; /** * \brief Disable plugin * \return true if plugin was successfully disabled */ virtual bool disable() = 0; }; Q_DECLARE_INTERFACE(PsiPlugin, "org.psi-im.PsiPlugin/0.3"); #endif psi-0.14/src/plugins/include/iqfilteringhost.h0000644000175000017500000000130011305557613017612 0ustar janjan#ifndef IQFILTERINGHOST_H #define IQFILTERINGHOST_H #include #include class IqNamespaceFilter; class IqFilteringHost { public: virtual ~IqFilteringHost() {} virtual void addIqNamespaceFilter(const QString& ns, IqNamespaceFilter* filter) = 0; virtual void addIqNamespaceFilter(const QRegExp& ns, IqNamespaceFilter* filter) = 0; virtual void removeIqNamespaceFilter(const QString& ns, IqNamespaceFilter* filter) = 0; virtual void removeIqNamespaceFilter(const QRegExp& ns, IqNamespaceFilter* filter) = 0; }; // TODO(mck): iq results/error may contain no namespaced element - think about this!! Q_DECLARE_INTERFACE(IqFilteringHost, "org.psi-im.IqFilteringHost/0.1"); #endif psi-0.14/src/plugins/include/iqnamespacefilter.h0000644000175000017500000000075211305557613020105 0ustar janjan#ifndef IQNAMESPACEFILTER_H #define IQNAMESPACEFILTER_H #include class IqNamespaceFilter { public: virtual ~IqNamespaceFilter() {} virtual bool iqGet(int account, const QDomElement& xml) = 0; virtual bool iqSet(int account, const QDomElement& xml) = 0; virtual bool iqResult(int account, const QDomElement& xml) = 0; virtual bool iqError(int account, const QDomElement& xml) = 0; }; Q_DECLARE_INTERFACE(IqNamespaceFilter, "org.psi-im.IqNamespaceFilter/0.1"); #endif psi-0.14/src/plugins/include/optionaccessinghost.h0000644000175000017500000000105511305557613020474 0ustar janjan#ifndef OPTIONACCESSINGHOST_H #define OPTIONACCESSINGHOST_H #include #include class OptionAccessingHost { public: virtual ~OptionAccessingHost() {} virtual void setPluginOption(const QString& option, const QVariant& value) = 0; virtual QVariant getPluginOption(const QString& option) = 0; virtual void setGlobalOption(const QString& option, const QVariant& value) = 0; virtual QVariant getGlobalOption(const QString& option) = 0; }; Q_DECLARE_INTERFACE(OptionAccessingHost, "org.psi-im.OptionAccessingHost/0.1"); #endif psi-0.14/src/plugins/include/optionaccessor.h0000644000175000017500000000061211305557613017437 0ustar janjan#ifndef OPTIONACCESSOR_H #define OPTIONACCESSOR_H #include //#include class OptionAccessingHost; class OptionAccessor { public: virtual ~OptionAccessor() {} virtual void setOptionAccessingHost(OptionAccessingHost* host) = 0; virtual void optionChanged(const QString& option) = 0; }; Q_DECLARE_INTERFACE(OptionAccessor, "org.psi-im.OptionAccessor/0.1"); #endif psi-0.14/src/plugins/include/stanzafilter.h0000644000175000017500000000051111305557613017110 0ustar janjan#ifndef STANZAFILTER_H #define STANZAFILTER_H #include class StanzaFilter { public: virtual ~StanzaFilter() {} // true = handled, don't pass to next handler virtual bool incomingStanza(int account, const QDomElement& xml) = 0; }; Q_DECLARE_INTERFACE(StanzaFilter, "org.psi-im.StanzaFilter/0.1"); #endif psi-0.14/src/plugins/include/eventfilter.h0000644000175000017500000000066311305557613016741 0ustar janjan#ifndef EVENTFILTER_H #define EVENTFILTER_H #include class EventFilter { public: virtual ~EventFilter() {} // true = handled, don't pass to next handler virtual bool processEvent(int account, const QDomElement& e) = 0; virtual bool processMessage(int account, const QString& fromJid, const QString& body, const QString& subject) = 0; }; Q_DECLARE_INTERFACE(EventFilter, "org.psi-im.EventFilter/0.1"); #endif psi-0.14/src/plugins/include/stanzasender.h0000644000175000017500000000042111305557613017103 0ustar janjan#ifndef STANZASENDER_H #define STANZASENDER_H class StanzaSendingHost; class StanzaSender { public: virtual ~StanzaSender() {} virtual void setStanzaSendingHost(StanzaSendingHost *host) = 0; }; Q_DECLARE_INTERFACE(StanzaSender, "org.psi-im.StanzaSender/0.1"); #endifpsi-0.14/src/plugins/include/stanzasendinghost.h0000644000175000017500000000106111305557613020151 0ustar janjan#ifndef STANZASENDINGHOST_H #define STANZASENDINGHOST_H #include #include class StanzaSendingHost { public: virtual ~StanzaSendingHost() {} virtual void sendStanza(int account, const QDomElement& xml) = 0; virtual void sendStanza(int account, const QString& xml) = 0; virtual void sendMessage(int account, const QString& to, const QString& body, const QString& subject, const QString& type) = 0; virtual QString uniqueId(int account) = 0; }; Q_DECLARE_INTERFACE(StanzaSendingHost, "org.psi-im.StanzaSendingHost/0.1"); #endif psi-0.14/src/plugins/include/iqfilter.h0000644000175000017500000000036311305557613016226 0ustar janjan#ifndef IQFILTER_H #define IQFILTER_H class IqFilteringHost; class IqFilter { public: virtual ~IqFilter() {} virtual void setIqFilteringHost(IqFilteringHost *host) = 0; }; Q_DECLARE_INTERFACE(IqFilter, "org.psi-im.IqFilter/0.1"); #endifpsi-0.14/src/plugins/generic/0000755000175000017500000000000011305557613014225 5ustar janjanpsi-0.14/src/plugins/generic/python/0000755000175000017500000000000011305557613015546 5ustar janjanpsi-0.14/src/plugins/generic/python/xmlmessage.py0000644000175000017500000000625011305557613020270 0ustar janjanimport xml.parsers.expat, sys,traceback class xmlobj(object): def __init__(self): self.name = '' self.cdata = '' self.attrs = {} self.subs = [] # list of subs self.subnames = {} # 2nd way to access subs self.parent = None self.index = -1 def __getattr__(self, name): return self.subnames.get(name, None) def sub(self, name): return self.subnames.get(name, None) def __getitem__(self, key): if key == '_cdata': return self.cdata return self.attrs.get(key,'') def __iter__(self): return self def next(self): self.index += 1 if self.index > len(self.subs) - 1: raise StopIteration, "Looped through all sub elements." return self.subs[self.index] def getxml(self, depth = 0): tab = '\t' * depth attrstring = '' for attr_name in self.attrs: attrstring += ' %s="%s"' % (attr_name, self.attrs[attr_name]) xmlstring = "%s<%s%s" % (tab, self.name, attrstring) if self.cdata == '' and self.subs == []: xmlstring += '/>' else: xmlstring += '>' if self.cdata != '': xmlstring += '\n%s' % self.cdata for sub in self.subs: xmlstring += "\n" + sub.getxml(depth + 1) xmlstring += "\n%s" % (tab,self.name) return xmlstring class xmllib(object): def __init__(self, xml_file, type='string'): self.parser = xml.parsers.expat.ParserCreate() self.parser.CharacterDataHandler = self.h_data self.parser.StartElementHandler = self.h_se self.parser.EndElementHandler = self.h_ee self.root = xmlobj() self.element = self.root try: if type == 'file': self.parser.ParseFile(open(xml_file, 'r')) elif type == 'string': self.parser.Parse(xml_file) except xml.parsers.expat.ExpatError: #exception, tb,rowcol = traceback.format_exc().split('\n')[-2].split(':',3) ##print "-" * 80 #print "XML Error!\n%s on %s\n%s" % (xml_file, rowcol.strip(), tb.strip()) #print "-" * 80 print "Expat Parsing Error." sys.exit() def h_se(self, name, attrs): newelement = xmlobj() # start a new element newelement.name = name # name it newelement.attrs = attrs # assign attributes newelement.parent = self.element # assign the current element as it's parent self.element.subs.append(newelement) # apparend to subs of the current element # appending subname if not self.element.subnames.has_key(name): self.element.subnames[name] = [] self.element.subnames[name].append(newelement) # ---------------- self.element = newelement # assign the new element as the current one def h_data(self, data): self.element.cdata += data # assign cdata def h_ee(self, name): self.element.cdata = self.element.cdata.strip() self.element = self.element.parent # element is done, set current to parent element def getroot(self): return self.root.subs[0] def loadfile(file): xmlparser = xmllib(file) return xmlparser.getroot() if __name__ == '__main__': message = """ Google Federated! I can totally send you messages from gmail now! """ xmlparser = xmllib(message) xml = xmlparser.getroot() for sub in xml: print sub.name print sub['_cdata'] print xml.sub('body')[0]['_cdata'] print xml['from'] psi-0.14/src/plugins/generic/python/pythonplugin.pro0000644000175000017500000000034211305557613021027 0ustar janjaninclude(../../plugins.pri) PYTHON_PATH = /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Python.framework/Versions/2.3/include/python2.3/ LIBS += -lpython INCLUDEPATH += $$PYTHON_PATH SOURCES += pythonplugin.cpp psi-0.14/src/plugins/generic/python/messagescript.py0000644000175000017500000000613611305557613020777 0ustar janjanimport xml.parsers.expat, sys,traceback class xmlobj(object): def __init__(self): self.name = '' self.cdata = '' self.attrs = {} self.subs = [] # list of subs self.subnames = {} # 2nd way to access subs self.parent = None self.index = -1 def __getattr__(self, name): return self.subnames.get(name, None) def sub(self, name): return self.subnames.get(name, None) def __getitem__(self, key): if key == '_cdata': return self.cdata return self.attrs.get(key,'') def __iter__(self): return self def next(self): self.index += 1 if self.index > len(self.subs) - 1: raise StopIteration, "Looped through all sub elements." return self.subs[self.index] def getxml(self, depth = 0): tab = '\t' * depth attrstring = '' for attr_name in self.attrs: attrstring += ' %s="%s"' % (attr_name, self.attrs[attr_name]) xmlstring = "%s<%s%s" % (tab, self.name, attrstring) if self.cdata == '' and self.subs == []: xmlstring += '/>' else: xmlstring += '>' if self.cdata != '': xmlstring += '\n%s' % self.cdata for sub in self.subs: xmlstring += "\n" + sub.getxml(depth + 1) xmlstring += "\n%s" % (tab,self.name) return xmlstring class xmllib(object): def __init__(self, xml_file, type='string'): self.parser = xml.parsers.expat.ParserCreate() self.parser.CharacterDataHandler = self.h_data self.parser.StartElementHandler = self.h_se self.parser.EndElementHandler = self.h_ee self.root = xmlobj() self.element = self.root try: if type == 'file': self.parser.ParseFile(open(xml_file, 'r')) elif type == 'string': self.parser.Parse(xml_file) except xml.parsers.expat.ExpatError: #exception, tb,rowcol = traceback.format_exc().split('\n')[-2].split(':',3) ##print "-" * 80 #print "XML Error!\n%s on %s\n%s" % (xml_file, rowcol.strip(), tb.strip()) #print "-" * 80 print "Expat Parsing Error." sys.exit() def h_se(self, name, attrs): newelement = xmlobj() # start a new element newelement.name = name # name it newelement.attrs = attrs # assign attributes newelement.parent = self.element # assign the current element as it's parent self.element.subs.append(newelement) # apparend to subs of the current element # appending subname if not self.element.subnames.has_key(name): self.element.subnames[name] = [] self.element.subnames[name].append(newelement) # ---------------- self.element = newelement # assign the new element as the current one def h_data(self, data): self.element.cdata += data # assign cdata def h_ee(self, name): self.element.cdata = self.element.cdata.strip() self.element = self.element.parent # element is done, set current to parent element def getroot(self): return self.root.subs[0] def loadfile(file): xmlparser = xmllib(file) return xmlparser.getroot() class strip_message(object): def processEvent(self, event): xmlparser = xmllib(event) thexml = xmlparser.getroot() for sub in thexml: print sub.name print sub['_cdata'] print "" print thexml.sub('body')[0]['_cdata'] print thexml['from'] scriptobject1 = strip_message() name="scriptobject1" psi-0.14/src/plugins/generic/python/pythonplugin.cpp0000644000175000017500000000747711305557613021031 0ustar janjan/* * pythonscriptingplugin.h - Psi plugin providing Python scripting * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "psiplugin.h" extern int Py_VerboseFlag; /** * Function to obtain all the directories in which plugins can be stored * \return List of plugin directories */ static QStringList scriptDirs() { QStringList l; l += "/Users/kismith/.psi/python"; return l; } class PythonPlugin : public PsiPlugin { Q_OBJECT Q_INTERFACES(PsiPlugin) public: PythonPlugin(); ~PythonPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual bool processEvent( const QString& account, QDomNode &event ); private: QStringList scriptObjects_; void loadScripts(); QString loadScript( const QString& fileName); PyObject* main_module_; PyObject* main_dict_; }; Q_EXPORT_PLUGIN(PythonPlugin); PythonPlugin::PythonPlugin() { Py_Initialize(); main_module_ = PyImport_AddModule("__main__"); main_dict_ = PyModule_GetDict(main_module_); QString command="print \"Python running\""; PyRun_SimpleString(qPrintable(command)); loadScripts(); } PythonPlugin::~PythonPlugin() { Py_Finalize(); } QString PythonPlugin::name() const { return "Python Scripting Plugin"; } QString PythonPlugin::shortName() const { return "python"; } QString PythonPlugin::version() const { return "0.0"; } bool PythonPlugin::processEvent( const QString& account, QDomNode &event ) { foreach (QString script, scriptObjects_) { qDebug() << (qPrintable(QString("running it on script %1").arg(script))); QString scriptCall=QString("%1.processEvent(\"\"\"%2\"\"\")").arg(script).arg(toString(event)); QString command=QString("%1").arg(scriptCall); qDebug() << (qPrintable(QString("Running python command:\n%1").arg(command))); PyRun_SimpleString(qPrintable(command)); } return true; } void PythonPlugin::loadScripts() { foreach(QString d, scriptDirs()) { QDir dir(d); foreach(QString file, dir.entryList()) { file=dir.absoluteFilePath(file); if (file.contains(".py")) loadScript(file); } } } QString PythonPlugin::loadScript(const QString& fileName) { FILE *file; if ((file = fopen(qPrintable(fileName),"r")) == NULL ) return ""; qDebug() << (qPrintable(QString("Found script file %1").arg(fileName))); PyObject* pyName = PyRun_File(file, qPrintable(fileName), Py_file_input, main_dict_, main_dict_); qDebug("well, we got this far"); fclose(file); pyName = PyDict_GetItemString( main_dict_, "name" ); if (pyName == NULL || !PyString_Check(pyName)) { qWarning(qPrintable(QString("Tried to load %1 but it didn't return a string for its name").arg(fileName))); return ""; } QString name( PyString_AsString( pyName ) ); scriptObjects_.append(name); qDebug() << (qPrintable(QString("Found script %1 in the file").arg(name))); return name; } #include "pythonplugin.moc" psi-0.14/src/plugins/generic/null/0000755000175000017500000000000011305557613015177 5ustar janjanpsi-0.14/src/plugins/generic/null/nullplugin.pro0000644000175000017500000000007011305557613020107 0ustar janjaninclude(../../psiplugin.pri) SOURCES += nullplugin.cpp psi-0.14/src/plugins/generic/null/nullplugin.cpp0000644000175000017500000000331111305557613020072 0ustar janjan/* * nullplugin.h - null-op Psi plugin * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psiplugin.h" class NullPlugin : public QObject, public PsiPlugin { Q_OBJECT Q_INTERFACES(PsiPlugin) public: virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options() const; virtual bool enable(); virtual bool disable(); }; Q_EXPORT_PLUGIN(NullPlugin); QString NullPlugin::name() const { return "Null Plugin"; } QString NullPlugin::shortName() const { return "null"; } QString NullPlugin::version() const { return "0.1"; } QWidget* NullPlugin::options() const { return 0; } bool NullPlugin::enable() { return true; } bool NullPlugin::disable() { return true; } #include "nullplugin.moc" psi-0.14/src/plugins/generic/antievil/0000755000175000017500000000000011305557613016040 5ustar janjanpsi-0.14/src/plugins/generic/antievil/antievil.cpp0000644000175000017500000000420711305557613020362 0ustar janjan/* * (c) 2007-2008 Maciej Niedzielski */ #include #include #include #include "psiplugin.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" class AntiEvilPlugin: public QObject, public PsiPlugin, public StanzaFilter, public StanzaSender { Q_OBJECT; Q_INTERFACES(PsiPlugin StanzaFilter StanzaSender); public: AntiEvilPlugin() : stanzaSender(0) { } //-- PsiPlugin ------------------------------------------- virtual QString name() const { // this will be displayed return "Machekku's Evil Blocker Plugin"; } virtual QString shortName() const { // internal name, no spaces please! return "antievil"; } virtual QString version() const { return "0.1"; } virtual QWidget* options() const { return 0; } virtual bool enable() { if (stanzaSender) { enabled = true; } return enabled; } virtual bool disable() { enabled = false; return true; } //-- StanzaFilter ---------------------------------------- virtual bool incomingStanza(int account, const QDomElement& stanza) { bool blocked = false; if (enabled) { for (QDomNode n = stanza.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if (!i.isNull() && i.tagName() == "evil" && i.attribute("xmlns") == "http://jabber.org/protocol/evil") { qDebug("evil blocked! ;)"); if (stanza.tagName() == "iq") { qDebug("sending 'forbidden' error"); QString sender = stanza.attribute("from"); QString reply = QString("") .arg(sender.isEmpty() ? "" : QString("to='%1'").arg(sender)); stanzaSender->sendStanza(account, reply); } blocked = true; // stop processing this stanza break; } } } return blocked; } //-- StanzaSender ---------------------------------------- virtual void setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } private: StanzaSendingHost* stanzaSender; bool enabled; }; Q_EXPORT_PLUGIN2(antievil, AntiEvilPlugin) #include "antievil.moc" psi-0.14/src/plugins/generic/antievil/antievil.pro0000644000175000017500000000006511305557613020376 0ustar janjaninclude(../../psiplugin.pri) SOURCES += antievil.cpp psi-0.14/src/plugins/generic/echo/0000755000175000017500000000000011305557613015143 5ustar janjanpsi-0.14/src/plugins/generic/echo/echoplugin.pro0000644000175000017500000000007011305557613020017 0ustar janjaninclude(../../psiplugin.pri) SOURCES += echoplugin.cpp psi-0.14/src/plugins/generic/echo/echoplugin.cpp0000644000175000017500000000771511305557613020016 0ustar janjan/* * echoplugin.cpp - Psi plugin to echo messages * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "psiplugin.h" #include "eventfilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" class EchoPlugin : public QObject, public PsiPlugin, public EventFilter, public StanzaSender, public OptionAccessor { Q_OBJECT Q_INTERFACES(PsiPlugin EventFilter StanzaSender OptionAccessor) public: EchoPlugin(); // PsiPlugin virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options() const; virtual bool enable(); virtual bool disable(); // EventFilter virtual bool processEvent(int account, const QDomElement& e); virtual bool processMessage(int account, const QString& fromJid, const QString& body, const QString& subject); // StanzaSender virtual void setStanzaSendingHost(StanzaSendingHost *host); // OptionAccessor virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& option); private: bool enabled; OptionAccessingHost* psiOptions; StanzaSendingHost* sender; }; Q_EXPORT_PLUGIN(EchoPlugin); EchoPlugin::EchoPlugin() : enabled(false), psiOptions(0), sender(0) { } //-- PsiPlugin ------------------------------------------------------ QString EchoPlugin::name() const { return "Echo Plugin"; } QString EchoPlugin::shortName() const { return "echo"; } QString EchoPlugin::version() const { return "0.1"; } QWidget* EchoPlugin::options() const { return 0; } bool EchoPlugin::enable() { if (psiOptions && sender) { enabled = true; } return enabled; } bool EchoPlugin::disable() { enabled = false; return true; } //-- EventFilter ---------------------------------------------------- bool EchoPlugin::processEvent(int account, const QDomElement& e) { Q_UNUSED(account); Q_UNUSED(e); return false; // don't stop processing } bool EchoPlugin::processMessage(int account, const QString& fromJid, const QString& body, const QString& subject) { if (enabled) { qWarning(qPrintable(QString("Received message '%1', echoing back to %2").arg(body).arg(fromJid))); QVariant option = psiOptions->getGlobalOption(body); QString reply; QString type; if (option.isValid()) { reply = QString("Option %1 = %2").arg(body).arg(option.toString()); type = "chat"; } else { reply = QString("What you say? %1 ?").arg(body); type = "normal"; } QString replySubject = QString("Re: %1").arg(subject); sender->sendMessage(account, fromJid, reply, replySubject, type); } return false; } //-- StanzaSender --------------------------------------------------- void EchoPlugin::setStanzaSendingHost(StanzaSendingHost *host) { sender = host; } //-- OptionAccessor ------------------------------------------------- void EchoPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void EchoPlugin::optionChanged(const QString& option) { Q_UNUSED(option); } #include "echoplugin.moc" psi-0.14/src/plugins/generic/chess/0000755000175000017500000000000011305557613015332 5ustar janjanpsi-0.14/src/plugins/generic/chess/gamesocket.cpp0000644000175000017500000000102411305557613020155 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: gamesocket.cpp,v 0.1 2005/01/08 12:31:24 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: */ #include #include "gamesocket.h" GameSocket::GameSocket(QWidget *parent, const char *name) :Q3ServerSocket(GAME_PORT, GAME_BACKLOG, (QObject *)parent, name) { } GameSocket::~GameSocket() { } void GameSocket::newConnection(int sock) { emit acceptConnection(sock); } psi-0.14/src/plugins/generic/chess/mainwindow.h0000644000175000017500000000326211305557613017662 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: mainwindow.h,v 0.1 2005/01/08 12:20:13 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: */ #ifndef __MAIN_WINDOW_H__ #define __MAIN_WINDOW_H__ #include #include #include #include #include #include #include #include #include #include //Added by qt3to4: #include #include #include "gamesocket.h" #include "gameboard.h" class MainWindow:public Q3MainWindow { Q_OBJECT public: MainWindow(QWidget *parent = NULL, const char *name = NULL); ~MainWindow(); bool sockOk()const{return (sock->ok());} private: int id; QString ready_txt; Q3PopupMenu *game, *help; QWorkspace *wrk; GameSocket *sock; QStringList hosts; private slots: void showStatus(const QString&); void newGame(); void newGame(int); void about(); void activated(QWidget *); void saveImage(); }; //----------------------------------------------------------------------------- class SelectGame:public QDialog { Q_OBJECT public: SelectGame(QWidget *parent = NULL, const char *name = NULL); ~SelectGame(); void setHosts(const QStringList &); QString host(); QStringList hosts(); GameBoard::GameType gameType(); private: QLabel *l1; QComboBox *hst; Q3ButtonGroup *btn; QRadioButton *wg, *bg; Q3GroupBox *box; QPushButton *Ok, *Cancel; protected: void resizeEvent(QResizeEvent *); private slots: void checkParams(); void checkParams(const QString&); }; #endif /* __MAIN_WINDOW_H__ */ psi-0.14/src/plugins/generic/chess/game-README0000644000175000017500000000113611305557613017122 0ustar janjanThis is the README for the chess game upon which this plugin is based (GPL). Network Chess Game ~~~~~~~~~~~~~~~~~~ This software is distributed under GNU GPL. Use it at own risk. NO WARRANTY. To compile the game you need Qt library version 3.2 or newer. Also you need to set QTDIR environvent variable. Read Qt manual for more info. Then just type make -f Makefile.gnu and wait for a few time. If you use FreeBSD you may type Makefile.FreeBSD. The game uses TCP port 1345, you may change it at gamesocket.h Maybe I'll write HTTP-proxy support... maybe! Denis, Tambov (aka denk@RusNet) 2005/29/01 psi-0.14/src/plugins/generic/chess/mainwindow.cpp0000644000175000017500000001400611305557613020213 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: mainwindow.cpp,v 0.1 2005/01/08 12:20:13 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: */ #include #include #include #include #include #include //Added by qt3to4: #include #include #include #include "mainwindow.h" #include "gameboard.h" #include "xpm/chess.xpm" #include "xpm/quit.xpm" #include "xpm/new_game.xpm" extern QColor cw, cb; MainWindow::MainWindow(QWidget *parent, const char *name) :Q3MainWindow(parent, name) { QPixmap xpm(chess_xpm); cw = QColor(0x8F, 0xDF, 0xF0); cb = QColor(0x70, 0x9F, 0xDF); setIcon(xpm); wrk = new QWorkspace(this); sock = new GameSocket(this); game = new Q3PopupMenu(this); game->insertItem(QPixmap((const char **)new_game), tr("New"), this, SLOT(newGame()), Qt::CTRL + Qt::Key_N); id = game->insertItem(xpm, tr("Save image"), this, SLOT(saveImage()), Qt::CTRL + Qt::Key_S); game->setItemEnabled(id, false); game->insertSeparator(); game->insertItem(QPixmap((const char **)quit_xpm), tr("Quit"), qApp, SLOT(quit()), Qt::CTRL + Qt::Key_Q); help = new Q3PopupMenu(this); help->insertItem(xpm, tr("About the game"), this, SLOT(about())); menuBar()->insertItem(tr("Game"), game); menuBar()->insertSeparator(); menuBar()->insertItem(tr("Help"), help); setCentralWidget(wrk); ready_txt = tr("Ready"); showStatus(ready_txt); QObject::connect(sock, SIGNAL(acceptConnection(int)), this, SLOT(newGame(int))); QObject::connect(wrk, SIGNAL(windowActivated(QWidget *)), this, SLOT(activated(QWidget *))); } MainWindow::~MainWindow() { delete help; delete game; delete sock; delete wrk; } void MainWindow::showStatus(const QString &txt) { statusBar()->message(txt); } void MainWindow::newGame() { SelectGame *dlg; GameBoard *brd; QString hst; dlg = new SelectGame(this); dlg->setHosts(hosts); if (dlg->exec()) { hosts = dlg->hosts(); hst = dlg->host(); brd = new GameBoard(dlg->gameType(), hst, wrk); showStatus(brd->status()); QObject::connect(brd, SIGNAL(showStatus(const QString&)), this, SLOT(showStatus(const QString&))); brd->show(); } delete dlg; } void MainWindow::newGame(int sock) { GameBoard *brd; brd = new GameBoard(sock, wrk); showStatus(brd->status()); QObject::connect(brd, SIGNAL(showStatus(const QString&)), this, SLOT(showStatus(const QString&))); brd->show(); game->setItemEnabled(id, true); } void MainWindow::about() { QMessageBox::about(this, tr("About") + " QNetChess", "QNetChess " + tr( "is a network game chess for two players.\n" "It has a client and a server in the same program.\n" "You can modify and redistribute the source code\n" "because it is under GPL.\n\n" "Russia, Tambov, 2005 (denis@silversoft.net)" )); } void MainWindow::activated(QWidget *w) { GameBoard *brd = (GameBoard *)w; game->setItemEnabled(id, brd != NULL); if (brd != NULL) showStatus(brd->status()); else showStatus(ready_txt); } void MainWindow::saveImage() { GameBoard *brd = (GameBoard *)wrk->activeWindow(); if (brd != NULL) brd->saveImage(); } //----------------------------------------------------------------------------- SelectGame::SelectGame(QWidget *parent, const char *name) :QDialog(parent, name) { setCaption(tr("New game with...")); l1 = new QLabel(tr("To play with "), this); hst = new QComboBox(true, this); hst->setValidator(new QRegExpValidator( QRegExp("([a-zA-Z0-9]*\\.)*[a-zA-Z]"), hst)); btn = new Q3ButtonGroup(tr("Choose your game"), this); wg = new QRadioButton(tr("White game"), btn); bg = new QRadioButton(tr("Black game"), btn); box = new Q3GroupBox(this); Ok = new QPushButton(tr("Play!"), box); Cancel = new QPushButton(tr("Cancel"), box); resize(400, QFontMetrics(font()).lineSpacing() * 7); setMinimumSize(size()); setMaximumSize(size()); QObject::connect(Ok, SIGNAL(clicked()), this, SLOT(accept())); QObject::connect(Cancel, SIGNAL(clicked()), this, SLOT(reject())); QObject::connect(wg, SIGNAL(clicked()), this, SLOT(checkParams())); QObject::connect(bg, SIGNAL(clicked()), this, SLOT(checkParams())); QObject::connect(hst, SIGNAL(textChanged(const QString&)), this, SLOT(checkParams(const QString&))); checkParams(); } SelectGame::~SelectGame() { delete Cancel; delete Ok; delete box; delete bg; delete wg; delete btn; delete hst; delete l1; } void SelectGame::resizeEvent(QResizeEvent *e) { QFontMetrics fm(font()); int w = e->size().width(), h = e->size().height(), fh = fm.lineSpacing() + 2, bl; QDialog::resizeEvent(e); l1->setGeometry(0, 0, fm.width(l1->text()) + 20, fh); hst->move(l1->x() + l1->width(), l1->y()); hst->resize(w - hst->x(), l1->height()); btn->move(l1->x(), l1->y() + l1->height()); btn->resize(w, l1->height() * 3 + 2); wg->setGeometry(2, fh, btn->width() - 4, fh); bg->setGeometry(wg->x(), wg->y() + wg->height(), wg->width(), wg->height()); box->move(btn->x(), btn->y() + btn->height()); box->resize(w, h - box->y()); bl = box->width() / 5; Ok->move(bl, 4); Ok->resize(bl, box->height() - Ok->y() * 2); Cancel->setGeometry(Ok->x() + Ok->width() + bl, Ok->y(), Ok->width(), Ok->height()); } void SelectGame::checkParams() { bool res; res = !hst->currentText().isEmpty() && (bg->isChecked() || wg->isChecked()); Ok->setEnabled(res); } void SelectGame::checkParams(const QString&) { checkParams(); } QString SelectGame::host() { QString h(hst->currentText()); return h.left(h.findRev(':')); } QStringList SelectGame::hosts() { QStringList lst; int i, cnt; cnt = hst->count(); lst += host(); for (i = 0; i < cnt; i++) lst += hst->text(i); return (lst); } void SelectGame::setHosts(const QStringList &h) { hst->insertStringList(h); } GameBoard::GameType SelectGame::gameType() { GameBoard::GameType gt; if (wg->isChecked()) gt = GameBoard::WHITE; else if (bg->isChecked()) gt = GameBoard::BLACK; else gt = GameBoard::NOGAME; return (gt); } psi-0.14/src/plugins/generic/chess/gameboard.h0000644000175000017500000001473011305557613017431 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: gameboard.h,v 0.1 2005/01/08 13:00:57 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: */ #ifndef __GAME_BOARD_H__ #define __GAME_BOARD_H__ #include #include #include #include #include #include //Added by qt3to4: #include #include #include #include #include #include #define MAX(a, b) (((a) > (b))?(a):(b)) #define SEP ' ' #define EOL '\n' #define LONG_XCHG "@-@" #define SHORT_XCHG "o-o" #define SOCK_WAIT 900 #define GAMEOVER_TXT "****" class GameBoard; class Drawer; class Figure; class GameProtocol; class GameBoard:public QWidget { Q_OBJECT public: enum GameType { NOGAME = 0x0, BLACK = 0x1, WHITE = 0x2 }; enum FigureType { NONE = 0x00, WHITE_PAWN = 0x01, WHITE_CASTLE = 0x02, WHITE_BISHOP = 0x03, WHITE_KING = 0x04, WHITE_QUEEN = 0x05, WHITE_KNIGHT = 0x06, BLACK_PAWN = 0x11, BLACK_CASTLE = 0x12, BLACK_BISHOP = 0x13, BLACK_KING = 0x14, BLACK_QUEEN = 0x15, BLACK_KNIGHT = 0x16, DUMMY = 0xFF }; GameBoard(GameType, const QString &, QWidget *parent = NULL, const char *name = NULL); GameBoard(int, QWidget *parent = NULL, const char *name = NULL); ~GameBoard(); void saveImage(); GameType type()const{return (gt);} QString status()const{return (my_stat);} public slots: void receiveData(const QString& data); private: Drawer *drw; GameType gt; FigureType *map; QString hst, my_stat; Q3Socket *sock; Q3GroupBox *box, *hist; QListWidget *lst, *hw, *hb; QLineEdit *edt; QTimer *tmr, *tmr2; int sock_tout; GameProtocol* protocol; void initMap(); void parseString(const QString&); void updateChat(const QString&); void updateHistory(const QString&, bool); void updateHistory(int, bool); protected: void resizeEvent(QResizeEvent *); void closeEvent(QCloseEvent *); void focusInEvent(QFocusEvent *); private slots: void showHostFound(); void sockConnected(); void sockRead(const QString& data); void sockClosed(); void sendMove(const QString&); void sendText(); void sendFigure(const QString&, GameBoard::FigureType); void sockTest(); void sockError(int); void gameover(int); signals: void showStatus(const QString&); void sendData(const QString& data); }; //----------------------------------------------------------------------------- class Drawer:public QWidget { Q_OBJECT public: Drawer(GameBoard::FigureType *, GameBoard::GameType *, QWidget *parent = NULL, const char *name = NULL); ~Drawer(); void makeMove(const QString&); void newFigure(const QString&, int); private: int top_margin, left_margin, hl; int x_brd, y_brd, cs; int tfx, tfy; QPixmap fig[12]; GameBoard::FigureType *map; GameBoard::GameType *gt; bool km, lcm, rcm, kk; void drawBoard(QPainter *, int, int); void drawMap(QPainter *, int, int); void win2map(int&, int&); void map2win(int, int, int&, int&); void takeFigure(int, int); void makeMove(GameBoard::GameType, int, int, int, int, bool, bool); bool xchg(GameBoard::FigureType, GameBoard::FigureType, int, int, int, int); bool checkWhiteCastle(int, int, int, int, bool); bool checkBlackCastle(int, int, int, int, bool); bool canTake(int, int); bool hasTakenFigure(); bool makeXchg(); protected: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *); signals: void touchFigure(int, int); void moved(const QString&); void newFigure(const QString&, GameBoard::FigureType); void gameover(int); }; //----------------------------------------------------------------------------- class FigureDialog:public QDialog { Q_OBJECT public: FigureDialog(const QPixmap *, const GameBoard::GameType, QWidget *parent = NULL, const char *name = NULL); ~FigureDialog(); GameBoard::FigureType figure()const{return (fr);} private: GameBoard::GameType gt; const QPixmap *fig; QString str; int step, fh; GameBoard::FigureType fr; protected: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *); }; //----------------------------------------------------------------------------- class Figure { public: static bool hasMyFigure(GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static int hasEnemyFigure(GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static bool hasFigure(GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static int map2map(GameBoard::GameType, int, int, bool); static int validMove(GameBoard::GameType, GameBoard::FigureType *, int, int, int, int, bool); static void moveList(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListWhitePawn(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListBlackPawn(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListCastle(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListBishop(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListKing(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListQueen(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static void moveListKnight(Q3PointArray&, GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static bool hasPoint(const Q3PointArray&, int, int); static bool hasKingsMeeting(GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static bool validPoint(GameBoard::GameType, GameBoard::FigureType *, int, int, bool); static QString map2str(int, int); static void str2map(const QString&, int *, int *); static int checkKing(GameBoard::GameType, GameBoard::FigureType *, bool, Q3PointArray&, bool); }; //----------------------------------------------------------------------------- class GameProtocol:public QDialog { Q_OBJECT public: void send(Q3Socket *, const QString&); void setGameType(Q3Socket *, GameBoard::GameType); void acceptGame(Q3Socket *); void sendMove(Q3Socket *, const QString&); void sendQuit(Q3Socket *); void sendText(Q3Socket *, const QString&); void sendFigure(Q3Socket *, const QString&, int); void sendGameover(Q3Socket *, const QString&); signals: void sendData(const QString& data); }; #endif /* __GAME_BOARD_H__ */ psi-0.14/src/plugins/generic/chess/chessplugin.cpp0000644000175000017500000001365611305557613020375 0ustar janjan/* * chessplugin.cpp - Psi plugin to play chess * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "psiplugin.h" #include "gameboard.h" extern QColor cw, cb; class ChessPlugin : public PsiPlugin { Q_OBJECT Q_INTERFACES(PsiPlugin) public: ChessPlugin(); virtual QString name() const; virtual bool processEvent( const PsiAccount* account, QDomNode &event ); virtual void message( const PsiAccount* account, const QString& message, const QString& fromJid, const QString& fromDisplay); virtual QString shortName() const; virtual QString version() const; private slots: void sendData(const QString& data); void receiveData(const QString& data); private: void startGame(const QString& jid, bool meWhite, const PsiAccount* account); void stopGame(); GameBoard* game_; QString playingWith_; PsiAccount* account_; }; Q_EXPORT_PLUGIN(ChessPlugin); ChessPlugin::ChessPlugin() : PsiPlugin() { game_ = NULL; } QString ChessPlugin::name() const { return "Chess Plugin"; } QString ChessPlugin::shortName() const { return "chess"; } QString ChessPlugin::version() const { return "0.0.1"; } bool ChessPlugin::processEvent( const PsiAccount* account, QDomNode &event ) { return true; } void ChessPlugin::message( const PsiAccount* account, const QString& message, const QString& fromJid, const QString& fromDisplay) { QString reply; qDebug("chess message"); if (!message.startsWith("chess")) return; qDebug("message for us in chess"); if (game_ && fromJid != playingWith_) { reply=QString("already playing chess with %2, sorry").arg(fromJid).arg(playingWith_); emit sendStanza(account, reply); return; } QString command = QString(message); command.remove(0,6); qDebug() << (qPrintable(QString("chess command string %1").arg(command))); if (command == QString("start")) { if (game_) return; qWarning(qPrintable(QString("Received message '%1', launching chess with %2").arg(message).arg(fromDisplay))); QString reply; reply=QString("chess starting").arg(fromJid); emit sendStanza(account, reply); startGame(fromJid, false, account); } else if (command == QString("starting")) { if (game_) return; qWarning(qPrintable(QString("Received message '%1', launching chess with %2").arg(message).arg(fromDisplay))); QString reply; reply=QString("starting chess, I go first :)").arg(fromJid); emit sendStanza(account, reply); startGame(fromJid, true, account); } else if (!game_) { return; } else if (command.startsWith("command")) { command.remove(0,8); qDebug() << (qPrintable(QString("chess command %1").arg(command))); receiveData(command); } } void ChessPlugin::startGame(const QString& jid, bool meFirst, const PsiAccount* account) { /* game = new TicTacToe( meFirst, size ); game->setCaption(QString("Noughts and Crosses with %1").arg(jid)); playingWith=jid; game->show(); account_=(PsiAccount*)account; connect(game, SIGNAL(closing()), this, SLOT(stopGame())); connect(game, SIGNAL(myMove(int)), this, SLOT(myTurn(int))); connect(game, SIGNAL(gameOverSignal(TicTacGameBoard::State)), this, SLOT(gameOver(TicTacGameBoard::State))); */ playingWith_=jid; account_=(PsiAccount*)account; cw = QColor(0x8F, 0xDF, 0xF0); cb = QColor(0x70, 0x9F, 0xDF); if (meFirst) { GameBoard::GameType type=GameBoard::WHITE; game_ = new GameBoard(type, jid, NULL); } else { game_ = new GameBoard(1); } //showStatus(game_->status()); //QObject::connect(brd, SIGNAL(showStatus(const QString&)), this, SLOT(showStatus(const QString&))); connect(game_, SIGNAL(sendData(const QString&)), this, SLOT(sendData(const QString &))); game_->show(); } void ChessPlugin::stopGame() { delete game_; game_=NULL; } /*void ChessPlugin::gameOver(TicTacGameBoard::State state) { QString reply; QString winner; switch (state) { case TicTacGameBoard::HumanWon: winner="I"; break; case TicTacGameBoard::ComputerWon: winner="You"; break; case TicTacGameBoard::NobodyWon: winner="It was a draw, no-one"; break; default: winner="ERROR!!!"; } reply=QString("%2 won. Good game.").arg(playingWith).arg(winner); emit sendStanza(account_, reply); }*/ void ChessPlugin::sendData(const QString& data) { qDebug() << (qPrintable(QString("sendingData turn: %1").arg(data))); if (!game_) return; QString reply; QString stanzaId="aaaa"; reply=QString("chess command %3").arg(playingWith_).arg(stanzaId).arg(data); qDebug() << (qPrintable(QString("sendingData stanza: %1").arg(reply))); emit sendStanza(account_, reply); } void ChessPlugin::receiveData(const QString& data) { qDebug() << (qPrintable(QString("received data: %1").arg(data))); if (!game_) return; //game->theirMove(space); game_->receiveData(data); } #include "chessplugin.moc" psi-0.14/src/plugins/generic/chess/chessplugin.pro0000644000175000017500000000124711305557613020404 0ustar janjaninclude(../../psiplugin.pri) # Input HEADERS += gameboard.h \ gamesocket.h \ mainwindow.h \ xpm/black_bishop.xpm \ xpm/black_castle.xpm \ xpm/black_king.xpm \ xpm/black_knight.xpm \ xpm/black_pawn.xpm \ xpm/black_queen.xpm \ xpm/white_bishop.xpm \ xpm/white_castle.xpm \ xpm/white_king.xpm \ xpm/white_knight.xpm \ xpm/white_pawn.xpm \ xpm/white_queen.xpm \ xpm/chess.xpm \ xpm/quit.xpm \ xpm/new_game.xpm SOURCES += gameboard.cpp gamesocket.cpp mainwindow.cpp SOURCES += chessplugin.cpp psi-0.14/src/plugins/generic/chess/xpm/0000755000175000017500000000000011305557613016136 5ustar janjanpsi-0.14/src/plugins/generic/chess/xpm/black_queen.xpm0000644000175000017500000000347711305557613021150 0ustar janjan/* XPM */ static char *black_queen[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "...................##...................", "...........##.....####.....##...........", "..........####....####....####..........", "..........####.....##.....####..........", "...........##......##......##...........", "...##......##......##......##......##...", "..####.....##.....####.....##.....####..", "..####.....###....####....###.....####..", "...##......###....####....###......##...", "....#......###....####....###......#....", "....##.....####...####...####.....##....", "....###....####...####...####....###....", "....####...####...####...####...####....", ".....###...####..######..####...###.....", ".....####..#####.######.#####..####.....", "......####.#####.######.#####.####......", "......##########.######.##########......", "......############################......", ".......##########################.......", ".......########aaaaaaaaaa########.......", "........##aaaaa##########aaaaa##........", "........#a####################a#........", ".........######################.........", ".........######aaaaaaaaaa######.........", ".........#aaaaa##########aaaaa#.........", ".........######################.........", "........#######aaaaaaaaaa#######........", "........#aaaaaa##########aaaaaa#........", "........########################........", "........########################........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/white_king.xpm0000644000175000017500000000347611305557613021026 0ustar janjan/* XPM */ static char *white_king[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "...................##...................", "...................##...................", ".................##aa##.................", ".................##aa##.................", "...................##...................", "...................##...................", "........####.......##.......####........", "......##aaaa##....####....##aaaa##......", ".....#aaaaaaaa#..##aa##..#aaaaaaaa#.....", ".....#aaa####aa###aaaa###aa####aaa#.....", "....#aaa#aaaa#aa##aaaa##aa#aaaa#aaa#....", "....#aa#aaaaaa#aa##aa##aa#aaaaaa#aa#....", "....#aa#aaaaaaa#aa####aa#aaaaaaa#aa#....", "....#aa#aaaaaaaa#aa##aa#aaaaaaaa#aa#....", ".....#a#aaaaaaaaa#aaaa#aaaaaaaaa#a#.....", ".....#aa#aaaaaaaa#aaaa#aaaaaaaa#aa#.....", ".....#aa#aaaaaaaaa#aa#aaaaaaaaa#aa#.....", "......#a#aaaaaaaaa#aa#aaaaaaaaa#a#......", "......#aa#aaaaaaaa#aa#aaaaaaaa#aa#......", ".......#a#aaaaaaaa#aa#aaaaaaaa#a#.......", ".......#aa#aaaaaaa#aa#aaaaaaa#aa#.......", "........#aa#aaaaaa#aa#aaaaaa#aa#........", ".........#aa#aaaaa#aa#aaaaa#aa#.........", "..........#aa##############aa#..........", "..........###aaaaaaaaaaaaaa###..........", "..........#aaaaaaaaaaaaaaaaaa#..........", ".........#aaaaa##########aaaaa#.........", "........#aaa###aaaaaaaaaa###aaa#........", "........####aaaaaaaaaaaaaaaa####........", "........#aaaaaaaaaaaaaaaaaaaaaa#........", "........#aaaaaaaaaaaaaaaaaaaaaa#........", "........##aaaaaaaaaaaaaaaaaaaa##........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/quit.xpm0000644000175000017500000000236111305557613017650 0ustar janjan/* XPM */ static char *quit_xpm[]={ "22 22 43 1", "e c #a4140a", "# c #a41c0b", "m c #a92415", "x c #ac2a1c", "d c #ac2f21", "b c #b23628", "c c #b33b2e", "a c #b44234", "o c #bc421c", "p c #bc5732", "C c #bc5e04", "q c #c0603a", "h c #c07e5c", "s c #c46f4a", "g c #c47852", "J c #cc7350", "i c #cc825c", "j c #cc8a63", "k c #cc8f66", "r c #d4976b", "l c #d49e77", "O c #d8cecc", "F c #d99979", "K c #dca47c", "N c #dca684", "f c #ddab91", "n c #e2b59a", "t c #e4d2c4", "M c #e7e5ea", "G c #ebf3f9", "I c #ececf2", "v c #ecfafc", "w c #efcbb7", "D c #f1c5b4", "z c #f4eef4", "B c #f4f6fc", "y c #f8d5c8", "L c #f9e4d8", "H c #fcece2", "E c #fcf2e4", "A c #fcfed0", "u c #fcfefc", ". c None", "...#aabcccdbdddddde...", ".bbfggghgghijjikkjlmm.", ".bbfggghgghijjikkjlmm.", "ennoppppqqkrsssssghlle", "chhpppstuuuuvvwiihhrrx", "chhpppstuuuuvvwiihhrrx", "bggpssuuyylnzzABBjhrrm", "dhhCttufsswDggnuuwjkkm", "chhguuysggEEgghEEujrrm", "chhguuysggEEgghEEujrrm", "dhhkuursssEEhhiDDvlrr#", "bhhFuuFgggGEiiiwwufll#", "djjhBBtgggHEhhkIIAlll#", "djjhBBtgggHEhhkIIAlll#", "diiJEEuKhhLtjjDuuMlll#", "djjskkBuyynfLLBuullNN#", "djjskkBuyynfLLBuullNN#", "djjgggiLuuuuuuLlllfNN#", "eKKhhhijkkfnrrlNNfOgge", ".mmKkkrkrrllllKKKfgee.", ".mmKkkrkrrllllKKKfgee.", "...exxmm##m######ee..."}; psi-0.14/src/plugins/generic/chess/xpm/black_bishop.xpm0000644000175000017500000000350011305557613021302 0ustar janjan/* XPM */ static char *black_bishop[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "...................##...................", "..................####..................", ".................######.................", "..................####..................", "..................####..................", ".................######.................", "...............##########...............", "..............############..............", ".............##############.............", "............#######aa#######............", "...........########aa########...........", "...........########aa########...........", "..........######aaaaaaaa######..........", "..........######aaaaaaaa######..........", "..........#########aa#########..........", "...........########aa########...........", "...........########aa########...........", "............################............", ".............##############.............", "..............############..............", "...............aaaaaaaaaa...............", "..............############..............", ".............##############.............", "..............############..............", "...............a########a...............", "...............#aaaaaaaa#...............", "..........####################..........", ".........######################.........", "........###########..###########........", "........##########....##########........", ".........########......########.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/black_king.xpm0000644000175000017500000000347611305557613020762 0ustar janjan/* XPM */ static char *black_king[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "...................##...................", "...................##...................", ".................######.................", ".................######.................", "...................##...................", "...................##...................", "........####.......##.......####........", "......########....#aa#....########......", ".....##########..#a##a#..##########.....", ".....####aaaa####a####a####aaaa####.....", "....####a####a###a####a###a####a####....", "....###a######a###a##a###a######a###....", "....###a#######a###aa###a#######a###....", "....###a########a##aa##a########a###....", ".....##a#########a####a#########a##.....", ".....###a########a####a########a###.....", ".....###a#########a##a#########a###.....", "......##a#########a##a#########a##......", "......###a########a##a########a###......", ".......##a########a##a########a##.......", ".......###a#######a##a#######a###.......", "........###a######a##a######a###........", ".........###a#####a##a#####a###.........", "..........###aaaaaaaaaaaaaa###..........", "..........aaa##############aaa..........", "..........####################..........", ".........######aaaaaaaaaa######.........", "........####aaa##########aaa####........", "........aaaa################aaaa........", "........########################........", "........########################........", "........########################........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/black_castle.xpm0000644000175000017500000000350011305557613021271 0ustar janjan/* XPM */ static char *black_castle[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "..........#####...####...#####..........", "..........#####...####...#####..........", "..........#####...####...#####..........", "..........####################..........", "..........####################..........", "...........##################...........", "............##aaaaaaaaaaaa##............", ".............##############.............", "..............############..............", "..............##aaaaaaaa##..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............############..............", "..............##aaaaaaaa##..............", "..............############..............", ".............##aaaaaaaaaa##.............", "............################............", "...........##################...........", "..........##aaaaaaaaaaaaaaaa##..........", "..........####################..........", ".........######################.........", ".........######################.........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/chess.xpm0000644000175000017500000000347411305557613020001 0ustar janjan/* XPM */ const char *chess_xpm[]={ "40 40 3 1", "# c #000000", "a c #ffffff", ". c none", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "..........#####...####...#####..........", "..........#aaa#...#aa#...#aaa#..........", "..........#aaa#...#aa#...#aaa#..........", "..........#aaaa###aaaa###aaaa#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", "...........#aaaaaaaaaaaaaaaa#...........", "............#a############a#............", ".............#aaaaaaaaaaaa#.............", "..............#aaaaaaaaaa#..............", "..............#.########.#..............", "..............#.########.#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", ".............#a##########a#.............", "............#aaaaaaaaaaaaaa#............", "...........#aaaaaaaaaaaaaaaa#...........", "..........#a################a#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", ".........#aaaaaaaaaaaaaaaaaaaa#.........", ".........#aaaaaaaaaaaaaaaaaaaa#.........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/black_knight.xpm0000644000175000017500000000350011305557613021302 0ustar janjan/* XPM */ static char *black_knight[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "................#...#...................", "...............###.###..................", "...............###.###..................", "..............####a###..................", ".............###aa#####.................", "............###a#########...............", "...........###############..............", "..........############a####.............", ".........####aaa#######a####............", ".........###aaa#########a####...........", "........#################a####..........", "........##################a###..........", ".......###################a####.........", ".......####################a###.........", "......######################a###........", ".....################.#####a####........", "....##aa###########...######a###........", "....##############...########a###.......", "....#####a#######...########a####.......", "....####aa#####....##########a###.......", ".....#aaa####.....############a###......", ".......a####....#############a####......", "......#####....###############a###......", ".......##.....###############a####......", ".............#################a###......", "............#################a####......", "...........###################a###......", "...........#######################......", "...........#######################......", "...........#######################......", "...........######################.......", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/white_knight.xpm0000644000175000017500000000350011305557613021346 0ustar janjan/* XPM */ static char *white_knight[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "................#...#...................", "...............#a#.#a#..................", "...............#a#.#a#..................", "..............#aaa#aa#..................", ".............#aa##aaa##.................", "............#aa#aaaaaaa##...............", "...........#aaaaaaaaaaaaa#..............", "..........#aaaaaaaaaaa#aaa#.............", ".........#aaa###aaaaaaa#aaa#............", ".........#aa###aaaaaaaaa#aaa#...........", "........#aaaaaaaaaaaaaaaa#aaa#..........", "........#aaaaaaaaaaaaaaaaa#aa#..........", ".......#aaaaaaaaaaaaaaaaaa#aaa#.........", ".......#aaaaaaaaaaaaaa#aaaa#aa#.........", "......#aaaaaaaaaaaaaa##aaaaa#aa#........", ".....#aaaaaaaaaaaaa##.#aaaa#aaa#........", "....#a##aaaaaaaaaa#...#aaaaa#aa#........", "....#aaaaaaaaaaaa#...#aaaaaaa#aa#.......", "....#aaaa#aaaaa##...#aaaaaaa#aaa#.......", "....#aaa##aaa##....#aaaaaaaaa#aa#.......", ".....####aaa#.....#aaaaaaaaaaa#aa#......", ".......#aaa#....##aaaaaaaaaaa#aaa#......", "......#aa##....#aaaaaaaaaaaaaa#aa#......", ".......##.....#aaaaaaaaaaaaaa#aaa#......", ".............#aaaaaaaaaaaaaaaa#aa#......", "............#aaaaaaaaaaaaaaaa#aaa#......", "...........#aaaaaaaaaaaaaaaaaa#aa#......", "...........#aaaaaaaaaaaaaaaaaaaaa#......", "...........#aaaaaaaaaaaaaaaaaaaaa#......", "...........#aaaaaaaaaaaaaaaaaaaaa#......", "...........######################.......", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/white_bishop.xpm0000644000175000017500000000350011305557613021346 0ustar janjan/* XPM */ static char *white_bishop[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "...................##...................", "..................#aa#..................", ".................#aaaa#.................", "..................#aa#..................", "..................####..................", ".................#aaaa#.................", "...............##aaaaaa##...............", "..............#aaaaaaaaaa#..............", ".............#aaaaaaaaaaaa#.............", "............#aaaaaa##aaaaaa#............", "...........#aaaaaaa##aaaaaaa#...........", "...........#aaaaaaa##aaaaaaa#...........", "..........#aaaaa########aaaaa#..........", "..........#aaaaa########aaaaa#..........", "..........#aaaaaaaa##aaaaaaaa#..........", "...........#aaaaaaa##aaaaaaa#...........", "...........#aaaaaaa##aaaaaaa#...........", "............#aaaaaaaaaaaaaa#............", ".............#aaaaaaaaaaaa#.............", "..............#aaaaaaaaaa#..............", "...............##########...............", "..............#aaaaaaaaaa#..............", ".............#aaaaaaaaaaaa#.............", "..............#aaaaaaaaaa#..............", "...............#aaaaaaaa#...............", "...............##########...............", "..........#####aaaaaaaaaa#####..........", ".........#aaaaaaaaa##aaaaaaaaa#.........", "........#aaaaaaaaa#..#aaaaaaaaa#........", "........#aaaaaaaa#....#aaaaaaaa#........", ".........########......########.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/white_castle.xpm0000644000175000017500000000350011305557613021335 0ustar janjan/* XPM */ static char *white_castle[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "..........#####...####...#####..........", "..........#aaa#...#aa#...#aaa#..........", "..........#aaa#...#aa#...#aaa#..........", "..........#aaaa###aaaa###aaaa#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", "...........#aaaaaaaaaaaaaaaa#...........", "............#a############a#............", ".............#aaaaaaaaaaaa#.............", "..............#aaaaaaaaaa#..............", "..............#a########a#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#aaaaaaaaaa#..............", "..............#a########a#..............", "..............#aaaaaaaaaa#..............", ".............#a##########a#.............", "............#aaaaaaaaaaaaaa#............", "...........#aaaaaaaaaaaaaaaa#...........", "..........#a################a#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", ".........#aaaaaaaaaaaaaaaaaaaa#.........", ".........#aaaaaaaaaaaaaaaaaaaa#.........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/new_game.xpm0000644000175000017500000000563211305557613020454 0ustar janjan/* XPM */ static char *new_game[] = { /* width height num_colors chars_per_pixel */ " 50 50 8 1", /* colors */ ". c #040204", "# c #8cdef4", "a c #749edc", "b c #84a6f4", "c c #0c0a0c", "d c #6c96fa", "e c #040604", "f c #0c0e0c", /* pixels */ "..................................................", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "e######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "e######bbbbba######abbbaa#######bbbaab######bbbbaa", "e######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "c######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", ".######aaaaaa######aaaaaa#######aaaaaa######aaaaaa", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", ".aaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######", "eaaaaaa######aaaaaa######aaaaaaa######aaaaaa######" }; psi-0.14/src/plugins/generic/chess/xpm/white_pawn.xpm0000644000175000017500000000347611305557613021043 0ustar janjan/* XPM */ static char *white_pawn[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "..................####..................", ".................#aaaa#.................", "................#aaaaaa#................", "...............#aaaaaaaa#...............", "...............#aaaaaaaa#...............", "...............#aaaaaaaa#...............", "................#aaaaaa#................", "................##aaaa##................", "...............#aaaaaaaa#...............", "..............#aaaaaaaaaa#..............", ".............#aaaaaaaaaaaa#.............", ".............#aaaaaaaaaaaa#.............", ".............#aaaaaaaaaaaa#.............", "..............#aaaaaaaaaa#..............", "...............#aaaaaaaa#...............", "..............#aaaaaaaaaa#..............", ".............#aaaaaaaaaaaa#.............", "............#aaaaaaaaaaaaaa#............", "............#aaaaaaaaaaaaaa#............", "...........#aaaaaaaaaaaaaaaa#...........", "...........#aaaaaaaaaaaaaaaa#...........", "..........#aaaaaaaaaaaaaaaaaa#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", "..........#aaaaaaaaaaaaaaaaaa#..........", "..........####################..........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/black_pawn.xpm0000644000175000017500000000345711305557613020776 0ustar janjan/* XPM */ static char *black_pawn[]={ "40 40 2 1", ". c None", "# c #000000", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "..................####..................", ".................######.................", "................########................", "...............##########...............", "...............##########...............", "...............##########...............", "................########................", "................########................", "...............##########...............", "..............############..............", ".............##############.............", ".............##############.............", ".............##############.............", "..............############..............", "...............##########...............", "..............############..............", ".............##############.............", "............################............", "............################............", "...........##################...........", "...........##################...........", "..........####################..........", "..........####################..........", "..........####################..........", "..........####################..........", "..........####################..........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/xpm/white_queen.xpm0000644000175000017500000000347711305557613021214 0ustar janjan/* XPM */ static char *white_queen[]={ "40 40 3 1", ". c None", "# c #000000", "a c #ffffff", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "...................##...................", "...........##.....#aa#.....##...........", "..........#aa#....#aa#....#aa#..........", "..........#aa#.....##.....#aa#..........", "...........##......##......##...........", "...##......##......##......##......##...", "..#aa#.....##.....#aa#.....##.....#aa#..", "..#aa#.....#a#....#aa#....#a#.....#aa#..", "...##......#a#....#aa#....#a#......##...", "....#......#a#....#aa#....#a#......#....", "....##.....#aa#...#aa#...#aa#.....##....", "....#a#....#aa#...#aa#...#aa#....#a#....", "....#aa#...#aa#...#aa#...#aa#...#aa#....", ".....#a#...#aa#..#aaaa#..#aa#...#a#.....", ".....#aa#..#aaa#.#aaaa#.#aaa#..#aa#.....", "......#aa#.#aaa#.#aaaa#.#aaa#.#aa#......", "......#aaa##aaa#.#aaaa#.#aaa##aaa#......", "......#aaaa#aaaa#aaaaaa#aaaa#aaaa#......", ".......#aaaaaaaaaaaaaaaaaaaaaaaa#.......", ".......#aaaaaaa##########aaaaaaa#.......", "........#a#####aaaaaaaaaa#####a#........", "........##aaaaaaaaaaaaaaaaaaaa##........", ".........#aaaaaaaaaaaaaaaaaaaa#.........", ".........#aaaaa##########aaaaa#.........", ".........######aaaaaaaaaa######.........", ".........#aaaaaaaaaaaaaaaaaaaa#.........", "........#aaaaaa##########aaaaaa#........", "........#######aaaaaaaaaa#######........", "........#aaaaaaaaaaaaaaaaaaaaaa#........", "........#aaaaaaaaaaaaaaaaaaaaaa#........", ".........######################.........", "........................................", "........................................", "........................................"}; psi-0.14/src/plugins/generic/chess/gameboard.cpp0000644000175000017500000012557311305557613017774 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: gameboard.cpp,v 1.1 2005/03/26 11:24:13 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: * Fixed the mate checker (big thanks to knyaz@RusNet) */ #include #include #include #include #include //Added by qt3to4: #include #include #include #include #include #include #include #include #include #include "gameboard.h" #include "gamesocket.h" #include "xpm/black_bishop.xpm" #include "xpm/black_castle.xpm" #include "xpm/black_king.xpm" #include "xpm/black_knight.xpm" #include "xpm/black_pawn.xpm" #include "xpm/black_queen.xpm" #include "xpm/white_bishop.xpm" #include "xpm/white_castle.xpm" #include "xpm/white_king.xpm" #include "xpm/white_knight.xpm" #include "xpm/white_pawn.xpm" #include "xpm/white_queen.xpm" const int cell_size = 40, XSize = 640, YSize = 480; QColor cb, cw; bool Figure::hasMyFigure(GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int n; bool res; n = map2map(gt, x, y, mirror); if (gt == GameBoard::WHITE) switch (map[n]) { case GameBoard::DUMMY: case GameBoard::WHITE_PAWN: case GameBoard::WHITE_CASTLE: case GameBoard::WHITE_BISHOP: case GameBoard::WHITE_KING: case GameBoard::WHITE_QUEEN: case GameBoard::WHITE_KNIGHT: res = true; break; default: res = false; } else if (gt == GameBoard::BLACK) switch (map[n]) { case GameBoard::DUMMY: case GameBoard::BLACK_PAWN: case GameBoard::BLACK_CASTLE: case GameBoard::BLACK_BISHOP: case GameBoard::BLACK_KING: case GameBoard::BLACK_QUEEN: case GameBoard::BLACK_KNIGHT: res = true; break; default: res = false; } else res = false; return (res); } int Figure::hasEnemyFigure(GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int n; int res; n = map2map(gt, x, y, mirror); if (gt == GameBoard::BLACK) switch (map[n]) { case GameBoard::WHITE_PAWN: case GameBoard::WHITE_CASTLE: case GameBoard::WHITE_BISHOP: case GameBoard::WHITE_QUEEN: case GameBoard::WHITE_KNIGHT: res = 1; break; case GameBoard::WHITE_KING: res = 2; break; case GameBoard::DUMMY: default: res = 0; } else if (gt == GameBoard::WHITE) switch (map[n]) { case GameBoard::BLACK_PAWN: case GameBoard::BLACK_CASTLE: case GameBoard::BLACK_BISHOP: case GameBoard::BLACK_QUEEN: case GameBoard::BLACK_KNIGHT: res = 1; break; case GameBoard::BLACK_KING: res = 2; break; case GameBoard::DUMMY: default: res = 0; } else res = 0; return (res); } bool Figure::hasFigure(GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int n; n = map2map(gt, x, y, mirror); return (map[n] != GameBoard::NONE); } int Figure::map2map(GameBoard::GameType gt, int x, int y, bool mirror) { int n = -1; if (gt == GameBoard::WHITE) if (mirror) n = (y - 1) * 8 + (8 - x); else n = (8 - y) * 8 + (x - 1); else if (gt == GameBoard::BLACK) if (mirror) n = (8 - y) * 8 + (x - 1); else n = (y - 1) * 8 + (8 - x); return (n); } QString Figure::map2str(int x, int y) { QString s; s = QString(QChar('a' + x - 1)) + QString::number(y); return (s); } void Figure::str2map(const QString &coo, int *x, int *y) { *x = coo.at(0).toAscii() - 'a' + 1; *y = coo.at(1).toAscii() - '0'; } int Figure::validMove(GameBoard::GameType gt, GameBoard::FigureType *map, int fx, int fy, int tx, int ty, bool mirror) { Q3PointArray vl; int res, f, t; moveList(vl, gt, map, fx, fy, mirror); res = hasPoint(vl, tx, ty); f = map2map(gt, fx, fy, mirror); switch (map[f]) { case GameBoard::WHITE_PAWN: if (res && (ty == 8)) res++; break; case GameBoard::BLACK_PAWN: if (res && (ty == 1)) res++; break; default:; } if (res) { t = map2map(gt, tx, ty, mirror); map[t] = map[f]; map[f] = GameBoard::NONE; if (mirror) { vl.resize(0); t = checkKing(gt, map, mirror, vl, false); switch (t) { case 1: res |= 0x10; break; case 2: res |= 0x20; break; case 3: res |= 0x40; break; default:; } } } return (res); } /* * 0 - nothing * 1 - check * 2 - mate * 3 - stalemate */ int Figure::checkKing(GameBoard::GameType gt, GameBoard::FigureType *map, bool mirror, Q3PointArray &vl, bool co) { Q3PointArray tmp; GameBoard::FigureType myking, map1[64]; GameBoard::GameType mytype; int res, x, y, p, xk, yk, pk; bool hp; if (gt == GameBoard::WHITE) { myking = GameBoard::BLACK_KING; mytype = GameBoard::BLACK; } else if (gt == GameBoard::BLACK) { myking = GameBoard::WHITE_KING; mytype = GameBoard::WHITE; } else { myking = GameBoard::NONE; mytype = GameBoard::NOGAME; } xk = yk = -1; res = 0; p = -1; for (y = 1; y < 9; ++y) for (x = 1; x < 9; ++x) /* check enemy figures */ if (hasMyFigure(gt, map, x, y, mirror)) moveList(vl, gt, map, x, y, mirror); else if (p == -1) { p = map2map(mytype, x, y, !mirror); if (map[p] == myking) { xk = x; yk = y; } else p = -1; } hp = hasPoint(vl, xk, yk); if (hp) { res++; if (!co) { vl.resize(0); for (y = 1; y < 9; ++y) for (x = 1; x < 9; ++x) if (hasMyFigure(mytype, map, x, y, !mirror)) moveList(vl, mytype, map, x, y, !mirror); memmove(map1, map, sizeof(map1)); pk = map2map(mytype, xk, yk, !mirror); for (x = vl.size() - 1; x >= 0; --x) { p = map2map(mytype, vl.point(x).x(), vl.point(x).y(), !mirror); if (p != pk) map1[p] = GameBoard::DUMMY; } if (checkKing(gt, map1, mirror, vl, true) != 0) { vl.resize(0); moveListKing(vl, mytype, map, xk, yk, !mirror); memmove(map1, map, sizeof(map1)); for (y = 0, x = vl.size() - 1; x >= 0; --x) { p = map2map(mytype, vl.point(x).x(), vl.point(x).y(), !mirror); map1[p] = myking; map1[pk] = GameBoard::NONE; if (checkKing(gt, map1, mirror, tmp, true) == 1) ++y; map1[pk] = map[pk]; map1[p] = map[p]; } if (y == (int)vl.size()) res++; } } } else if (!co) { vl.resize(0); for (y = 1; y < 9; ++y) for (x = 1; x < 9; ++x) if (hasMyFigure(mytype, map, x, y, !mirror)) moveList(vl, mytype, map, x, y, !mirror); if (vl.size() == 0) res = 3; } return (res); } void Figure::moveList(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int n; n = map2map(gt, x, y, mirror); switch (map[n]) { case GameBoard::WHITE_PAWN: moveListWhitePawn(vl, gt, map, x, y, mirror); break; case GameBoard::WHITE_CASTLE: case GameBoard::BLACK_CASTLE: moveListCastle(vl, gt, map, x, y, mirror); break; case GameBoard::WHITE_BISHOP: case GameBoard::BLACK_BISHOP: moveListBishop(vl, gt, map, x, y, mirror); break; case GameBoard::WHITE_KING: case GameBoard::BLACK_KING: moveListKing(vl, gt, map, x, y, mirror); break; case GameBoard::WHITE_QUEEN: case GameBoard::BLACK_QUEEN: moveListQueen(vl, gt, map, x, y, mirror); break; case GameBoard::WHITE_KNIGHT: case GameBoard::BLACK_KNIGHT: moveListKnight(vl, gt, map, x, y, mirror); break; case GameBoard::BLACK_PAWN: moveListBlackPawn(vl, gt, map, x, y, mirror); break; default:; } } void Figure::moveListWhitePawn(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { if (validPoint(gt, map, x, y + 1, mirror) && !hasFigure(gt, map, x, y + 1, mirror)) { vl.putPoints(vl.size(), 1, x, y + 1); if ((y == 2) && validPoint(gt, map, x, y + 2, mirror)) vl.putPoints(vl.size(), 1, x, y + 2); } if (validPoint(gt, map, x + 1, y + 1, mirror) && hasEnemyFigure(gt, map, x + 1, y + 1, mirror)) vl.putPoints(vl.size(), 1, x + 1, y + 1); if (validPoint(gt, map, x - 1, y + 1, mirror) && hasEnemyFigure(gt, map, x - 1, y + 1, mirror)) vl.putPoints(vl.size(), 1, x - 1, y + 1); } void Figure::moveListBlackPawn(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { if (validPoint(gt, map, x, y - 1, mirror) && !hasFigure(gt, map, x, y - 1, mirror)) { vl.putPoints(vl.size(), 1, x, y - 1); if ((y == 7) && validPoint(gt, map, x, y - 2, mirror)) vl.putPoints(vl.size(), 1, x, y - 2); } if (validPoint(gt, map, x + 1, y - 1, mirror) && hasEnemyFigure(gt, map, x + 1, y - 1, mirror)) vl.putPoints(vl.size(), 1, x + 1, y - 1); if (validPoint(gt, map, x - 1, y - 1, mirror) && hasEnemyFigure(gt, map, x - 1, y - 1, mirror)) vl.putPoints(vl.size(), 1, x - 1, y - 1); } void Figure::moveListCastle(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int i; for (i = x + 1; i < 9; i++) { if (!hasFigure(gt, map, i, y, mirror)) { vl.putPoints(vl.size(), 1, i, y); continue; } else if (hasEnemyFigure(gt, map, i, y, mirror)) vl.putPoints(vl.size(), 1, i, y); break; } for (i = x - 1; i > 0; i--) { if (!hasFigure(gt, map, i, y, mirror)) { vl.putPoints(vl.size(), 1, i, y); continue; } else if (hasEnemyFigure(gt, map, i, y, mirror)) vl.putPoints(vl.size(), 1, i, y); break; } for (i = y + 1; i < 9; i++) { if (!hasFigure(gt, map, x, i, mirror)) { vl.putPoints(vl.size(), 1, x, i); continue; } else if (hasEnemyFigure(gt, map, x, i, mirror)) vl.putPoints(vl.size(), 1, x, i); break; } for (i = y - 1; i > 0; i--) { if (!hasFigure(gt, map, x, i, mirror)) { vl.putPoints(vl.size(), 1, x, i); continue; } else if (hasEnemyFigure(gt, map, x, i, mirror)) vl.putPoints(vl.size(), 1, x, i); break; } } void Figure::moveListBishop(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int i, j; for (i = x + 1, j = y + 1; (i < 9) && (j < 9); i++, j++) { if (!hasFigure(gt, map, i, j, mirror)) { vl.putPoints(vl.size(), 1, i, j); continue; } else if (hasEnemyFigure(gt, map, i, j, mirror)) vl.putPoints(vl.size(), 1, i, j); break; } for (i = x - 1, j = y + 1; (i > 0) && (j < 9); i--, j++) { if (!hasFigure(gt, map, i, j, mirror)) { vl.putPoints(vl.size(), 1, i, j); continue; } else if (hasEnemyFigure(gt, map, i, j, mirror)) vl.putPoints(vl.size(), 1, i, j); break; } for (i = x - 1, j = y - 1; (i > 0) && (j > 0); i--, j--) { if (!hasFigure(gt, map, i, j, mirror)) { vl.putPoints(vl.size(), 1, i, j); continue; } else if (hasEnemyFigure(gt, map, i, j, mirror)) vl.putPoints(vl.size(), 1, i, j); break; } for (i = x + 1, j = y - 1; (i < 9) && (j > 0); i++, j--) { if (!hasFigure(gt, map, i, j, mirror)) { vl.putPoints(vl.size(), 1, i, j); continue; } else if (hasEnemyFigure(gt, map, i, j, mirror)) vl.putPoints(vl.size(), 1, i, j); break; } } void Figure::moveListKing(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int x1, x2, y1, y2; x1 = x - 1; x2 = x + 1; y1 = y - 1; y2 = y + 1; if (validPoint(gt, map, x1, y2, mirror) && !hasKingsMeeting(gt, map, x1, y2, mirror)) vl.putPoints(vl.size(), 1, x1, y2); if (validPoint(gt, map, x, y2, mirror) && !hasKingsMeeting(gt, map, x, y2, mirror)) vl.putPoints(vl.size(), 1, x, y2); if (validPoint(gt, map, x2, y2, mirror) && !hasKingsMeeting(gt, map, x2, y2, mirror)) vl.putPoints(vl.size(), 1, x2, y2); if (validPoint(gt, map, x1, y, mirror) && !hasKingsMeeting(gt, map, x1, y, mirror)) vl.putPoints(vl.size(), 1, x1, y); if (validPoint(gt, map, x2, y, mirror) && !hasKingsMeeting(gt, map, x2, y, mirror)) vl.putPoints(vl.size(), 1, x2, y); if (validPoint(gt, map, x1, y1, mirror) && !hasKingsMeeting(gt, map, x1, y1, mirror)) vl.putPoints(vl.size(), 1, x1, y1); if (validPoint(gt, map, x, y1, mirror) && !hasKingsMeeting(gt, map, x, y1, mirror)) vl.putPoints(vl.size(), 1, x, y1); if (validPoint(gt, map, x2, y1, mirror) && !hasKingsMeeting(gt, map, x2, y1, mirror)) vl.putPoints(vl.size(), 1, x2, y1); } void Figure::moveListQueen(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { moveListBishop(vl, gt, map, x, y, mirror); moveListCastle(vl, gt, map, x, y, mirror); } void Figure::moveListKnight(Q3PointArray &vl, GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int x1, x2, x3, x4, y1, y2, y3, y4; x1 = x + 1; x2 = x1 + 1; x3 = x - 1; x4 = x3 - 1; y1 = y + 1; y2 = y1 + 1; y3 = y - 1; y4 = y3 - 1; if (validPoint(gt, map, x3, y2, mirror)) vl.putPoints(vl.size(), 1, x3, y2); if (validPoint(gt, map, x1, y2, mirror)) vl.putPoints(vl.size(), 1, x1, y2); if (validPoint(gt, map, x4, y1, mirror)) vl.putPoints(vl.size(), 1, x4, y1); if (validPoint(gt, map, x2, y1, mirror)) vl.putPoints(vl.size(), 1, x2, y1); if (validPoint(gt, map, x4, y3, mirror)) vl.putPoints(vl.size(), 1, x4, y3); if (validPoint(gt, map, x2, y3, mirror)) vl.putPoints(vl.size(), 1, x2, y3); if (validPoint(gt, map, x3, y4, mirror)) vl.putPoints(vl.size(), 1, x3, y4); if (validPoint(gt, map, x1, y4, mirror)) vl.putPoints(vl.size(), 1, x1, y4); } bool Figure::hasKingsMeeting(GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { int x1, x2, y1, y2; bool res; x1 = x - 1; x2 = x + 1; y1 = y - 1; y2 = y + 1; res = false; if (validPoint(gt, map, x1, y2, mirror)) res = (hasEnemyFigure(gt, map, x1, y2, mirror) == 2); if (! res && validPoint(gt, map, x, y2, mirror)) res = (hasEnemyFigure(gt, map, x, y2, mirror) == 2); if (!res && validPoint(gt, map, x2, y2, mirror)) res = (hasEnemyFigure(gt, map, x2, y2, mirror) == 2); if (!res && validPoint(gt, map, x1, y, mirror)) res = (hasEnemyFigure(gt, map, x1, y, mirror) == 2); if (!res && validPoint(gt, map, x2, y, mirror)) res = (hasEnemyFigure(gt, map, x2, y, mirror) == 2); if (!res && validPoint(gt, map, x1, y1, mirror)) res = (hasEnemyFigure(gt, map, x1, y1, mirror) == 2); if (!res && validPoint(gt, map, x, y1, mirror)) res = (hasEnemyFigure(gt, map, x, y1, mirror) == 2); if (!res && validPoint(gt, map, x2, y1, mirror)) res = (hasEnemyFigure(gt, map, x2, y1, mirror) == 2); return (res); } bool Figure::hasPoint(const Q3PointArray &vl, int x, int y) { int i, xp, yp, cnt; bool res = false; cnt = vl.count(); for (i = 0; i < cnt; ++i) { vl.point(i, &xp, &yp); if ((xp == x) && (yp == y)) { res = true; break; } } return (res); } bool Figure::validPoint(GameBoard::GameType gt, GameBoard::FigureType *map, int x, int y, bool mirror) { bool res; res = ((x >0) && (x < 9) && (y >0) && (y < 9)); if (res) res = !hasMyFigure(gt, map, x, y, mirror); return (res); } //----------------------------------------------------------------------------- GameBoard::GameBoard(GameType g, const QString &h, QWidget *parent, const char *name) :QWidget(parent, name, Qt::WResizeNoErase | Qt::WNoAutoErase) { setAttribute(Qt::WA_DeleteOnClose); QString str; protocol = new GameProtocol(); connect(protocol,SIGNAL(sendData(const QString&)), this, SIGNAL(sendData(const QString&))); gt = g; hst = h; setCursor(QCursor(Qt::WaitCursor)); if (gt == WHITE) str = tr("White"); else if (gt == BLACK) str = tr("Black"); str += ' ' + tr("game with") + ' '; setCaption(str + hst); setIcon(QPixmap((const char **)white_knight)); map = new FigureType[64]; initMap(); sock = new Q3Socket(this); drw = new Drawer(map, >, this); drw->setEnabled(false); drw->setFocusPolicy(Qt::NoFocus); box = new Q3GroupBox(tr("Game chat"), this); lst = new QListWidget(box); lst->setFocusPolicy(Qt::NoFocus); lst->setVScrollBarMode(Q3ScrollView::AlwaysOff); lst->setSelectionMode(QListWidget::NoSelection); edt = new QLineEdit(box); edt->setEnabled(false); setFocusProxy(edt); hist = new Q3GroupBox(tr("History"), this); hist->setAlignment(Qt::AlignHCenter); hist->setFocusPolicy(Qt::NoFocus); hw = new QListWidget(hist); hw->setSelectionMode(QListWidget::NoSelection); hw->setPaletteBackgroundColor(cw); hb = new QListWidget(hist); hb->setSelectionMode(QListWidget::NoSelection); hb->setPaletteBackgroundColor(cb); //tmr = new QTimer(this); //sock_tout = SOCK_WAIT; my_stat = tr("Looking up the host") + ' ' + hst + "..."; /*QObject::connect(sock, SIGNAL(hostFound()), this, SLOT(showHostFound())); QObject::connect(sock, SIGNAL(connected()), this, SLOT(sockConnected())); QObject::connect(sock, SIGNAL(readyRead()), this, SLOT(sockRead())); QObject::connect(sock, SIGNAL(connectionClosed()), this, SLOT(sockClosed())); QObject::connect(sock, SIGNAL(error(int)), this, SLOT(sockError(int)));*/ QObject::connect(drw, SIGNAL(moved(const QString&)), this, SLOT(sendMove(const QString&))); QObject::connect(drw, SIGNAL(newFigure(const QString&, GameBoard::FigureType)), this, SLOT(sendFigure(const QString&, GameBoard::FigureType))); QObject::connect(drw, SIGNAL(gameover(int)), this, SLOT(gameover(int))); QObject::connect(edt, SIGNAL(returnPressed()), this, SLOT(sendText())); //QObject::connect(tmr, SIGNAL(timeout()), this, SLOT(sockTest())); resize(XSize, YSize); setMinimumSize(size()); setMaximumSize(size()); //sock->connectToHost(hst, GAME_PORT); //tmr->start(1000); //hackyhackhack tmr = new QTimer(this); connect(tmr, SIGNAL(timeout()), this, SLOT(showHostFound())); tmr->start(1000); tmr2 = new QTimer(this); connect(tmr2, SIGNAL(timeout()), this, SLOT(sockConnected())); tmr2->start(2000); qDebug("GameBoard inited, type 1"); } GameBoard::GameBoard(int sfd, QWidget *parent, const char *name) :QWidget(parent, name, Qt::WResizeNoErase | Qt::WNoAutoErase | Qt::WDestructiveClose) { gt = NOGAME; setCursor(QCursor(Qt::WaitCursor)); setIcon(QPixmap((const char **)white_knight)); map = new FigureType[64]; memset(map, NONE, 64 * sizeof(*map)); protocol = new GameProtocol(); connect(protocol,SIGNAL(sendData(const QString&)), this, SIGNAL(sendData(const QString&))); sock = new Q3Socket(this); drw = new Drawer(map, >, this); drw->setEnabled(false); drw->setFocusPolicy(Qt::NoFocus); box = new Q3GroupBox(tr("Game chat"), this); lst = new QListWidget(box); lst->setFocusPolicy(Qt::NoFocus); lst->setVScrollBarMode(Q3ScrollView::AlwaysOff); lst->setSelectionMode(QListWidget::NoSelection); edt = new QLineEdit(box); setFocusProxy(edt); hist = new Q3GroupBox(tr("History"), this); hist->setAlignment(Qt::AlignHCenter); hist->setFocusPolicy(Qt::NoFocus); hw = new QListWidget(hist); hw->setSelectionMode(QListWidget::NoSelection); hw->setPaletteBackgroundColor(cw); hb = new QListWidget(hist); hb->setSelectionMode(QListWidget::NoSelection); hb->setPaletteBackgroundColor(cb); //sock->setSocket(sfd); //sock_tout = SOCK_WAIT; my_stat = tr("Accepted a new connection"); /*QObject::connect(sock, SIGNAL(hostFound()), this, SLOT(showHostFound())); QObject::connect(sock, SIGNAL(connected()), this, SLOT(sockConnected())); QObject::connect(sock, SIGNAL(readyRead()), this, SLOT(sockRead())); QObject::connect(sock, SIGNAL(connectionClosed()), this, SLOT(sockClosed())); QObject::connect(sock, SIGNAL(error(int)), this, SLOT(sockError(int)));*/ QObject::connect(drw, SIGNAL(moved(const QString&)), this, SLOT(sendMove(const QString&))); QObject::connect(drw, SIGNAL(newFigure(const QString&, GameBoard::FigureType)), this, SLOT(sendFigure(const QString&, GameBoard::FigureType))); QObject::connect(drw, SIGNAL(gameover(int)), this, SLOT(gameover(int))); QObject::connect(edt, SIGNAL(returnPressed()), this, SLOT(sendText())); resize(XSize, YSize); setMinimumSize(size()); setMaximumSize(size()); //hackyhackhack tmr = new QTimer(this); //connect(tmr, SIGNAL(timeout()), this, SLOT(showHostFound())); //tmr->start(1000); tmr2 = new QTimer(this); //connect(tmr2, SIGNAL(timeout()), this, SLOT(sockConnected())); //tmr2->start(2000); qDebug("GameBoard initialised (type 2)"); } GameBoard::~GameBoard() { protocol->sendQuit(sock); delete tmr; delete tmr2; delete hb; delete hw; delete hist; delete edt; delete lst; delete box; delete drw; delete sock; delete[] map; delete protocol; } void GameBoard::resizeEvent(QResizeEvent *e) { QFontMetrics fm(font()); int w = e->size().width(), h = e->size().height(), fh = fm.lineSpacing() + 4; QWidget::resizeEvent(e); drw->move(0, 0); box->move(drw->x(), drw->y() + drw->height()); box->resize(w, h - box->y()); edt->move(2, box->height() - fh - 2); edt->resize(box->width() - edt->x() * 2, fh); lst->move(edt->x(), fm.lineSpacing()); lst->resize(edt->width(), edt->y() - lst->y()); hist->move(drw->x() + drw->width(), drw->y()); hist->resize(w - hist->x(), box->y()); hw->move(2, QFontMetrics(hist->font()).lineSpacing()); hw->resize((hist->width() - hw->x()) / 2, hist->height() - hw->y() - 2); hb->move(hw->x() + hw->width(), hw->y()); hb->resize(hw->size()); } void GameBoard::focusInEvent(QFocusEvent *e) { QWidget::focusInEvent(e); emit showStatus(my_stat); } void GameBoard::initMap() { memset(map, NONE, 64 * sizeof(*map)); if (gt == WHITE) { map[0] = BLACK_CASTLE; map[1] = BLACK_KNIGHT; map[2] = BLACK_BISHOP; map[3] = BLACK_QUEEN; map[4] = BLACK_KING; map[5] = BLACK_BISHOP; map[6] = BLACK_KNIGHT; map[7] = BLACK_CASTLE; map[8] = BLACK_PAWN; map[9] = BLACK_PAWN; map[10] = BLACK_PAWN; map[11] = BLACK_PAWN; map[12] = BLACK_PAWN; map[13] = BLACK_PAWN; map[14] = BLACK_PAWN; map[15] = BLACK_PAWN; map[48] = WHITE_PAWN; map[49] = WHITE_PAWN; map[50] = WHITE_PAWN; map[51] = WHITE_PAWN; map[52] = WHITE_PAWN; map[53] = WHITE_PAWN; map[54] = WHITE_PAWN; map[55] = WHITE_PAWN; map[56] = WHITE_CASTLE; map[57] = WHITE_KNIGHT; map[58] = WHITE_BISHOP; map[59] = WHITE_QUEEN; map[60] = WHITE_KING; map[61] = WHITE_BISHOP; map[62] = WHITE_KNIGHT; map[63] = WHITE_CASTLE; } else { map[0] = WHITE_CASTLE; map[1] = WHITE_KNIGHT; map[2] = WHITE_BISHOP; map[3] = WHITE_KING; map[4] = WHITE_QUEEN; map[5] = WHITE_BISHOP; map[6] = WHITE_KNIGHT; map[7] = WHITE_CASTLE; map[8] = WHITE_PAWN; map[9] = WHITE_PAWN; map[10] = WHITE_PAWN; map[11] = WHITE_PAWN; map[12] = WHITE_PAWN; map[13] = WHITE_PAWN; map[14] = WHITE_PAWN; map[15] = WHITE_PAWN; map[48] = BLACK_PAWN; map[49] = BLACK_PAWN; map[50] = BLACK_PAWN; map[51] = BLACK_PAWN; map[52] = BLACK_PAWN; map[53] = BLACK_PAWN; map[54] = BLACK_PAWN; map[55] = BLACK_PAWN; map[56] = BLACK_CASTLE; map[57] = BLACK_KNIGHT; map[58] = BLACK_BISHOP; map[59] = BLACK_KING; map[60] = BLACK_QUEEN; map[61] = BLACK_BISHOP; map[62] = BLACK_KNIGHT; map[63] = BLACK_CASTLE; } } void GameBoard::showHostFound() { tmr->stop(); my_stat = tr("The host found"); emit showStatus(my_stat); qDebug("showHostFound"); } void GameBoard::sockConnected() { tmr2->stop(); my_stat = tr("Connected to the host"); emit showStatus(my_stat); protocol->setGameType(sock, gt); edt->setEnabled(true); qDebug("sockConnected"); } void GameBoard::receiveData(const QString& data) { sockRead(data); } void GameBoard::sockRead(const QString& data) { parseString(data); } void GameBoard::sockClosed() { close(); } void GameBoard::sockError(int err) { QString e; QMessageBox::critical(this, tr("Socket Error..."), tr("You have a socket error number") + ' ' + QString::number(err)); } void GameBoard::parseString(const QString &str) { QStringList lst(QStringList::split(SEP, str)); QString s(lst[0].lower()); int id; if (s == "game") { s = lst[1].lower(); if (s == "mate") { updateHistory(GAMEOVER_TXT, true); gt = NOGAME; gameover(0); close(); } else if (s == "stalemate") { gt = NOGAME; gameover(3); close(); } else if (s != "accept") { if (s == "white") { gt = BLACK; s = tr("White"); } else if (s == "black") { gt = WHITE; s = tr("Black"); drw->setEnabled(true); setCursor(QCursor(Qt::ArrowCursor)); } s += ' ' + tr("game from") + ' '; my_stat = tr("Accepted the") + ' ' + s; hst = sock->peerName(); if (hst.isEmpty()) hst = sock->peerAddress().toString() + ':' + QString::number(sock->peerPort()); initMap(); drw->repaint(true); protocol->acceptGame(sock); setCaption(s + hst); my_stat += hst; emit showStatus(my_stat); } else if (gt == WHITE) { drw->setEnabled(true); setCursor(QCursor(Qt::ArrowCursor)); } } else if (s == "move") { if (!drw->isEnabled()) { drw->setEnabled(true); s = lst[1].lower(); updateHistory(s, true); drw->makeMove(s); setCursor(QCursor(Qt::ArrowCursor)); my_stat = tr("Your move..."); emit showStatus(my_stat); } } else if (s == "quit") { gt = NOGAME; sockClosed(); } else if (s == "chat") { s = str.right(str.length() - 5); updateChat('>' + s); } else if (s == "figure") { s = lst[1].lower(); id = lst[2].toInt(); drw->newFigure(s, id); updateHistory(id, true); } } void GameBoard::sendMove(const QString &str) { protocol->sendMove(sock, str); emit sendData(str); drw->setEnabled(false); setCursor(QCursor(Qt::WaitCursor)); updateHistory(str, false); sock_tout = SOCK_WAIT; my_stat = tr("Waiting a move..."); emit showStatus(my_stat); } void GameBoard::closeEvent(QCloseEvent *e) { int res; if (gt != NOGAME) { res = QMessageBox::question(this, tr("End the game"), tr("Want you to end the game?\nYou will lose it"), tr("Yes, end"), tr("No, continue"), QString::null, 1); if (res == 0) QWidget::closeEvent(e); } else QWidget::closeEvent(e); } void GameBoard::sendText() { QString s; s = edt->text().utf8(); if (!s.isEmpty()) { updateChat(s); protocol->sendText(sock, s.ascii()); } edt->clear(); } void GameBoard::updateChat(const QString &s) { int fh, h; lst->insertItem(QString::fromUtf8(s.ascii())); h = lst->height(); fh = QFontMetrics(lst->font()).lineSpacing(); if ((int)lst->count() * fh >= lst->visibleHeight()) lst->removeItem(0); } void GameBoard::updateHistory(const QString &st, bool t) { QString s; if (st.length() == 3) { if (st[0] == '@') s = "O-O"; else s = st; } else s = st.left(2) + " - " + st.right(2); if (t) { if (gt == WHITE) hb->insertItem(s); else if (gt == BLACK) hw->insertItem(s); } else { if (gt == WHITE) hw->insertItem(s); else if (gt == BLACK) hb->insertItem(s); } } void GameBoard::updateHistory(int id, bool t) { QString s("; "), s1; switch (id) { case 3: s += tr("B"); break; case 4: s += tr("K"); break; case 5: s += tr("C"); break; case 10: s += tr("Q"); break; default: s += tr("Error!"); } if (t) { if (gt == WHITE) { id = hb->count() - 1; s1 = hb->text(id); hb->changeItem(s1 + s, id); } else if (gt == BLACK) { id = hw->count() - 1; s1 = hw->text(id); hw->changeItem(s1 + s, id); } } else { if (gt == WHITE) { id = hw->count() - 1; s1 = hw->text(id); hw->changeItem(s1 + s, id); } else if (gt == BLACK) { id = hb->count() - 1; s1 = hb->text(id); hb->changeItem(s1 + s, id); } } } void GameBoard::sendFigure(const QString &coo, GameBoard::FigureType ft) { int id = -1; switch (ft) { case BLACK_CASTLE: case WHITE_CASTLE: id = 5; break; case BLACK_BISHOP: case WHITE_BISHOP: id = 3; break; case BLACK_KNIGHT: case WHITE_KNIGHT: id = 4; break; case BLACK_QUEEN: case WHITE_QUEEN: id = 10; break; default: id = -1; } if (id != -1) { protocol->sendFigure(sock, coo, id); updateHistory(id, false); } } void GameBoard::sockTest() { --sock_tout; if (sock_tout < 0) { tmr->stop(); HAXEP: gt = NOGAME; sockClosed(); } else if ((sock->state() == QAbstractSocket::HostLookupState) && (sock_tout + 60 < SOCK_WAIT)) { tmr->stop(); QMessageBox::critical(this, tr("Lookup Error"), tr("The host") + ' ' + hst + ' ' + tr("not found.")); goto HAXEP; } } void GameBoard::saveImage() { QString fn; fn = Q3FileDialog::getSaveFileName(QString::null, "*.png", this, NULL, tr("Save image")); if (!fn.isEmpty()) { if (fn.findRev(".png") < (int)(fn.length() - 4)) fn += ".png"; QPixmap::grabWidget(this).save(fn, "PNG"); } } void GameBoard::gameover(int type) { bool save = false; QString s('\n' + tr("Do you want to save the image?")), yes(tr("Yes, save")), no(tr("No, don't save")), go(tr("Game over")); if (type == 0) { save = (QMessageBox::question(this, go, tr("You scored the game") + s, yes, no) == 0); } else if (type == 2) { updateHistory(GAMEOVER_TXT, false); protocol->sendGameover(sock, "MATE"); save = (QMessageBox::question(this, go, tr("You have a mate.\nYou lost the game.") + s, yes, no) == 0); } else if (type == 3) { protocol->sendGameover(sock, "STALEMATE"); save = (QMessageBox::question(this, go, tr("You have a stalemate") + s, yes, no) == 0); } if (save) saveImage(); } //----------------------------------------------------------------------------- Drawer::Drawer(GameBoard::FigureType *ft, GameBoard::GameType *g, QWidget *parent, const char *name) :QWidget(parent, name, Qt::WResizeNoErase | Qt::WNoAutoErase) { QFontMetrics fm(font()); int i; map = ft; gt = g; kk = rcm = lcm = km = false; cs = cell_size * 8; top_margin = 5; for (left_margin = 0, i = 0; i < 8; i++) left_margin = MAX(fm.width(QString::number(i)), left_margin); left_margin += top_margin; hl = fm.lineSpacing() + 2; setPaletteBackgroundColor(Qt::white); i = MAX(cs + left_margin + top_margin, cs + top_margin + hl); resize(i, i); x_brd = i - cs - 6; y_brd = 4; tfx = tfy = -1; fig[0] = QPixmap((const char **)black_bishop); fig[1] = QPixmap((const char **)black_castle); fig[2] = QPixmap((const char **)black_knight); fig[3] = QPixmap((const char **)black_pawn); fig[4] = QPixmap((const char **)black_king); fig[5] = QPixmap((const char **)black_queen); fig[6] = QPixmap((const char **)white_bishop); fig[7] = QPixmap((const char **)white_castle); fig[8] = QPixmap((const char **)white_knight); fig[9] = QPixmap((const char **)white_pawn); fig[10] = QPixmap((const char **)white_king); fig[11] = QPixmap((const char **)white_queen); } Drawer::~Drawer() { } void Drawer::paintEvent(QPaintEvent *e) { QPainter *p; int w, y; w = width(); y = w - 4; QWidget::paintEvent(e); p = new QPainter(this); p->setPen(Qt::black); p->drawRect(0, 0, w, w); p->drawRect(2, 2, y, y); p->drawLine(2, y, x_brd, cs + 4); drawBoard(p, x_brd, y_brd); drawMap(p, x_brd, y_brd); delete p; } void Drawer::drawBoard(QPainter *p, int x, int y) { int i, j, cs, x1, r, k; char c, st; cs = Drawer::cs + 2; p->setPen(Qt::black); p->drawRect(x, y, cs, cs); c = 'a'; st = 1; r = (*gt == GameBoard::BLACK); if (r) { c += 7; st = -st; k = 1; r ^= 1; } else k = 8; x1 = x + 1; for (j = 0, y++; j < 8; j++, y += cell_size, r ^= 1) { for (i = 0, x = x1; i < 8; i++, x += cell_size) { r ^= 1; if (r) { p->setPen(cw); p->setBrush(cw); } else { p->setPen(cb); p->setBrush(cb); } p->drawRect(x, y, cell_size, cell_size); if (j == 7) { p->setPen(Qt::black); p->drawText(x, cs + 2, cell_size, hl, Qt::AlignCenter, QChar(c)); c += st; } } p->setPen(Qt::black); p->drawText(x1 - left_margin, y, left_margin, cell_size, Qt::AlignCenter, QString::number(k)); k -= st; } if ((tfx != -1) && (tfy != -1)) { map2win(tfx, tfy, x, y); p->setPen(QPen(Qt::red, 2)); p->setBrush(Qt::NoBrush); p->drawRect(x, y, cell_size, cell_size); } } void Drawer::drawMap(QPainter *p, int x, int y) { int i, j, x1, n; QPixmap *xpm; x1 = x + 1; y++; for (n = j = 0; j < 8; j++, y += cell_size) { for (i = 0, x = x1; i < 8; i++, x += cell_size) { switch (map[n++]) { case GameBoard::WHITE_PAWN: xpm = &fig[9]; break; case GameBoard::WHITE_CASTLE: xpm = &fig[7]; break; case GameBoard::WHITE_BISHOP: xpm = &fig[6]; break; case GameBoard::WHITE_KING: xpm = &fig[10]; break; case GameBoard::WHITE_QUEEN: xpm = &fig[11]; break; case GameBoard::WHITE_KNIGHT: xpm = &fig[8]; break; case GameBoard::BLACK_PAWN: xpm = &fig[3]; break; case GameBoard::BLACK_CASTLE: xpm = &fig[1]; break; case GameBoard::BLACK_BISHOP: xpm = &fig[0]; break; case GameBoard::BLACK_KING: xpm = &fig[4]; break; case GameBoard::BLACK_QUEEN: xpm = &fig[5]; break; case GameBoard::BLACK_KNIGHT: xpm = &fig[2]; break; default: xpm = NULL; } if (xpm != NULL) p->drawPixmap(x, y, *xpm); } } } void Drawer::mousePressEvent(QMouseEvent *e) { int x = e->x() - x_brd, y = e->y() - y_brd; if ((x >= 0) && (x <= cs) && (y >= 0) && (y <= cs)) { win2map(x, y); if (hasTakenFigure()) { if ((tfx == x) && (tfy == y)) { tfx = tfy = -1; repaint(false); } else makeMove(*gt, tfx, tfy, x, y, false, false); } else if (canTake(x, y)) { takeFigure(x, y); emit touchFigure(x, y); } } } bool Drawer::canTake(int x, int y) { return (Figure::hasMyFigure(*gt, map, x, y, false)); } void Drawer::win2map(int &x, int &y) { if (*gt == GameBoard::WHITE) { x /= cell_size; y = 8 - y / cell_size; x++; } else if (*gt == GameBoard::BLACK) { x = 8 - x / cell_size; y /= cell_size; y++; } } void Drawer::map2win(int mx, int my, int &x, int &y) { if (*gt == GameBoard::WHITE) { x = (mx - 1) * cell_size + x_brd + 1; y = (8 - my) * cell_size + y_brd + 1; } else if (*gt == GameBoard::BLACK) { x = (8 - mx) * cell_size + x_brd + 1; y = (my - 1) * cell_size + y_brd + 1; } else { x = mx; y = my; } } void Drawer::takeFigure(int x, int y) { if ((tfx == x) && (tfy == y)) tfx = tfy = -1; else { tfx = x; tfy = y; } repaint(false); } bool Drawer::hasTakenFigure() { return ((tfx != -1) && (tfy != -1)); } void Drawer::newFigure(const QString &coo, int id) { GameBoard::FigureType ft; int x, y, n; ft = GameBoard::NONE; n = -1; Figure::str2map(coo, &x, &y); if (*gt == GameBoard::WHITE) { n = Figure::map2map(GameBoard::BLACK, x, y, true); switch (id) { case 3: ft = GameBoard::BLACK_BISHOP; break; case 4: ft = GameBoard::BLACK_KNIGHT; break; case 5: ft = GameBoard::BLACK_CASTLE; break; case 10: ft = GameBoard::BLACK_QUEEN; break; default: ft = GameBoard::NONE; } } else if (*gt == GameBoard::BLACK) { n = Figure::map2map(GameBoard::WHITE, x, y, true); switch (id) { case 3: ft = GameBoard::WHITE_BISHOP; break; case 4: ft = GameBoard::WHITE_KNIGHT; break; case 5: ft = GameBoard::WHITE_CASTLE; break; case 10: ft = GameBoard::WHITE_QUEEN; break; default: ft = GameBoard::NONE; } } if (ft != GameBoard::NONE) { map[n] = ft; repaint(false); } } void Drawer::makeMove(const QString &txt) { int fx, fy, tx, ty; GameBoard::GameType et; if (*gt == GameBoard::WHITE) et = GameBoard::BLACK; else if (*gt == GameBoard::BLACK) et = GameBoard::WHITE; else et = GameBoard::NOGAME; if (txt == LONG_XCHG) { if (et == GameBoard::BLACK) makeMove(et, 1, 8, 4, 8, true, true); else if (et == GameBoard::WHITE) makeMove(et, 1, 1, 4, 1, true, true); } else if (txt == SHORT_XCHG) { if (et == GameBoard::BLACK) makeMove(et, 8, 8, 6, 8, true, true); else if (et == GameBoard::WHITE) makeMove(et, 8, 1, 6, 1, true, true); } else { Figure::str2map(txt.left(2), &fx, &fy); Figure::str2map(txt.right(2), &tx, &ty); makeMove(et, fx, fy, tx, ty, true, false); } } void Drawer::makeMove(GameBoard::GameType gt, int fx, int fy, int tx, int ty, bool mirror, bool xc) { GameBoard::GameType et; GameBoard::FigureType fo, old; int res, nf, nt; FigureDialog *dlg; bool x; Q3PointArray vl; et = GameBoard::NOGAME; nf = Figure::map2map(gt, fx, fy, mirror); fo = map[nf]; nt = Figure::map2map(gt, tx, ty, mirror); old = map[nt]; res = Figure::validMove(gt, map, fx, fy, tx, ty, mirror); if (res) { if (!mirror) { x = false; if (gt == GameBoard::WHITE) et = GameBoard::BLACK; else if (gt == GameBoard::BLACK) et = GameBoard::WHITE; if (Figure::checkKing(et, map, mirror, vl, true) != 0) { map[nf] = map[nt]; map[nt] = old; tfx = tfy = -1; QMessageBox::information(this, tr("Error moving"), tr("You cannot " "move this figure because the king " "is in check") + '.'); goto HAXEP; } else kk = false; if (!km && (!lcm || !rcm) && !kk) x = xchg(fo, map[nt], fx, fy, tx, ty); else x = true; if (x) emit moved(Figure::map2str(fx, fy) + Figure::map2str(tx, ty)); if ((res & 0xF) == 2) { dlg = new FigureDialog(fig, gt, this); dlg->exec(); fo = dlg->figure(); delete dlg; map[nt] = fo; emit newFigure(Figure::map2str(tx, ty), fo); } tfx = tfy = -1; } else if (xc) { if (gt == GameBoard::BLACK) checkBlackCastle(fx, fy, tx, ty, true); else if (gt == GameBoard::WHITE) checkWhiteCastle(fx, fy, tx, ty, true); } if (mirror && (res & 0x10)) { kk = true; } else if (res & 0x20) { repaint(false); emit gameover(2); return; } else if (res & 0x40) { repaint(false); emit gameover(3); return; } HAXEP: repaint(false); } } bool Drawer::xchg(GameBoard::FigureType o, GameBoard::FigureType n, int fx, int fy, int tx, int ty) { bool ret = true; if (*gt == GameBoard::WHITE) { km = ((o == n) && (o == GameBoard::WHITE_KING)); if (!km && ((o == n) && (o == GameBoard::WHITE_CASTLE))) ret = checkWhiteCastle(fx, fy, tx, ty, false); } else if (*gt == GameBoard::BLACK) { km = ((o == n) && (o == GameBoard::BLACK_KING)); if (!km && ((o == n) && (o == GameBoard::BLACK_CASTLE))) ret = checkBlackCastle(fx, fy, tx, ty, false); } return (ret); } bool Drawer::checkWhiteCastle(int fx, int fy, int tx, int ty, bool mirror) { int n1, n2; bool ret = true; n1 = n2 = -1; if ((fx == 1) && (fy == 1)) { if ((tx == 4) && (ty == 1)) if (mirror) { n1 = Figure::map2map(*gt, 5, 1, false); n2 = Figure::map2map(*gt, 3, 1, false); } else if (!lcm) { if (makeXchg()) { n1 = Figure::map2map(*gt, 5, 1, false); n2 = Figure::map2map(*gt, 3, 1, false); emit moved(LONG_XCHG); ret = false; rcm = true; } lcm = true; } } else if ((fx == 8) && (fy == 1)) { if ((tx == 6) && (ty == 1)) if (mirror) { n1 = Figure::map2map(*gt, 5, 1, false); n2 = Figure::map2map(*gt, 7, 1, false); } else if (!rcm) { if (makeXchg()) { n1 = Figure::map2map(*gt, 5, 1, false); n2 = Figure::map2map(*gt, 7, 1, false); emit moved(SHORT_XCHG); ret = false; lcm = true; } rcm = true; } } if (n1 != n2) { map[n2] = map[n1]; map[n1] = GameBoard::NONE; } return (ret); } bool Drawer::checkBlackCastle(int fx, int fy, int tx, int ty, bool mirror) { int n1, n2; bool ret = true; n1 = n2 = -1; if ((fx == 1) && (fy == 8)) { if ((tx == 4) && (ty == 8)) { if (mirror) { n1 = Figure::map2map(*gt, 5, 8, false); n2 = Figure::map2map(*gt, 3, 8, false); } else if (!rcm) { if (makeXchg()) { n1 = Figure::map2map(*gt, 5, 8, false); n2 = Figure::map2map(*gt, 3, 8, false); emit moved(LONG_XCHG); ret = false; } rcm = true; } } } else if ((fx == 8) && (fy == 8)) { if ((tx == 6) && (ty == 8)) if (mirror) { n1 = Figure::map2map(*gt, 5, 8, false); n2 = Figure::map2map(*gt, 7, 8, false); } else if (!lcm) { if (makeXchg()) { n1 = Figure::map2map(*gt, 5, 8, false); n2 = Figure::map2map(*gt, 7, 8, false); emit moved(SHORT_XCHG); ret = false; } lcm = true; } } if (n1 != n2) { map[n2] = map[n1]; map[n1] = GameBoard::NONE; } return (ret); } bool Drawer::makeXchg() { return (QMessageBox::question(this, tr("To castle"), tr("Do you want to castle?"), tr("Yes"), tr("No")) == 0); } //----------------------------------------------------------------------------- FigureDialog::FigureDialog(const QPixmap *f, const GameBoard::GameType g, QWidget *parent, const char *name):QDialog(parent, name) { QFontMetrics fm(font()); int w, h; gt = g; fig = f; if (gt == GameBoard::WHITE) fr = GameBoard::WHITE_QUEEN; else if (gt == GameBoard::BLACK) fr = GameBoard::BLACK_QUEEN; str = tr("What figure should I set?"); setCaption(str); fh = fm.lineSpacing() + 2; h = cell_size + fh; w = MAX(cell_size * 4, fm.width(str)); step = (w - cell_size * 4) / 2; resize(w, h); setMinimumSize(size()); setMaximumSize(size()); } FigureDialog::~FigureDialog() { } void FigureDialog::paintEvent(QPaintEvent *e) { QPainter *p; int x, f = -1; QDialog::paintEvent(e); p = new QPainter(this); p->setPen(Qt::black); p->drawText(0, 0, width(), fh, Qt::AlignCenter, str); x = step; if (gt == GameBoard::BLACK) f = 0; else if (gt == GameBoard::WHITE) f = 6; p->drawPixmap(x, fh, fig[f]); x += cell_size; p->drawPixmap(x, fh, fig[f + 1]); x += cell_size; p->drawPixmap(x, fh, fig[f + 2]); x += cell_size; p->drawPixmap(x, fh, fig[f + 5]); delete p; } void FigureDialog::mousePressEvent(QMouseEvent *e) { int x = e->x(), y = e->y(), f = -1; if (e->button() == Qt::LeftButton) { if ((x >= step) && (x <= width() - step) && (y >= fh) && (y <= height())) f = (x - step) / cell_size; } if (f != -1) { if (gt == GameBoard::WHITE) switch (f) { case 0: fr = GameBoard::WHITE_BISHOP; break; case 1: fr = GameBoard::WHITE_CASTLE; break; case 2: fr = GameBoard::WHITE_KNIGHT; break; case 3: default: fr = GameBoard::WHITE_QUEEN; } else if (gt == GameBoard::BLACK) switch (f) { case 0: fr = GameBoard::BLACK_BISHOP; break; case 1: fr = GameBoard::BLACK_CASTLE; break; case 2: fr = GameBoard::BLACK_KNIGHT; break; case 3: default: fr = GameBoard::BLACK_QUEEN; } accept(); } } //----------------------------------------------------------------------------- void GameProtocol::send(Q3Socket *sock, const QString &dat) { /*QString s(dat + EOL); const char *buf; if (sock->state() == Q3Socket::Connected) { buf = s.ascii(); sock->writeBlock(buf, s.length()); sock->flush(); }*/ qDebug() << (qPrintable(QString("GameProtocol::send(%1)").arg(dat))); emit sendData(dat); } void GameProtocol::setGameType(Q3Socket *sock, GameBoard::GameType gt) { QString d("GAME"); d += SEP; if (gt == GameBoard::WHITE) d += "WHITE"; else if (gt == GameBoard::BLACK) d += "BLACK"; else d += "NOGAME"; send(sock, d); } void GameProtocol::acceptGame(Q3Socket *sock) { QString d("GAME"); d += SEP; d += "ACCEPT"; send(sock, d); } void GameProtocol::sendMove(Q3Socket *sock, const QString &coo) { QString d("MOVE"); d += SEP; d += coo; send(sock, d); } void GameProtocol::sendQuit(Q3Socket *sock) { send(sock, "QUIT"); } void GameProtocol::sendText(Q3Socket *sock, const QString &txt) { QString d("CHAT"); d += SEP; d += txt; send(sock, d); } void GameProtocol::sendFigure(Q3Socket *sock, const QString &coo, int id) { QString d("FIGURE"); d += SEP; d += coo; d += SEP; d += QString::number(id); send(sock, d); } void GameProtocol::sendGameover(Q3Socket *sock, const QString &got) { QString d("GAME"); d += SEP; d += got; send(sock, d); } psi-0.14/src/plugins/generic/chess/main.cpp0000644000175000017500000000177311305557613016772 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: main.cpp,v 0.1 2005/01/08 12:19:58 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: */ #include #include #include //Added by qt3to4: #include #include "mainwindow.h" const int XSize = 800, YSize = 600; int main(int argc, const char *argv[]) { QApplication *app; MainWindow *mw; QTranslator *qt; int result = 0; app = new QApplication(argc, (char **)argv); /*qt = new QTranslator(); if (qt->load(LOCALE_FILE)) app->installTranslator(qt);*/ mw = new MainWindow(); if (mw->sockOk()) { app->setMainWidget(mw); mw->show(); mw->resize(XSize, YSize); mw->setMinimumSize(mw->size()); result = app->exec(); } else QMessageBox::critical(NULL, QObject::tr("Socket Error"), QObject::tr("Cannot create a server socket!")); delete mw; delete qt; delete app; return (result); } psi-0.14/src/plugins/generic/chess/gamesocket.h0000644000175000017500000000121311305557613017622 0ustar janjan/* * Copyright (c) 2005 by SilverSoft.Net * All rights reserved * * $Id: gamesocket.h,v 0.1 2005/01/08 12:31:24 denis Exp $ * * Author: Denis Kozadaev (denis@silversoft.net) * Description: * * See also: style(9) * * Hacked by: */ #ifndef __GAME_SOCKET_H__ #define __GAME_SOCKET_H__ #include #include #define GAME_PORT 1345 #define GAME_BACKLOG 5 class GameSocket:public Q3ServerSocket { Q_OBJECT public: GameSocket(QWidget *parent = NULL, const char *name = NULL); ~GameSocket(); private: protected: void newConnection(int); signals: void acceptConnection(int); }; #endif /* __GAME_SOCKET_H__ */ psi-0.14/src/plugins/generic/chess/chess-standalone.pro0000644000175000017500000000167411305557613021317 0ustar janjan###################################################################### # Automatically generated by qmake (2.00a) Sun Jul 16 13:47:06 2006 ###################################################################### TEMPLATE = app TARGET += DEPENDPATH += . INCLUDEPATH += . # Input HEADERS += gameboard.h \ gamesocket.h \ mainwindow.h \ xpm/black_bishop.xpm \ xpm/black_castle.xpm \ xpm/black_king.xpm \ xpm/black_knight.xpm \ xpm/black_pawn.xpm \ xpm/black_queen.xpm \ xpm/white_bishop.xpm \ xpm/white_castle.xpm \ xpm/white_king.xpm \ xpm/white_knight.xpm \ xpm/white_pawn.xpm \ xpm/white_queen.xpm \ xpm/chess.xpm \ xpm/quit.xpm \ xpm/new_game.xpm SOURCES += gameboard.cpp gamesocket.cpp main.cpp mainwindow.cpp #The following line was inserted by qt3to4 QT += network psi-0.14/src/plugins/generic/noughtsandcrosses/0000755000175000017500000000000011305557613020001 5ustar janjanpsi-0.14/src/plugins/generic/noughtsandcrosses/noughtsandcrossesplugin.pro0000644000175000017500000000016311305557613025516 0ustar janjaninclude(../../psiplugin.pri) HEADERS += tictac.h SOURCES += tictac.cpp SOURCES += noughtsandcrossesplugin.cpp psi-0.14/src/plugins/generic/noughtsandcrosses/noughtsandcrossesplugin.cpp0000644000175000017500000001471211305557613025505 0ustar janjan/* * noughtsandcrossesplugin.cpp - Psi plugin to play noughts and crosses * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "psiplugin.h" #include "eventfilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "tictac.h" class NoughtsAndCrossesPlugin : public QObject, public PsiPlugin, public EventFilter, public StanzaSender { Q_OBJECT Q_INTERFACES(PsiPlugin EventFilter StanzaSender) public: NoughtsAndCrossesPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options() const; virtual bool enable(); virtual bool disable(); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual bool processEvent(int account, const QDomElement& e); virtual bool processMessage(int account, const QString& fromJid, const QString& body, const QString& subject); private slots: void stopGame(); void myTurn(int space); void theirTurn(int space); void gameOver(TicTacGameBoard::State state); private: void startGame(QString jid, int size, bool meFirst, int account); TicTacToe* game; QString playingWith; int account_; bool enabled_; StanzaSendingHost* stanzaSender_; }; Q_EXPORT_PLUGIN(NoughtsAndCrossesPlugin); NoughtsAndCrossesPlugin::NoughtsAndCrossesPlugin() { game = NULL; enabled_ = false; stanzaSender_ = 0; } QString NoughtsAndCrossesPlugin::name() const { return "NoughtsAndCrosses Plugin"; } QString NoughtsAndCrossesPlugin::shortName() const { return "noughtsandcrosses"; } QString NoughtsAndCrossesPlugin::version() const { return "0.1"; } QWidget* NoughtsAndCrossesPlugin::options() const { return 0; } bool NoughtsAndCrossesPlugin::enable() { if (stanzaSender_) { enabled_ = true; } return enabled_; } bool NoughtsAndCrossesPlugin::disable() { stopGame(); enabled_ = false; return true; } void NoughtsAndCrossesPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender_ = host; } bool NoughtsAndCrossesPlugin::processEvent(int account, const QDomElement& e) { Q_UNUSED(account); Q_UNUSED(e); return false; } bool NoughtsAndCrossesPlugin::processMessage(int account, const QString& fromJid, const QString& message, const QString& subject) { // FIXME(mck) QString fromDisplay = fromJid; Q_UNUSED(subject); if (!enabled_) { return false; } QString reply; qDebug("naughtsandcrosses message"); if (!message.startsWith("noughtsandcrosses")) return false; qDebug("message for us in noughtsandcrosses"); if (game && fromJid != playingWith) { reply=QString("already playing with %2, sorry").arg(fromJid).arg(playingWith); stanzaSender_->sendStanza(account, reply); return true; } QString command = QString(message); command.remove(0,18); qDebug() << (qPrintable(QString("noughtsandcrosses command string %1").arg(command))); if (command == QString("start")) { if (game) return true; qWarning(qPrintable(QString("Received message '%1', launching nac with %2").arg(message).arg(fromDisplay))); QString reply; reply=QString("noughtsandcrosses starting").arg(fromJid); stanzaSender_->sendStanza(account, reply); startGame(fromJid, 3, false, account); } else if (command == QString("starting")) { if (game) return true; qWarning(qPrintable(QString("Received message '%1', launching nac with %2").arg(message).arg(fromDisplay))); QString reply; reply=QString("starting noughts and crosses, I go first :)").arg(fromJid); stanzaSender_->sendStanza(account, reply); startGame(fromJid, 3, true, account); } else if (!game) { return true; } else if (command.startsWith("move")) { command.remove(0,5); int space=command.toInt(); qDebug() << (qPrintable(QString("noughtsandcrosses move to space %1").arg(space))); theirTurn(space); } return true; } void NoughtsAndCrossesPlugin::startGame(QString jid, int size, bool meFirst, int account) { game = new TicTacToe( meFirst, size ); game->setCaption(QString("Noughts and Crosses with %1").arg(jid)); playingWith=jid; game->show(); account_=account; connect(game, SIGNAL(closing()), this, SLOT(stopGame())); connect(game, SIGNAL(myMove(int)), this, SLOT(myTurn(int))); connect(game, SIGNAL(gameOverSignal(TicTacGameBoard::State)), this, SLOT(gameOver(TicTacGameBoard::State))); } void NoughtsAndCrossesPlugin::stopGame() { delete game; game=NULL; } void NoughtsAndCrossesPlugin::gameOver(TicTacGameBoard::State state) { QString reply; QString winner; switch (state) { case TicTacGameBoard::HumanWon: winner="I"; break; case TicTacGameBoard::ComputerWon: winner="You"; break; case TicTacGameBoard::NobodyWon: winner="It was a draw, no-one"; break; default: winner="ERROR!!!"; } reply=QString("%2 won. Good game.").arg(playingWith).arg(winner); stanzaSender_->sendStanza(account_, reply); } void NoughtsAndCrossesPlugin::myTurn(int space) { qDebug() << (qPrintable(QString("my turn: %1").arg(space))); if (!game) return; QString reply; reply=QString("noughtsandcrosses move %2").arg(playingWith).arg(space); stanzaSender_->sendStanza(account_, reply); } void NoughtsAndCrossesPlugin::theirTurn(int space) { qDebug() << (qPrintable(QString("their turn: %1").arg(space))); if (!game) return; game->theirMove(space); } #include "noughtsandcrossesplugin.moc" psi-0.14/src/plugins/generic/noughtsandcrosses/tictac.h0000644000175000017500000000675511305557613021436 0ustar janjan /**************************************************************************** ** $Id: $ ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #ifndef TICTAC_H #define TICTAC_H #include #include //Added by qt3to4: #include #include class QComboBox; class QLabel; // -------------------------------------------------------------------------- // TicTacButton implements a single tic-tac-toe button // class TicTacButton : public QPushButton { Q_OBJECT public: TicTacButton( QWidget *parent ); enum Type { Blank, Circle, Cross }; Type type() const { return t; } void setType( Type type ) { t = type; QString mark=""; if (t==Circle) mark="0"; if (t==Cross) mark="X"; setText(mark); repaint(); } QSizePolicy sizePolicy() const { return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); } QSize sizeHint() const { return QSize( 32, 32 ); } QSize minimumSizeHint() const { return QSize( 10, 10 ); } //protected: // void drawButtonLabel( QPainter * ); private: Type t; }; // Using template vector to make vector-class of TicTacButton. // This vector is used by the TicTacGameBoard class defined below. typedef Q3PtrVector TicTacButtons; typedef Q3MemArray TicTacArray; // -------------------------------------------------------------------------- // TicTacGameBoard implements the tic-tac-toe game board. // TicTacGameBoard is a composite widget that contains N x N TicTacButtons. // N is specified in the constructor. // class TicTacGameBoard : public QWidget { Q_OBJECT public: TicTacGameBoard( bool meFirst, int n, QWidget *parent=0, const char *name=0 ); ~TicTacGameBoard(); enum State { Init, HumansTurn, ComputersTurn, HumanWon, ComputerWon, NobodyWon }; State state() const { return st; } void computerStarts( bool v ); void newGame(); signals: void finished(); // game finished void myMove(int space); void stateChanged(); public slots: void theirMove(int space); private slots: void buttonClicked(); private: void setState( State state ) { st = state; } void updateButtons(); int checkBoard( TicTacArray * ); void computerMove(); State st; int nBoard; bool comp_starts; TicTacArray *btArray; TicTacButtons *buttons; }; // -------------------------------------------------------------------------- // TicTacToe implements the complete game. // TicTacToe is a composite widget that contains a TicTacGameBoard and // two push buttons for starting the game and quitting. // class TicTacToe : public QWidget { Q_OBJECT public: TicTacToe( bool meFirst, int boardSize=3, QWidget *parent=0, const char *name=0 ); signals: void closing(); void myMove(int space); void gameOverSignal(TicTacGameBoard::State state); public slots: void theirMove(int space); private slots: void newGameClicked(); void gameOver(); void newState(); private: QComboBox *whoStarts; QPushButton *newGame; QPushButton *quit; QLabel *message; TicTacGameBoard *board; }; #endif // TICTAC_H psi-0.14/src/plugins/generic/noughtsandcrosses/tictac.cpp0000644000175000017500000003311111305557613021753 0ustar janjan/**************************************************************************** ** $Id: qt/tictac.cpp 3.0.6 edited Nov 14 2001 $ ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "tictac.h" #include #include #include #include #include #include #include //Added by qt3to4: #include #include #include #include #include #include // rand() function #include // seed for rand() //*************************************************************************** //* TicTacButton member functions //*************************************************************************** // -------------------------------------------------------------------------- // Creates a TicTacButton // TicTacButton::TicTacButton( QWidget *parent ) : QPushButton( parent ) { t = Blank; // initial type } // -------------------------------------------------------------------------- // Paints TicTacButton // /*void TicTacButton::drawButtonLabel( QPainter *p ) { QRect r = rect(); p->setPen( QPen( Qt::black,2 ) ); // set fat pen if ( t == Circle ) { p->drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 ); } else if ( t == Cross ) { // draw cross p->drawLine( r.topLeft() +QPoint(4,4), r.bottomRight()-QPoint(4,4)); p->drawLine( r.bottomLeft()+QPoint(4,-4),r.topRight() -QPoint(4,-4)); } }*/ //*************************************************************************** //* TicTacGameBoard member functions //*************************************************************************** // -------------------------------------------------------------------------- // Creates a game board with N x N buttons and connects the "clicked()" // signal of all buttons to the "buttonClicked()" slot. // TicTacGameBoard::TicTacGameBoard( bool meFirst, int n, QWidget *parent, const char *name ) : QWidget( parent, name ) { st = Init; // initial state nBoard = n; n *= n; // make square comp_starts = false; // human starts buttons = new TicTacButtons(n); // create real buttons btArray = new TicTacArray(n); // create button model Q3GridLayout * grid = new Q3GridLayout( this, nBoard, nBoard, 4 ); qDebug("added grid"); QPalette p( Qt::blue ); for ( int i=0; isetPalette( p ); ttb->setEnabled( false ); connect( ttb, SIGNAL(clicked()), SLOT(buttonClicked()) ); grid->addWidget( ttb, i%nBoard, i/nBoard ); buttons->insert( i, ttb ); btArray->at(i) = TicTacButton::Blank; // initial button type } QTime t = QTime::currentTime(); // set random seed srand( t.hour()*12+t.minute()*60+t.second()*60 ); computerStarts(!meFirst); } TicTacGameBoard::~TicTacGameBoard() { delete buttons; delete btArray; } // -------------------------------------------------------------------------- // TicTacGameBoard::computerStarts( bool v ) // // Computer starts if v=TRUE. The human starts by default. // void TicTacGameBoard::computerStarts( bool v ) { comp_starts = v; } // -------------------------------------------------------------------------- // TicTacGameBoard::newGame() // // Clears the game board and prepares for a new game // void TicTacGameBoard::newGame() { st = HumansTurn; for ( int i=0; iat(i) = TicTacButton::Blank; if ( comp_starts ) st = ComputersTurn; //computerMove(); //else updateButtons(); } // -------------------------------------------------------------------------- // TicTacGameBoard::buttonClicked() - SLOT // // This slot is activated when a TicTacButton emits the signal "clicked()", // i.e. the user has clicked on a TicTacButton. // void TicTacGameBoard::buttonClicked() { if ( st != HumansTurn ) // not ready return; int i = buttons->findRef( (TicTacButton*)sender() ); TicTacButton *b = buttons->at(i); // get piece that was pressed if ( b->type() == TicTacButton::Blank ) { // empty piece? btArray->at(i) = TicTacButton::Circle; emit myMove(i); st = ComputersTurn; updateButtons(); //if ( checkBoard( btArray ) == 0 ) // not a winning move? //computerMove(); int s = checkBoard( btArray ); if ( s ) { // any winners yet? st = s == TicTacButton::Circle ? HumanWon : ComputerWon; emit finished(); } } } void TicTacGameBoard::theirMove(int space) { if (st != ComputersTurn) return; qDebug() << (qPrintable(QString("they moved to %1 of %2").arg(space).arg(nBoard*nBoard))); if (space>=nBoard*nBoard) return; qDebug() << (qPrintable(QString("Space %1 was %2").arg(space).arg((int)(btArray->at(space))))); (*btArray)[space] = TicTacButton::Cross; qDebug() << (qPrintable(QString("Set %1 to %2 in btArray").arg(space).arg((int)(btArray->at(space))))); updateButtons(); qDebug("buttons updated"); int s = checkBoard( btArray ); st = HumansTurn; qDebug("board checked"); if ( s ) { // any winners yet? st = s == TicTacButton::Circle ? HumanWon : ComputerWon; emit finished(); } qDebug("thoir move finished"); } // -------------------------------------------------------------------------- // TicTacGameBoard::updateButtons() // // Updates all buttons that have changed state // void TicTacGameBoard::updateButtons() { for ( int i=0; iat(i)->type() != btArray->at(i) ) buttons->at(i)->setType( (TicTacButton::Type)btArray->at(i) ); buttons->at(i)->setEnabled( buttons->at(i)->type() == TicTacButton::Blank ); } emit stateChanged(); } // -------------------------------------------------------------------------- // TicTacGameBoard::checkBoard() // // Checks if one of the players won the game, works for any board size. // // Returns: // - TicTacButton::Cross if the player with X buttons won // - TicTacButton::Circle if the player with O buttons won // - Zero (0) if there is no winner yet // int TicTacGameBoard::checkBoard( TicTacArray *a ) { int t = 0; int row, col; bool won = false; for ( row=0; rowat(row*nBoard); if ( t == TicTacButton::Blank ) continue; col = 1; while ( colat(row*nBoard+col) == t ) col++; if ( col == nBoard ) won = true; } for ( col=0; colat(col); if ( t == TicTacButton::Blank ) continue; row = 1; while ( rowat(row*nBoard+col) == t ) row++; if ( row == nBoard ) won = true; } if ( !won ) { // check diagonal top left t = a->at(0); // to bottom right if ( t != TicTacButton::Blank ) { int i = 1; while ( iat(i*nBoard+i) == t ) i++; if ( i == nBoard ) won = true; } } if ( !won ) { // check diagonal bottom left int j = nBoard-1; // to top right int i = 0; t = a->at(i+j*nBoard); if ( t != TicTacButton::Blank ) { i++; j--; while ( iat(i+j*nBoard) == t ) { i++; j--; } if ( i == nBoard ) won = true; } } if ( !won ) // no winner t = 0; return t; } // -------------------------------------------------------------------------- // TicTacGameBoard::computerMove() // // Puts a piece on the game board. Very, very simple. // void TicTacGameBoard::computerMove() { int numButtons = nBoard*nBoard; int *altv = new int[numButtons]; // buttons alternatives int altc = 0; int stopHuman = -1; TicTacArray a = btArray->copy(); int i; for ( i=0; i= 0 ) // must stop human from winning a[stopHuman] = TicTacButton::Cross; else if ( i == numButtons ) { // tried all alternatives if ( altc > 0 ) // set random piece a[altv[rand()%(altc--)]] = TicTacButton::Cross; if ( altc == 0 ) { // no more blanks st = NobodyWon; emit finished(); } } *btArray = a; // update model updateButtons(); // update buttons delete[] altv; } //*************************************************************************** //* TicTacToe member functions //*************************************************************************** // -------------------------------------------------------------------------- // Creates a game widget with a game board and two push buttons, and connects // signals of child widgets to slots. // TicTacToe::TicTacToe( bool meFirst, int boardSize, QWidget *parent, const char *name ) : QWidget( parent, name ) { Q3VBoxLayout * l = new Q3VBoxLayout( this, 6 ); // Create a message label message = new QLabel( this ); message->setFrameStyle( Q3Frame::WinPanel | Q3Frame::Sunken ); message->setAlignment( Qt::AlignCenter ); l->addWidget( message ); // Create the game board and connect the signal finished() to this // gameOver() slot board = new TicTacGameBoard( meFirst, boardSize, this ); connect( board, SIGNAL(finished()), SLOT(gameOver()) ); l->addWidget( board ); // Create a horizontal frame line Q3Frame *line = new Q3Frame( this ); line->setFrameStyle( Q3Frame::HLine | Q3Frame::Sunken ); l->addWidget( line ); // Create the combo box for deciding who should start, and // connect its clicked() signals to the buttonClicked() slot whoStarts = new QComboBox( this ); whoStarts->insertItem( "Opponent starts" ); whoStarts->insertItem( "You start" ); l->addWidget( whoStarts ); whoStarts->setEnabled(false); whoStarts->setCurrentIndex(meFirst); // Create the push buttons and connect their clicked() signals // to this right slots. connect( board, SIGNAL(myMove(int)), this, SIGNAL(myMove(int))); connect( board, SIGNAL(stateChanged()), this, SLOT(newState())); newGame = new QPushButton( "Play!", this ); connect( newGame, SIGNAL(clicked()), SLOT(newGameClicked()) ); newGame->setEnabled(false); quit = new QPushButton( "Quit", this ); connect( quit, SIGNAL(clicked()), this, SIGNAL(closing()) ); Q3HBoxLayout * b = new Q3HBoxLayout; l->addLayout( b ); b->addWidget( newGame ); b->addWidget( quit ); newState(); //board->newGame(); newGameClicked(); } void TicTacToe::theirMove(int space) { board->theirMove(space); } // -------------------------------------------------------------------------- // TicTacToe::newGameClicked() - SLOT // // This slot is activated when the new game button is clicked. // void TicTacToe::newGameClicked() { board->computerStarts( whoStarts->currentItem() == 0 ); board->newGame(); newState(); } // -------------------------------------------------------------------------- // TicTacToe::gameOver() - SLOT // // This slot is activated when the TicTacGameBoard emits the signal // "finished()", i.e. when a player has won or when it is a draw. // void TicTacToe::gameOver() { newState(); // update text box emit gameOverSignal(board->state()); } // -------------------------------------------------------------------------- // Updates the message to reflect a new state. // void TicTacToe::newState() { static const char *msg[] = { // TicTacGameBoard::State texts "Click Play to start", "Make your move", "Waiting for other player", "You won!", "Opponent won!", "It's a draw" }; message->setText( msg[board->state()] ); return; } psi-0.14/src/plugins/generic/consoledump/0000755000175000017500000000000011305557613016555 5ustar janjanpsi-0.14/src/plugins/generic/consoledump/consoledumpplugin.cpp0000644000175000017500000000523411305557613023034 0ustar janjan/* * consoledump.cpp - Psi plugin to dump stream to console * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "psiplugin.h" #include "eventfilter.h" class ConsoleDumpPlugin : public QObject, public PsiPlugin, public EventFilter { Q_OBJECT Q_INTERFACES(PsiPlugin EventFilter) public: ConsoleDumpPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options() const; virtual bool enable(); virtual bool disable(); virtual bool processEvent(int account, const QDomElement& e); virtual bool processMessage(int account, const QString& fromJid, const QString& body, const QString& subject) ; private: bool enabled; }; Q_EXPORT_PLUGIN(ConsoleDumpPlugin); ConsoleDumpPlugin::ConsoleDumpPlugin() : enabled(false) { } QString ConsoleDumpPlugin::name() const { return "Console Dump Plugin"; } QString ConsoleDumpPlugin::shortName() const { return "consdump"; } QString ConsoleDumpPlugin::version() const { return "0.1"; } QWidget* ConsoleDumpPlugin::options() const { return 0; } bool ConsoleDumpPlugin::enable() { enabled = true; return true; } bool ConsoleDumpPlugin::disable() { enabled = false; return true; } bool ConsoleDumpPlugin::processEvent(int account, const QDomElement& e) { Q_UNUSED(account); Q_UNUSED(e); return false; // don't stop processing } bool ConsoleDumpPlugin::processMessage(int account, const QString& fromJid, const QString& body, const QString& subject) { Q_UNUSED(account); Q_UNUSED(subject); if (enabled) { qWarning(qPrintable(QString("Received message from %1").arg(fromJid))); qWarning(qPrintable(body)); } return false; // don't stop processing } #include "consoledumpplugin.moc" psi-0.14/src/plugins/generic/consoledump/consoledumpplugin.pro0000644000175000017500000000007711305557613023052 0ustar janjaninclude(../../psiplugin.pri) SOURCES += consoledumpplugin.cpp psi-0.14/src/plugins/generic/urlwatcher/0000755000175000017500000000000011305557613016405 5ustar janjanpsi-0.14/src/plugins/generic/urlwatcher/urlevent.h0000644000175000017500000000216411305557613020425 0ustar janjan/* * urlevent.h - simple URL container * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _URLEVENT_H_ #define _URLEVENT_H_ #include "QtCore" class URLEvent : public QObject { Q_OBJECT public: URLEvent(QString sender, QString url, QObject *parent = 0): QObject(parent) { sender_=sender; url_=url; viewed_=false; } ~URLEvent(){}; QString sender_; QString url_; bool viewed_; }; #endif /* _URLEVENT_H_ */psi-0.14/src/plugins/generic/urlwatcher/urlwatcherplugin.pro0000644000175000017500000000012511305557613022524 0ustar janjaninclude(../../psiplugin.pri) SOURCES += urlwatcherplugin.cpp HEADERS += urlevent.h psi-0.14/src/plugins/generic/urlwatcher/urlwatcherplugin.cpp0000644000175000017500000002023711305557613022514 0ustar janjan/* * urlwatcherplugin.cpp - Psi plugin to log URLs to a widget * Copyright (C) 2006 Kevin 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "psiplugin.h" #include "eventfilter.h" #include "urlevent.h" class URLWatcherPlugin : public QObject, public PsiPlugin, public EventFilter { Q_OBJECT Q_INTERFACES(PsiPlugin EventFilter) public: URLWatcherPlugin(); ~URLWatcherPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options() const; virtual bool enable(); virtual bool disable(); virtual bool processEvent(int account, const QDomElement& e); virtual bool processMessage(int account, const QString& fromJid, const QString& body, const QString& subject) ; private: bool enabled_; QList urls_; QWidget* viewer_; QTextEdit* viewerText_; }; Q_EXPORT_PLUGIN(URLWatcherPlugin); URLWatcherPlugin::URLWatcherPlugin() { enabled_ = false; viewer_ = new QWidget(); QVBoxLayout *vboxLayout; QFrame *frame; QLabel *label; vboxLayout = new QVBoxLayout(viewer_); vboxLayout->setObjectName(QString::fromUtf8("vboxLayout")); frame = new QFrame(viewer_); frame->setObjectName(QString::fromUtf8("frame")); frame->setFrameShape(QFrame::StyledPanel); frame->setFrameShadow(QFrame::Raised); viewerText_ = new QTextEdit(frame); viewerText_->setObjectName(QString::fromUtf8("text")); viewerText_->setReadOnly(true); label = new QLabel(viewer_); label->setObjectName(QString::fromUtf8("label")); label->setText("URLs"); vboxLayout->addWidget(label); vboxLayout->addWidget(viewerText_); //viewer_->show(); } URLWatcherPlugin::~URLWatcherPlugin() { delete viewer_; } QString URLWatcherPlugin::name() const { return "URL Watcher Plugin"; } QString URLWatcherPlugin::shortName() const { return "urlWatcher"; } QString URLWatcherPlugin::version() const { return "0.2"; } QWidget* URLWatcherPlugin::options() const { return 0; } bool URLWatcherPlugin::enable() { viewer_->show(); enabled_ = true; return true; } bool URLWatcherPlugin::disable() { viewer_->hide(); enabled_ = false; return true; } QString resolveEntities(const QString &in) { QString out; for(int i = 0; i < (int)in.length(); ++i) { if(in[i] == '&') { // find a semicolon ++i; int n = in.indexOf(';', i); if(n == -1) break; QString type = in.mid(i, (n-i)); i = n; // should be n+1, but we'll let the loop increment do it if(type == "amp") out += '&'; else if(type == "lt") out += '<'; else if(type == "gt") out += '>'; else if(type == "quot") out += '\"'; else if(type == "apos") out += '\''; } else { out += in[i]; } } return out; } static bool linkify_pmatch(const QString &str1, int at, const QString &str2) { if(str2.length() > (str1.length()-at)) return false; for(int n = 0; n < (int)str2.length(); ++n) { if(str1.at(n+at).toLower() != str2.at(n).toLower()) return false; } return true; } static bool linkify_isOneOf(const QChar &c, const QString &charlist) { for(int i = 0; i < (int)charlist.length(); ++i) { if(c == charlist.at(i)) return true; } return false; } // encodes a few dangerous html characters static QString linkify_htmlsafe(const QString &in) { QString out; for(int n = 0; n < in.length(); ++n) { if(linkify_isOneOf(in.at(n), "\"\'`<>")) { // hex encode QString hex; hex.sprintf("%%%02X", in.at(n).toLatin1()); out.append(hex); } else { out.append(in.at(n)); } } return out; } static bool linkify_okUrl(const QString &url) { if(url.at(url.length()-1) == '.') return false; return true; } static bool linkify_okEmail(const QString &addy) { // this makes sure that there is an '@' and a '.' after it, and that there is // at least one char for each of the three sections int n = addy.indexOf('@'); if(n == -1 || n == 0) return false; int d = addy.indexOf('.', n+1); if(d == -1 || d == 0) return false; if((addy.length()-1) - d <= 0) return false; if(addy.indexOf("..") != -1) return false; return true; } bool URLWatcherPlugin::processEvent(int account, const QDomElement& e) { Q_UNUSED(account); Q_UNUSED(e); return false; } bool URLWatcherPlugin::processMessage(int account, const QString& fromJid, const QString& body, const QString& subject) { Q_UNUSED(account); Q_UNUSED(subject); QString newUrl; QString out = body; int x1, x2; bool isUrl, isEmail; QString linked, link, href; for(int n = 0; n < (int)out.length(); ++n) { isUrl = false; isEmail = false; x1 = n; if(linkify_pmatch(out, n, "http://")) { n += 7; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "https://")) { n += 8; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "ftp://")) { n += 6; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "news://")) { n += 7; isUrl = true; href = ""; } else if (linkify_pmatch(out, n, "ed2k://")) { n += 7; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "www.")) { isUrl = true; href = "http://"; } else if(linkify_pmatch(out, n, "ftp.")) { isUrl = true; href = "ftp://"; } else if(linkify_pmatch(out, n, "@")) { isEmail = true; href = "mailto:"; } if(isUrl) { // make sure the previous char is not alphanumeric if(x1 > 0 && out.at(x1-1).isLetterOrNumber()) continue; // find whitespace (or end) for(x2 = n; x2 < (int)out.length(); ++x2) { if(out.at(x2).isSpace() || out.at(x2) == '<') break; } int len = x2-x1; QString pre = resolveEntities(out.mid(x1, x2-x1)); // go backward hacking off unwanted punctuation int cutoff; for(cutoff = pre.length()-1; cutoff >= 0; --cutoff) { if(!linkify_isOneOf(pre.at(cutoff), "!?,.()[]{}<>\"")) break; } ++cutoff; //++x2; link = pre.mid(0, cutoff); if(!linkify_okUrl(link)) { n = x1 + link.length(); continue; } href += link; href = linkify_htmlsafe(href); //printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1()); linked = QString("").arg(href) + Qt::escape(link) + "" + Qt::escape(pre.mid(cutoff)); out.replace(x1, len, linked); n = x1 + linked.length() - 1; } else if(isEmail) { // go backward till we find the beginning if(x1 == 0) continue; --x1; for(; x1 >= 0; --x1) { if(!linkify_isOneOf(out.at(x1), "_.-") && !out.at(x1).isLetterOrNumber()) break; } ++x1; // go forward till we find the end x2 = n + 1; for(; x2 < (int)out.length(); ++x2) { if(!linkify_isOneOf(out.at(x2), "_.-") && !out.at(x2).isLetterOrNumber()) break; } int len = x2-x1; link = out.mid(x1, len); //link = resolveEntities(link); if(!linkify_okEmail(link)) { n = x1 + link.length(); continue; } href += link; //printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1()); linked = QString("").arg(href) + link + ""; out.replace(x1, len, linked); n = x1 + linked.length() - 1; } } newUrl=out; qWarning("string parsed"); if (isUrl) { qWarning(qPrintable(QString("it's a url %1").arg(newUrl))); newUrl=QString("<%1> %2
").arg(fromJid).arg(newUrl); viewerText_->append(newUrl); } return false; } #include "urlwatcherplugin.moc" psi-0.14/src/plugins/psiplugin.pri0000644000175000017500000000017011305557613015335 0ustar janjanTEMPLATE = lib CONFIG += plugin QT += xml target.path = $$(HOME)/.psi/plugins INSTALLS += target include(plugins.pri) psi-0.14/src/mucconfig.ui0000644000175000017500000002002211305557613013435 0ustar janjan MUCConfig 0 0 483 375 Room Configuration 9 6 0 Affiliations 9 6 Qt::Vertical 20 141 Filter: 5 0 0 0 Qt::Horizontal 40 20 7 13 0 0 Add Remove General 9 6 0 9 6 Qt::Vertical 20 40 message Qt::AlignCenter true Qt::Vertical 20 40 0 6 Qt::Horizontal 40 20 Destroy Room Qt::Horizontal 40 20 0 6 Qt::Horizontal 131 31 Apply Close BusyWidget QWidget
busywidget.h
1
MUCAffiliationsView QWidget
mucaffiliationsview.h
1
pb_close clicked() MUCConfig reject() 369 253 179 282
psi-0.14/src/libpsi/0000755000175000017500000000000011305557617012416 5ustar janjanpsi-0.14/src/libpsi/widgets/0000755000175000017500000000000011305557617014064 5ustar janjanpsi-0.14/src/libpsi/widgets/groupchatbrowsewindow.h0000644000175000017500000000765311305557617020716 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #ifndef GROUPCHATBROWSEWINDOW_H #define GROUPCHATBROWSEWINDOW_H #include #include #include class GroupChatBrowseWindow : public QWidget { Q_OBJECT public: class RoomOptions { public: XMPP::Jid jid; QString roomName; bool visible; RoomOptions() : visible(false) { } }; class RoomInfo { public: XMPP::Jid jid; bool remove; // the following are only valid if 'remove' is false QString roomName; bool autoJoin; bool owner; int participants; RoomInfo() : remove(false), autoJoin(false), owner(false), participants(-1) { } }; GroupChatBrowseWindow(QWidget *parent = 0) : QWidget(parent) { } // FIXME: remove this virtual QObject *controller() const = 0; virtual void setController(QObject *controller) = 0; virtual void setGroupChatIcon(const QPixmap &icon) = 0; virtual void setServer(const XMPP::Jid &roomServer) = 0; virtual void setServerVisible(bool b) = 0; virtual void setNicknameVisible(bool b) = 0; signals: void onBrowse(const XMPP::Jid &roomServer); void onJoin(const XMPP::Jid &room); void onCreate(const XMPP::Jid &room); void onCreateConfirm(const GroupChatBrowseWindow::RoomOptions &options); void onCreateCancel(const XMPP::Jid &room); // no ack void onCreateFinalize(const XMPP::Jid &room, bool join); // no-ack if join=false void onDestroy(const XMPP::Jid &room); void onSetAutoJoin(const QList &rooms, bool enabled); public slots: // onBrowse virtual void handleBrowseResultsReady(const QList &list) = 0; virtual void handleBrowseError(const QString &reason) = 0; // onJoin or onCreateFinalize virtual void handleJoinSuccess() = 0; virtual void handleJoinError(const QString &reason) = 0; // from onCreate virtual void handleCreateSuccess(const GroupChatBrowseWindow::RoomOptions &defaultOptions) = 0; // from onCreateConfirm virtual void handleCreateConfirmed() = 0; // from onCreate or onCreateConfirm virtual void handleCreateError(const QString &reason) = 0; // from onDestroy virtual void handleDestroySuccess() = 0; virtual void handleDestroyError(const QString &reason) = 0; }; class PsiGroupChatBrowseWindow : public GroupChatBrowseWindow { Q_OBJECT public: PsiGroupChatBrowseWindow(QWidget *parent = 0); ~PsiGroupChatBrowseWindow(); // FIXME: remove this virtual QObject *controller() const; virtual void setController(QObject *controller); // from qwidget virtual void resizeEvent(QResizeEvent *event); virtual void setGroupChatIcon(const QPixmap &icon); virtual void setServer(const XMPP::Jid &roomServer); virtual void setServerVisible(bool b); virtual void setNicknameVisible(bool b); public slots: virtual void handleBrowseResultsReady(const QList &list); virtual void handleBrowseError(const QString &reason); virtual void handleJoinSuccess(); virtual void handleJoinError(const QString &reason); virtual void handleCreateSuccess(const GroupChatBrowseWindow::RoomOptions &defaultOptions); virtual void handleCreateConfirmed(); virtual void handleCreateError(const QString &reason); virtual void handleDestroySuccess(); virtual void handleDestroyError(const QString &reason); private: class Private; Private *d; }; #endif psi-0.14/src/libpsi/widgets/groupchatbrowsewindow.ui0000644000175000017500000000420111305557617021066 0ustar janjan GroupChatBrowseWindowUI 0 0 411 296 Groupchat Groupchat server: &Browse Specify groupchat name manually: Show your name in the groupchat as: QDialogButtonBox::Cancel|QDialogButtonBox::Ok le_server pb_browse tv_rooms le_room le_nick buttonBox psi-0.14/src/libpsi/widgets/groupchatbrowsewindow.cpp0000644000175000017500000002612711305557617021246 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * 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 2 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, see . * */ #include "groupchatbrowsewindow.h" #include #include #include #include #include #include "ui_groupchatbrowsewindow.h" // TODO: recent list of joins, like original gcjoindlg? Q_DECLARE_METATYPE(XMPP::Jid) Q_DECLARE_METATYPE(GroupChatBrowseWindow::RoomOptions) Q_DECLARE_METATYPE(GroupChatBrowseWindow::RoomInfo) enum Role { RoomInfoRole = Qt::UserRole }; // TODO: handle duplicate rooms somehow class RoomModel : public QStandardItemModel { Q_OBJECT public: QList list; QPixmap icon; RoomModel(QObject *parent = 0) : QStandardItemModel(parent) { QStringList headers; headers += tr("Groupchat name"); //headers += tr("Participants"); headers += tr("Auto-join"); setHorizontalHeaderLabels(headers); //setSortRole(RoomItem::PositionRole); } void addRooms(const QList &alist) { list += alist; foreach(const GroupChatBrowseWindow::RoomInfo &info, alist) { QList clist; clist += new QStandardItem(icon, info.roomName); clist[0]->setData(qVariantFromValue(info), RoomInfoRole); //clist += new QStandardItem(QString::number(info.participants)); clist += new QStandardItem; clist[1]->setCheckable(true); if(info.autoJoin) clist[1]->setCheckState(Qt::Checked); clist[0]->setEditable(false); clist[1]->setEditable(false); appendRow(clist); } } void removeRoom(int at) { list.removeAt(at); removeRow(at); } }; class PsiGroupChatBrowseWindow::Private : public QObject { Q_OBJECT public: PsiGroupChatBrowseWindow *q; Ui::GroupChatBrowseWindowUI ui; XMPP::Jid server; RoomModel *model; QObject *controller; // FIXME: remove this XMPP::Jid roomBeingCreated, roomBeingDestroyed; QPushButton *pb_create, *pb_join; Private(PsiGroupChatBrowseWindow *_q) : QObject(_q), q(_q), controller(0) { ui.setupUi(q); model = new RoomModel(this); ui.tv_rooms->setAllColumnsShowFocus(true); ui.tv_rooms->setRootIsDecorated(false); ui.tv_rooms->setSortingEnabled(true); ui.tv_rooms->sortByColumn(0, Qt::AscendingOrder); ui.tv_rooms->header()->setMovable(false); ui.tv_rooms->header()->setClickable(true); ui.tv_rooms->setModel(model); ui.buttonBox->setStandardButtons(QDialogButtonBox::Close); pb_create = new QPushButton("Cre&ate...", q); pb_join = new QPushButton("&Join", q); pb_join->setDefault(true); ui.buttonBox->addButton(pb_create, QDialogButtonBox::ActionRole); ui.buttonBox->addButton(pb_join, QDialogButtonBox::AcceptRole); ui.tv_rooms->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui.tv_rooms, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(rooms_contextMenuRequested(const QPoint &))); connect(ui.tv_rooms, SIGNAL(activated(const QModelIndex &)), SLOT(rooms_activated(const QModelIndex &))); connect(ui.tv_rooms->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(rooms_selectionChanged(const QItemSelection &, const QItemSelection &))); connect(ui.le_room, SIGNAL(textChanged(const QString &)), SLOT(room_textChanged(const QString &))); connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(model_dataChanged(const QModelIndex &, const QModelIndex &))); connect(pb_create, SIGNAL(clicked()), SLOT(doCreate())); connect(pb_join, SIGNAL(clicked()), SLOT(doJoin())); connect(ui.buttonBox, SIGNAL(rejected()), SLOT(doClose())); pb_join->setEnabled(false); q->resize(560, 420); } void setWidgetsEnabled(bool enabled) { ui.tv_rooms->setEnabled(enabled); ui.le_room->setEnabled(enabled); ui.le_nick->setEnabled(enabled); pb_create->setEnabled(enabled); pb_join->setEnabled(enabled); } void roomDestroyed() { int at = -1; for(int n = 0; n < model->list.count(); ++n) { if(model->list[n].jid == roomBeingDestroyed) { at = n; break; } } if(at == -1) return; model->removeRoom(at); } public slots: void rooms_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); if(!selected.indexes().isEmpty() || !ui.le_room->text().isEmpty()) pb_join->setEnabled(true); else pb_join->setEnabled(false); } void rooms_contextMenuRequested(const QPoint &pos) { QItemSelection selected = ui.tv_rooms->selectionModel()->selection(); if(!selected.indexes().isEmpty()) { QPoint gpos = ui.tv_rooms->viewport()->mapToGlobal(pos); QMenu menu(q); QAction *destroyAction = menu.addAction(tr("Destroy")); QAction *act = menu.exec(gpos); if(act == destroyAction) { QModelIndex index = selected.indexes().first(); // ### async is bad QMetaObject::invokeMethod(this, "destroyRoom", Qt::QueuedConnection, Q_ARG(XMPP::Jid, model->list[index.row()].jid)); } } } void rooms_activated(const QModelIndex &index) { XMPP::Jid room = model->list[index.row()].jid; if(!room.isEmpty()) { setWidgetsEnabled(false); emit q->onJoin(room); } } void room_textChanged(const QString &text) { Q_UNUSED(text); QItemSelection selected = ui.tv_rooms->selectionModel()->selection(); if(!selected.indexes().isEmpty() || !ui.le_room->text().isEmpty()) pb_join->setEnabled(true); else pb_join->setEnabled(false); } void model_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { Q_UNUSED(bottomRight); QModelIndex index = topLeft; QStandardItem *i = model->itemFromIndex(index); bool isChecked = false; if(i->checkState() == Qt::Checked) isChecked = true; bool previousState = model->list[index.row()].autoJoin; model->list[index.row()].autoJoin = isChecked; if(previousState != isChecked) emit q->onSetAutoJoin(QList() << model->list[index.row()].jid, isChecked); } void doCreate() { QString room = QInputDialog::getText(q, tr("Create Groupchat"), tr("Choose a name for the groupchat you want to create:")); if(!room.isEmpty()) { setWidgetsEnabled(false); roomBeingCreated = server.withNode(room); emit q->onCreate(roomBeingCreated); } } void doJoin() { XMPP::Jid room; QString manualRoom = ui.le_room->text(); if(!manualRoom.isEmpty()) { if(manualRoom.indexOf('@') != -1) room = manualRoom; else room = server.withNode(manualRoom); } else { QItemSelection selection = ui.tv_rooms->selectionModel()->selection(); if(selection.indexes().isEmpty()) return; QModelIndex index = selection.indexes().first(); room = model->list[index.row()].jid; } if(!room.isEmpty()) { setWidgetsEnabled(false); emit q->onJoin(room); } } void doClose() { q->close(); } void createFinalize() { emit q->onCreateFinalize(roomBeingCreated, true); q->close(); } void destroyRoom(const XMPP::Jid &room) { setWidgetsEnabled(false); roomBeingDestroyed = room; emit q->onDestroy(room); } }; PsiGroupChatBrowseWindow::PsiGroupChatBrowseWindow(QWidget *parent) : GroupChatBrowseWindow(parent) { qRegisterMetaType(); qRegisterMetaType(); d = new Private(this); } PsiGroupChatBrowseWindow::~PsiGroupChatBrowseWindow() { delete d; } void PsiGroupChatBrowseWindow::resizeEvent(QResizeEvent *event) { //int sort_margin = d->ui.tv_rooms->header()->style()->pixelMetric(QStyle::PM_HeaderMargin); int grip_width = d->ui.tv_rooms->header()->style()->pixelMetric(QStyle::PM_HeaderGripMargin); int frame_width = d->ui.tv_rooms->frameWidth(); //printf("s=%d,g=%d,f=%d,h=%d\n", sort_margin, grip_width, frame_width, d->ui.tv_rooms->header()->frameWidth()); grip_width *= 2; // HACK: this is certainly wrong, but some styles need extra pixel shifting frame_width *= 2; // frame on left and right side int widget_width = d->ui.tv_rooms->width(); //int right_column_ideal = qMax(d->ui.tv_rooms->header()->minimumSectionSize(), d->ui.tv_rooms->header()->sectionSizeHint(1)); int right_column_ideal = 132; //d->ui.tv_rooms->header()->sectionSizeHint(1); int left_column_width = widget_width - right_column_ideal - grip_width - frame_width; d->ui.tv_rooms->header()->resizeSection(0, left_column_width); GroupChatBrowseWindow::resizeEvent(event); } QObject *PsiGroupChatBrowseWindow::controller() const { return d->controller; } void PsiGroupChatBrowseWindow::setController(QObject *controller) { d->controller = controller; } void PsiGroupChatBrowseWindow::setGroupChatIcon(const QPixmap &icon) { d->model->icon = icon; } void PsiGroupChatBrowseWindow::setServer(const XMPP::Jid &roomServer) { d->server = roomServer; d->ui.le_server->setText(d->server.full()); d->ui.le_server->setCursorPosition(0); // FIXME: we shouldn't do this here QMetaObject::invokeMethod(this, "onBrowse", Qt::QueuedConnection, Q_ARG(XMPP::Jid, d->server)); } void PsiGroupChatBrowseWindow::setServerVisible(bool b) { d->ui.lb_server->setVisible(b); d->ui.le_server->setVisible(b); d->ui.pb_browse->setVisible(b); } void PsiGroupChatBrowseWindow::setNicknameVisible(bool b) { d->ui.lb_nick->setVisible(b); d->ui.le_nick->setVisible(b); } void PsiGroupChatBrowseWindow::handleBrowseResultsReady(const QList &list) { d->model->addRooms(list); } void PsiGroupChatBrowseWindow::handleBrowseError(const QString &reason) { // TODO Q_UNUSED(reason); } void PsiGroupChatBrowseWindow::handleJoinSuccess() { close(); } void PsiGroupChatBrowseWindow::handleJoinError(const QString &reason) { d->setWidgetsEnabled(true); QMessageBox::information(this, tr("Error"), tr("Unable to join groupchat.\nReason: %1").arg(reason)); } void PsiGroupChatBrowseWindow::handleCreateSuccess(const GroupChatBrowseWindow::RoomOptions &defaultOptions) { QMetaObject::invokeMethod(this, "onCreateConfirm", Qt::QueuedConnection, Q_ARG(GroupChatBrowseWindow::RoomOptions, defaultOptions)); } void PsiGroupChatBrowseWindow::handleCreateConfirmed() { QMetaObject::invokeMethod(d, "createFinalize", Qt::QueuedConnection); } void PsiGroupChatBrowseWindow::handleCreateError(const QString &reason) { d->setWidgetsEnabled(true); QMessageBox::information(this, tr("Error"), tr("Unable to create groupchat.\nReason: %1").arg(reason)); } void PsiGroupChatBrowseWindow::handleDestroySuccess() { d->setWidgetsEnabled(true); d->roomDestroyed(); } void PsiGroupChatBrowseWindow::handleDestroyError(const QString &reason) { d->setWidgetsEnabled(true); QMessageBox::information(this, tr("Error"), tr("Unable to destroy groupchat.\nReason: %1").arg(reason)); } #include "groupchatbrowsewindow.moc" psi-0.14/src/libpsi/dialogs/0000755000175000017500000000000011305557617014040 5ustar janjanpsi-0.14/src/libpsi/dialogs/grepshortcutkeydialog.h0000644000175000017500000000307611305557617020641 0ustar janjan/* * grepshortcutkeydialog.h - a dialog which greps a KeySequence and * emits a signal with this KeySequence as Parameter * Copyright (C) 2006 Cestonaro Thilo * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "ui_grepshortcutkeydialog.h" #ifndef GREPSHORTCUTKEYDIALOG_H #define GREPSHORTCUTKEYDIALOG_H class GrepShortcutKeyDialog : public QDialog { Q_OBJECT public: GrepShortcutKeyDialog(); // reimplemented void show(); void close(); protected: // reimplemented void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); signals: void newShortcutKey(const QKeySequence& key); private: Ui::GrepShortcutKeyDialog ui_; bool gotKey; void displayPressedKeys(const QKeySequence& keys); QKeySequence getKeySequence(QKeyEvent* event) const; bool isValid(int key) const; bool isModifier(int key) const; }; #endif psi-0.14/src/libpsi/dialogs/grepshortcutkeydialog.cpp0000644000175000017500000000520111305557617021164 0ustar janjan/* * grepshortcutkeydialog.cpp - a dialog which greps a KeySequence and * emits a signal with this KeySequence as Parameter * Copyright (C) 2006 Cestonaro Thilo * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "grepshortcutkeydialog.h" GrepShortcutKeyDialog::GrepShortcutKeyDialog() : QDialog() , gotKey(false) { ui_.setupUi(this); displayPressedKeys(QKeySequence()); } /** * Grabs the keyboard and proceeds with the default show() call. */ void GrepShortcutKeyDialog::show() { grabKeyboard(); QDialog::show(); } /** * Releases the grabbed keyboard and proceeds with the default close() call. */ void GrepShortcutKeyDialog::close() { QDialog::close(); releaseKeyboard(); } void GrepShortcutKeyDialog::displayPressedKeys(const QKeySequence& keys) { QString str = keys.toString(QKeySequence::NativeText); if (str.isEmpty()) str = tr("Set Keys"); ui_.shortcutPreview->setText(str); } QKeySequence GrepShortcutKeyDialog::getKeySequence(QKeyEvent* event) const { return QKeySequence((isValid(event->key()) ? event->key() : 0) + (event->modifiers() & ~Qt::KeypadModifier)); } void GrepShortcutKeyDialog::keyPressEvent(QKeyEvent* event) { displayPressedKeys(getKeySequence(event)); if (!isValid(event->key()) || gotKey) return; gotKey = true; emit newShortcutKey(getKeySequence(event)); close(); } void GrepShortcutKeyDialog::keyReleaseEvent(QKeyEvent* event) { displayPressedKeys(getKeySequence(event)); } /** * Returns true if \param key could be used in a shortcut. */ bool GrepShortcutKeyDialog::isValid(int key) const { switch (key) { case 0: case Qt::Key_unknown: return false; } return !isModifier(key); } /** * Returns true if \param key is modifier. */ bool GrepShortcutKeyDialog::isModifier(int key) const { switch (key) { case Qt::Key_Shift: case Qt::Key_Control: case Qt::Key_Meta: case Qt::Key_Alt: case Qt::Key_AltGr: case Qt::Key_Super_L: case Qt::Key_Super_R: case Qt::Key_Menu: return true; } return false; } psi-0.14/src/libpsi/dialogs/grepshortcutkeydialog.ui0000644000175000017500000000337011305557617021024 0ustar janjan GrepShortcutKeyDialog Qt::ApplicationModal 0 0 255 50 0 0 0 0 Qt::NoContextMenu 9 6 Qt::NoFocus Qt::AlignHCenter true Qt::NoFocus Cancel pushButton clicked() GrepShortcutKeyDialog close() 207 83 100 23 psi-0.14/src/libpsi/dialogs/grepshortcutkeydialog.pri0000644000175000017500000000025411305557617021177 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/grepshortcutkeydialog.h SOURCES += $$PWD/grepshortcutkeydialog.cpp INTERFACES += $$PWD/grepshortcutkeydialog.ui psi-0.14/src/libpsi/README0000644000175000017500000000004711305557617013277 0ustar janjanlibpsi -- home of the finest Psi code! psi-0.14/src/libpsi/COPYING0000644000175000017500000003677211305557617013470 0ustar janjan As a special exception, the copyright holder(s) give permission to link this program with the Qt Library (commercial or non-commercial edition), and distribute the resulting executable, without including the source code for the Qt library in the source distribution. As a special exception, the copyright holder(s) give permission to link this program with any other library, and distribute the resulting executable, without including the source code for the library in the source distribution, provided that the library interfaces with this program only via the following plugin interfaces: 1. The Qt Plugin APIs, only as authored by Trolltech 2. The QCA Plugin API, only as authored by Justin Karneges GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS psi-0.14/src/libpsi/tools/0000755000175000017500000000000011305557617013556 5ustar janjanpsi-0.14/src/libpsi/tools/mac_dock/0000755000175000017500000000000011305557617015316 5ustar janjanpsi-0.14/src/libpsi/tools/mac_dock/docktest.pro0000644000175000017500000000015611305557617017662 0ustar janjanTEMPLATE = app HEADERS += mac_dock.h SOURCES += mac_dock.cpp docktest.cpp QMAKE_LFLAGS += -framework Carbon psi-0.14/src/libpsi/tools/mac_dock/mac_dock.pri0000644000175000017500000000020611305557617017570 0ustar janjanHEADERS += $$PWD/mac_dock.h SOURCES += $$PWD/mac_dock.cpp INCLUDEPATH += $$PWD DEPENDPATH += $$PWD QMAKE_LFLAGS += -framework Carbon psi-0.14/src/libpsi/tools/mac_dock/mac_dock.h0000644000175000017500000000041311305557617017225 0ustar janjan#ifndef MACDOCK_H #define MACDOCK_H #include class MacDock { public: static void startBounce(); static void stopBounce(); static void overlay(const QString& text = QString::null); private: static bool isBouncing; static bool overlayed; }; #endif psi-0.14/src/libpsi/tools/mac_dock/mac_dock.cpp0000644000175000017500000000545711305557617017575 0ustar janjan#include "mac_dock.h" #include "ApplicationServices/ApplicationServices.h" #include "Carbon/Carbon.h" #define DOCK_FONT_NAME "LucidaGrande-Bold" #define DOCK_FONT_SIZE 24 static NMRec bounceRec; /** * Converts a QString to a CoreFoundation string, preserving Unicode. * * \param s the string to be converted. * \return a reference to a CoreFoundation string. */ /*static CFStringRef qString2CFString(const QString& s) { if (s.isNull()) return 0; ushort* buffer = new ushort[s.length()]; for (unsigned int i = 0; i < s.length(); ++i) buffer[i] = s[i].unicode(); CFStringRef result = CFStringCreateWithBytes ( NULL, (UInt8*) buffer, s.length()*sizeof(ushort), kCFStringEncodingUnicode, false); delete buffer; return result; }*/ void MacDock::startBounce() { if (!isBouncing) { bounceRec.qType = nmType; bounceRec.nmMark = 1; bounceRec.nmIcon = NULL; bounceRec.nmSound = NULL; bounceRec.nmStr = NULL; bounceRec.nmResp = NULL; bounceRec.nmRefCon = 0; NMInstall(&bounceRec); isBouncing = true; } } void MacDock::stopBounce() { if(isBouncing) { NMRemove(&bounceRec); isBouncing = false; } } void MacDock::overlay(const QString& text) { if (text.isEmpty()) { overlayed = false; RestoreApplicationDockTileImage(); return; } // Create the context CGContextRef context = BeginCGContextForApplicationDockTile(); if (!overlayed) { overlayed = true; // Add some subtle drop down shadow CGSize s = { 2.0, -4.0 }; CGContextSetShadow(context, s, 5.0); } // Draw a circle CGContextBeginPath(context); CGContextAddArc(context, 95.0, 95.0, 25.0, 0.0, 2 * M_PI, true); CGContextClosePath(context); CGContextSetRGBFillColor(context, 1, 0.0, 0.0, 1); CGContextFillPath(context); // Set the clipping path to the same circle CGContextBeginPath(context); CGContextAddArc(context, 95.0, 95.0, 25.0, 0.0, 2 * M_PI, true); CGContextClip(context); // Remove drop shadow // FIXME: Disabled because 10.2 doesn't support it //CGSize s = { 0.0, -0.0 }; //CGContextSetShadowWithColor(context, s, 0, NULL); // Select the appropriate font CGContextSelectFont(context,DOCK_FONT_NAME, DOCK_FONT_SIZE, kCGEncodingMacRoman); CGContextSetRGBFillColor(context, 1, 1, 1, 1); // Draw the text invisible CGPoint begin = CGContextGetTextPosition(context); CGContextSetTextDrawingMode(context, kCGTextInvisible); CGContextShowTextAtPoint(context, begin.x, begin.y, text.toStdString().c_str(), text.length()); CGPoint end = CGContextGetTextPosition(context); // Draw the text CGContextSetTextDrawingMode(context, kCGTextFill); CGContextShowTextAtPoint(context, 95 - (end.x - begin.x)/2, 95 - 8, text.toStdString().c_str(), text.length()); // Cleanup CGContextFlush(context); EndCGContextForApplicationDockTile(context); } bool MacDock::isBouncing = false; bool MacDock::overlayed = false; psi-0.14/src/libpsi/tools/mac_dock/docktest.cpp0000644000175000017500000000406111305557617017643 0ustar janjan/* * docktest.cpp: A test program for the dock class * Copyright (C) 2005 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include "mac_dock.h" class DockTestWidget : public QWidget { Q_OBJECT public: DockTestWidget( QWidget *parent=0); public slots: void do_overlay(); private: QLineEdit *text; }; DockTestWidget::DockTestWidget( QWidget *parent ) : QWidget(parent) { // Initialize widgets QGridLayout *layout = new QGridLayout(this); layout->addWidget(new QLabel("Text",this),0,0); text = new QLineEdit(this); text->setText("1"); layout->addWidget(text,0,1); QPushButton *overlay = new QPushButton( "Overlay", this ); connect(overlay, SIGNAL(clicked()), SLOT(do_overlay())); layout->addWidget(overlay,1,0); } int main( int argc, char **argv ) { QApplication a( argc, argv ); DockTestWidget w; w.show(); return a.exec(); } void DockTestWidget::do_overlay() { MacDock::overlay(text->text()); } #include "docktest.moc" psi-0.14/src/libpsi/tools/growlnotifier/0000755000175000017500000000000011305557617016450 5ustar janjanpsi-0.14/src/libpsi/tools/growlnotifier/growltest.pro0000644000175000017500000000022211305557617021220 0ustar janjanTEMPLATE = app HEADERS += growlnotifier.h SOURCES += growlnotifier.cpp growltest.cpp QMAKE_LFLAGS += -framework Growl -framework CoreFoundation psi-0.14/src/libpsi/tools/growlnotifier/ChangeLog0000644000175000017500000000031711305557617020223 0ustar janjan2005-05-05, Remko Troncon * Created a more extensive example * Added timeout signal (new in Growl 0.7) 2005-04-15, Remko Troncon * Implemented the click notification 2005-04-11, Remko Troncon * Start psi-0.14/src/libpsi/tools/growlnotifier/growlnotifier.pri0000644000175000017500000000025211305557617022055 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/growlnotifier.h SOURCES += $$PWD/growlnotifier.cpp QMAKE_LFLAGS += -framework Growl -framework CoreFoundation psi-0.14/src/libpsi/tools/growlnotifier/growltest.cpp0000644000175000017500000000763511305557617021221 0ustar janjan/* * growltest.cpp: A test program for the GrowlNotifier class * Copyright (C) 2005 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "growlnotifier.h" #include #include #include #include #include #include #include #include #include #include #include class GrowlTestWidget : public QWidget { Q_OBJECT public: GrowlTestWidget(QWidget *parent=0); public slots: void do_notification1(); void do_notification2(); void notification_clicked(); private: QLineEdit *text, *title; QCheckBox* sticky; GrowlNotifier* growlNotifier; }; GrowlTestWidget::GrowlTestWidget(QWidget *parent) : QWidget(parent) { // Initialize widgets QGridLayout *layout = new QGridLayout(this); layout->addWidget(new QLabel("Title",this),0,0); title = new QLineEdit(this); title->setText("My Text"); layout->addWidget(title,0,1); layout->addWidget(new QLabel("Text",this),1,0); text = new QLineEdit(this); text->setText("My Description"); layout->addWidget(text,1,1); //layout->addWidget(new QLabel("Sticky",this),2,0); //sticky = new QCheckBox(this); //sticky->setTristate(); //layout->addWidget(sticky,2,1); QPushButton *notification1 = new QPushButton( "Notification 1", this ); connect(notification1, SIGNAL(clicked()), SLOT(do_notification1())); layout->addWidget(notification1,3,0); QPushButton *notification2 = new QPushButton( "Notification 2", this ); connect(notification2, SIGNAL(clicked()), SLOT(do_notification2())); layout->addWidget(notification2,3,1); // Initialize GrowlNotifier QStringList nots, defaults; nots << "Notification 1" << "Notification 2"; defaults << "Notification 1"; growlNotifier = new GrowlNotifier(nots, defaults, "GrowlNotifierTest"); } int main( int argc, char **argv ) { QApplication a( argc, argv ); GrowlTestWidget w; w.show(); return a.exec(); } void GrowlTestWidget::do_notification1() { //if (sticky->state() != QButton::NoChange) { // growlNotifier->notify("Notification 1", title->text(), text->text(), QPixmap(), sticky->isChecked(), this, SLOT(notification_clicked())); //} //else { // growlNotifier->notify("Notification 1", title->text(), text->text(), QPixmap()); //} growlNotifier->notify("Notification 1", title->text(), text->text(), QPixmap(), false, this, SLOT(notification_clicked())); } void GrowlTestWidget::do_notification2() { //if (sticky->state() != QButton::NoChange) { // growlNotifier->notify("Notification 2", title->text(), text->text(), QPixmap(), sticky->isChecked(), this, SLOT(notification_clicked())); //} //else { // growlNotifier->notify("Notification 2", title->text(), text->text(), QPixmap()); //} growlNotifier->notify("Notification 2", title->text(), text->text(), QPixmap(), false, this, SLOT(notification_clicked())); } void GrowlTestWidget::notification_clicked() { QMessageBox::information(0, "Information", "Notification was clicked\n"); } #include "growltest.moc" psi-0.14/src/libpsi/tools/growlnotifier/growlnotifier.cpp0000644000175000017500000002571111305557617022054 0ustar janjan/* * growlnotifier.cpp - A simple Qt interface to Growl * * Copyright (C) 2005 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /** * \class GrowlNotifier * \todo Write a destructor, which CFReleases all datastructures */ extern "C" { #include #include } #include #include #include //#include //#include #include "growlnotifier.h" //------------------------------------------------------------------------------ /** * \brief A class for emitting a clicked signal to the interested party. */ class GrowlNotifierSignaler : public QObject { Q_OBJECT public: GrowlNotifierSignaler() { }; void emitNotificationClicked(void* context) { emit notificationClicked(context); } void emitNotificationTimeout(void* context) { emit notificationTimedOut(context); } signals: void notificationClicked(void*); void notificationTimedOut(void*); }; //------------------------------------------------------------------------------ /** * \brief Converts a QString to a CoreFoundation string, preserving Unicode. * * \param s the string to be converted. * \return a reference to a CoreFoundation string. */ static CFStringRef qString2CFString(const QString& s) { if (s.isNull()) return 0; ushort* buffer = new ushort[s.length()]; for (int i = 0; i < s.length(); ++i) buffer[i] = s[i].unicode(); CFStringRef result = CFStringCreateWithBytes ( NULL, (UInt8*) buffer, s.length()*sizeof(ushort), kCFStringEncodingUnicode, false); delete[] buffer; return result; } //------------------------------------------------------------------------------ /** * \brief Retrieves the values from the context. * * \param context the context * \param receiver the receiving object which will be signaled when the * notification is clicked. May be NULL. * \param clicked_slot the slot to be signaled when the notification is clicked. * \param timeout_slot the slot to be signaled when the notification isn't clicked. * \param context the context which will be passed back to the slot * May be NULL. */ void getContext( CFPropertyListRef context, GrowlNotifierSignaler** signaler, const QObject** receiver, const char** clicked_slot, const char** timeout_slot, void** qcontext/*, pid_t* pid*/) { CFDataRef data; if (signaler) { data = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) context, 0); CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8*) signaler); } if (receiver){ data = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) context, 1); CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8*) receiver); } if (clicked_slot) { data = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) context, 2); CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8*) clicked_slot); } if (timeout_slot) { data = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) context, 3); CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8*) timeout_slot); } if (qcontext) { data = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) context, 4); CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8*) qcontext); } //if (pid) { // data = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) context, 5); // CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8*) pid); //} } //------------------------------------------------------------------------------ /** * Creates a context for a notification, which will be sent back by Growl * when a notification is clicked. * * \param receiver the receiving object which will be signaled when the * notification is clicked. May be NULL. * \param clicked_slot the slot to be signaled when the notification is clicked. * \param timeout_slot the slot to be signaled when the notification isn't clicked. * \param context the context which will be passed back to the slot * May be NULL. * \return the context */ CFPropertyListRef createContext( GrowlNotifierSignaler* signaler, const QObject* receiver, const char* clicked_slot, const char* timeout_slot, void* qcontext /*, pid_t pid*/) { CFDataRef context[5]; context[0] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &signaler, sizeof(GrowlNotifierSignaler*)); context[1] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &receiver, sizeof(const QObject *)); context[2] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &clicked_slot, sizeof(const char*)); context[3] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &timeout_slot, sizeof(const char*)); context[4] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &qcontext, sizeof(void*)); //context[5] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &pid, sizeof(pid_t)); CFArrayRef array = CFArrayCreate( kCFAllocatorDefault, (const void **)context, 5, &kCFTypeArrayCallBacks ); // Cleaning up CFRelease(context[0]); CFRelease(context[1]); CFRelease(context[2]); CFRelease(context[3]); CFRelease(context[4]); //CFRelease(context[5]); return array; } //------------------------------------------------------------------------------ /** * The callback function, used by Growl to notify that a notification was * clicked. * \param context the context of the notification */ void notification_clicked(CFPropertyListRef context) { GrowlNotifierSignaler* signaler; const QObject* receiver; const char* slot; void* qcontext; //pid_t pid; getContext(context, &signaler, &receiver, &slot, 0, &qcontext/*, &pid*/); //if (pid == getpid()) { QObject::connect(signaler,SIGNAL(notificationClicked(void*)),receiver,slot); signaler->emitNotificationClicked(qcontext); QObject::disconnect(signaler,SIGNAL(notificationClicked(void*)),receiver,slot); //} } //------------------------------------------------------------------------------ /** * The callback function, used by Growl to notify that a notification has * timed out. * \param context the context of the notification */ void notification_timeout(CFPropertyListRef context) { GrowlNotifierSignaler* signaler; const QObject* receiver; const char* slot; void* qcontext; //pid_t pid; getContext(context, &signaler, &receiver, 0, &slot, &qcontext /*, &pid*/); //if (pid == getpid()) { QObject::connect(signaler,SIGNAL(notificationTimedOut(void*)),receiver,slot); signaler->emitNotificationTimeout(qcontext); QObject::disconnect(signaler,SIGNAL(notificationTimedOut(void*)),receiver,slot); //} } //------------------------------------------------------------------------------ /** * Constructs a GrowlNotifier. * * \param notifications the list names of all notifications that can be sent * by this notifier. * \param default_notifications the list of names of the notifications that * should be enabled by default. * \param app the name of the application under which the notifier should * register with growl. */ GrowlNotifier::GrowlNotifier( const QStringList& notifications, const QStringList& default_notifications, const QString& app) { // Initialize signaler signaler_ = new GrowlNotifierSignaler(); // All Notifications QStringList::ConstIterator it; CFMutableArrayRef allNotifications = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); for ( it = notifications.begin(); it != notifications.end(); ++it ) CFArrayAppendValue(allNotifications, qString2CFString(*it)); // Default Notifications CFMutableArrayRef defaultNotifications = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); for ( it = default_notifications.begin(); it != default_notifications.end(); ++it ) CFArrayAppendValue(defaultNotifications, qString2CFString(*it)); // Initialize delegate InitGrowlDelegate(&delegate_); if (!app.isEmpty()) delegate_.applicationName = qString2CFString(app); CFTypeRef keys[] = { GROWL_NOTIFICATIONS_ALL, GROWL_NOTIFICATIONS_DEFAULT }; CFTypeRef values[] = { allNotifications, defaultNotifications }; delegate_.registrationDictionary = CFDictionaryCreate( kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); delegate_.growlNotificationWasClicked = ¬ification_clicked; delegate_.growlNotificationTimedOut = ¬ification_timeout; // Register with Growl Growl_SetDelegate(&delegate_); } /** * \brief Sends a notification to Growl. * * \param name the registered name of the notification. * \param title the title for the notification. * \param description the description of the notification. * \param icon the icon of the notification. * \param sticky whether the notification should be sticky (i.e. require a * click to discard. * \param receiver the receiving object which will be signaled when the * notification is clicked. May be NULL. * \param slot the slot to be signaled when the notification is clicked. * \param context the context which will be passed back to the slot * May be NULL. */ void GrowlNotifier::notify(const QString& name, const QString& title, const QString& description, const QPixmap& p, bool sticky, const QObject* receiver, const char* clicked_slot, const char* timeout_slot, void* qcontext) { // Convert the image if necessary CFDataRef icon = 0; if (!p.isNull()) { QByteArray img_data; QBuffer buffer(&img_data); buffer.open(QIODevice::WriteOnly); p.save(&buffer, "PNG"); icon = CFDataCreate( NULL, (UInt8*) img_data.data(), img_data.size()); } // Convert strings CFStringRef cf_title = qString2CFString(title); CFStringRef cf_description = qString2CFString(description); CFStringRef cf_name = qString2CFString(name); // Do notification CFPropertyListRef context = createContext(signaler_, receiver, clicked_slot, timeout_slot, qcontext/*, getpid()*/); Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext( cf_title, cf_description, cf_name, icon, 0, sticky, context); // Release intermediary datastructures CFRelease(context); if (icon) CFRelease(icon); if (cf_title) CFRelease(cf_title); if (cf_description) CFRelease(cf_description); if (cf_name) CFRelease(cf_name); } //----------------------------------------------------------------------------- #include "growlnotifier.moc" psi-0.14/src/libpsi/tools/growlnotifier/growlnotifier.h0000644000175000017500000000345711305557617021524 0ustar janjan/* * growlnotifier.h - A simple Qt interface to Growl * * Copyright (C) 2005 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GROWLNOTIFIER_H #define GROWLNOTIFIER_H #include #include #include #include #include class GrowlNotifierSignaler; /** * \brief A simple interface to Growl. */ class GrowlNotifier { public: GrowlNotifier( const QStringList& notifications, const QStringList& default_notifications, const QString& app_name = ""); void notify(const QString& name, const QString& title, const QString& description, const QPixmap& icon = QPixmap(), bool sticky = false, const QObject* receiver = 0, const char* clicked_slot = 0, const char* timeout_slot = 0, void* context = 0); private: struct Growl_Delegate delegate_; GrowlNotifierSignaler* signaler_; }; #endif psi-0.14/src/libpsi/tools/spellchecker/0000755000175000017500000000000011305557617016222 5ustar janjanpsi-0.14/src/libpsi/tools/spellchecker/spellhighlighter.cpp0000644000175000017500000000151011305557617022261 0ustar janjan#include "spellhighlighter.h" #include "spellchecker.h" #include "common.h" SpellHighlighter::SpellHighlighter(QTextDocument* d) : QSyntaxHighlighter(d) { } void SpellHighlighter::highlightBlock(const QString& text) { // Underline QTextCharFormat tcf; tcf.setUnderlineColor(QColor(255,0,0)); if(qVersionInt() >= 0x040400 && qVersionInt() < 0x040402) { tcf.setUnderlineStyle(QTextCharFormat::DotLine); } else { tcf.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline); } // Match words (minimally) QRegExp expression("\\b\\w+\\b"); // Iterate through all words int index = text.indexOf(expression); while (index >= 0) { int length = expression.matchedLength(); if (!SpellChecker::instance()->isCorrect(expression.cap())) setFormat(index, length, tcf); index = text.indexOf(expression, index + length); } } psi-0.14/src/libpsi/tools/spellchecker/spellchecker.pri0000644000175000017500000000073611305557617021410 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/spellchecker.h $$PWD/spellhighlighter.h SOURCES += $$PWD/spellchecker.cpp $$PWD/spellhighlighter.cpp mac { HEADERS += $$PWD/macspellchecker.h OBJECTIVE_SOURCES += $$PWD/macspellchecker.mm } !mac:contains(DEFINES, HAVE_ASPELL) { HEADERS += $$PWD/aspellchecker.h SOURCES += $$PWD/aspellchecker.cpp } !mac:contains(DEFINES, HAVE_ENCHANT) { HEADERS += $$PWD/enchantchecker.h SOURCES += $$PWD/enchantchecker.cpp } psi-0.14/src/libpsi/tools/spellchecker/spellhighlighter.h0000644000175000017500000000040611305557617021731 0ustar janjan#ifndef SPELLHIGHLIGHTER_H #define SPELLHIGHLIGHTER_H #include class QString; class SpellHighlighter : public QSyntaxHighlighter { public: SpellHighlighter(QTextDocument*); virtual void highlightBlock(const QString& text); }; #endif psi-0.14/src/libpsi/tools/spellchecker/spellchecker.h0000644000175000017500000000276211305557617021046 0ustar janjan/* * spellchecker.h * * Copyright (C) 2006 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SPELLCHECKER_H #define SPELLCHECKER_H #include #include #include class SpellChecker : public QObject { public: static SpellChecker* instance(); virtual bool available() const; virtual bool writable() const; virtual QList suggestions(const QString&); virtual bool isCorrect(const QString&); virtual bool add(const QString&); protected: SpellChecker(); virtual ~SpellChecker(); private: static SpellChecker* instance_; }; #endif psi-0.14/src/libpsi/tools/spellchecker/enchantchecker.h0000644000175000017500000000276511305557617021352 0ustar janjan/* * enchantchecker.h * * Copyright (C) 2009 Caolán McNamara * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ENCHANTCHECKER_H #define ENCHANTCHECKER_H #include #include #include "spellchecker.h" namespace enchant { class Dict; } class EnchantChecker : public SpellChecker { public: EnchantChecker(); ~EnchantChecker(); virtual QList suggestions(const QString&); virtual bool isCorrect(const QString&); virtual bool add(const QString&); virtual bool available() const; virtual bool writable() const; private: enchant::Dict* speller_; }; #endif psi-0.14/src/libpsi/tools/spellchecker/aspellchecker.cpp0000644000175000017500000000617011305557617021537 0ustar janjan/* * aspellchecker.cpp * * Copyright (C) 2006 Remko Troncon * Thanks to Ephraim. * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "aspell.h" #include "aspellchecker.h" ASpellChecker::ASpellChecker() { config_ = NULL; speller_ = NULL; config_ = new_aspell_config(); aspell_config_replace(config_, "encoding", "utf-8"); #ifdef Q_WS_WIN aspell_config_replace(config_, "conf-dir", QDir::homeDirPath()); aspell_config_replace(config_, "data-dir", QString("%1/aspell/data").arg(QCoreApplication::applicationDirPath())); aspell_config_replace(config_, "dict-dir", QString("%1/aspell/dict").arg(QCoreApplication::applicationDirPath())); #endif AspellCanHaveError* ret = new_aspell_speller(config_); if (aspell_error_number(ret) == 0) { speller_ = to_aspell_speller(ret); } else { qWarning() << QString("Aspell error: %1").arg(aspell_error_message(ret)); } } ASpellChecker::~ASpellChecker() { if(config_) { delete_aspell_config(config_); config_ = NULL; } if(speller_) { delete_aspell_speller(speller_); speller_ = NULL; } } bool ASpellChecker::isCorrect(const QString& word) { if(speller_) { int correct = aspell_speller_check(speller_, word.toUtf8().constData(), -1); return (correct != 0); } return true; } QList ASpellChecker::suggestions(const QString& word) { QList words; if (speller_) { const AspellWordList* list = aspell_speller_suggest(speller_, word.toUtf8(), -1); AspellStringEnumeration* elements = aspell_word_list_elements(list); const char *c_word; while ((c_word = aspell_string_enumeration_next(elements)) != NULL) { words += QString::fromUtf8(c_word); } delete_aspell_string_enumeration(elements); } return words; } bool ASpellChecker::add(const QString& word) { bool result = false; if (config_ && speller_) { QString trimmed_word = word.trimmed(); if(!word.isEmpty()) { aspell_speller_add_to_personal(speller_, trimmed_word.toUtf8(), trimmed_word.toUtf8().length()); aspell_speller_save_all_word_lists(speller_); result = true; } } return result; } bool ASpellChecker::available() const { return (speller_ != NULL); } bool ASpellChecker::writable() const { return false; } psi-0.14/src/libpsi/tools/spellchecker/macspellchecker.h0000644000175000017500000000266011305557617021524 0ustar janjan/* * macspellchecker.h * * Copyright (C) 2006 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MACSPELLCHECKER_H #define MACSPELLCHECKER_H #include #include #include "spellchecker.h" class MacSpellChecker : public SpellChecker { public: MacSpellChecker(); ~MacSpellChecker(); virtual QList suggestions(const QString&); virtual bool isCorrect(const QString&); virtual bool add(const QString&); virtual bool available() const; virtual bool writable() const; }; #endif psi-0.14/src/libpsi/tools/spellchecker/aspellchecker.h0000644000175000017500000000301411305557617021176 0ustar janjan/* * aspellchecker.h * * Copyright (C) 2006 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ASPELLCHECKER_H #define ASPELLCHECKER_H #include #include #include "spellchecker.h" struct AspellConfig; struct AspellSpeller; class ASpellChecker : public SpellChecker { public: ASpellChecker(); ~ASpellChecker(); virtual QList suggestions(const QString&); virtual bool isCorrect(const QString&); virtual bool add(const QString&); virtual bool available() const; virtual bool writable() const; private: AspellConfig* config_; AspellSpeller* speller_; }; #endif psi-0.14/src/libpsi/tools/spellchecker/macspellchecker.mm0000644000175000017500000000377311305557617021714 0ustar janjan/* * macspellchecker.cpp * * Copyright (C) 2006 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "macspellchecker.h" MacSpellChecker::MacSpellChecker() { } MacSpellChecker::~MacSpellChecker() { } bool MacSpellChecker::isCorrect(const QString& word) { NSString* ns_word = [NSString stringWithUTF8String: word.toUtf8().data()]; NSRange range = {0,0}; range = [[NSSpellChecker sharedSpellChecker] checkSpellingOfString:ns_word startingAt:0]; return (range.length == 0); } QList MacSpellChecker::suggestions(const QString& word) { QList s; NSString* ns_word = [NSString stringWithUTF8String: word.toUtf8().data()]; NSArray* ns_suggestions = [[NSSpellChecker sharedSpellChecker] guessesForWord:ns_word]; for(unsigned int i = 0; i < [ns_suggestions count]; i++) { s += QString::fromUtf8([[ns_suggestions objectAtIndex:i] UTF8String]); } return s; } bool MacSpellChecker::add(const QString& word) { return false; } bool MacSpellChecker::available() const { return true; } bool MacSpellChecker::writable() const { return false; } psi-0.14/src/libpsi/tools/spellchecker/enchantchecker.cpp0000644000175000017500000000505711305557617021702 0ustar janjan/* * enchantchecker.cpp * * Copyright (C) 2009 Caolán McNamara * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "enchant++.h" #include "enchantchecker.h" EnchantChecker::EnchantChecker() : speller_(NULL) { if (enchant::Broker *instance = enchant::Broker::instance()) { std::string lang("en_US"); if (instance->dict_exists(QTextCodec::locale())) lang = QTextCodec::locale(); try { speller_ = enchant::Broker::instance()->request_dict(lang); } catch (enchant::Exception &e) { qWarning() << QString("Enchant error: %1").arg(e.what()); } } } EnchantChecker::~EnchantChecker() { delete speller_; speller_ = NULL; } bool EnchantChecker::isCorrect(const QString& word) { if(speller_) { return speller_->check(word.toUtf8().constData()); } return true; } QList EnchantChecker::suggestions(const QString& word) { QList words; if (speller_) { std::vector out_suggestions; speller_->suggest(word.toUtf8().constData(), out_suggestions); std::vector::iterator aE = out_suggestions.end(); for (std::vector::iterator aI = out_suggestions.begin(); aI != aE; ++aI) { words += QString::fromUtf8(aI->c_str()); } } return words; } bool EnchantChecker::add(const QString& word) { bool result = false; if (speller_) { QString trimmed_word = word.trimmed(); if(!word.isEmpty()) { speller_->add_to_pwl(word.toUtf8().constData()); result = true; } } return result; } bool EnchantChecker::available() const { return (speller_ != NULL); } bool EnchantChecker::writable() const { return false; } psi-0.14/src/libpsi/tools/spellchecker/spellchecker.cpp0000644000175000017500000000400611305557617021372 0ustar janjan/* * spellchecker.cpp * * Copyright (C) 2006 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "spellchecker.h" #include #if defined(Q_WS_MAC) #include "macspellchecker.h" #elif defined(HAVE_ENCHANT) #include "enchantchecker.h" #elif defined(HAVE_ASPELL) #include "aspellchecker.h" #endif SpellChecker* SpellChecker::instance() { if (!instance_) { #ifdef Q_WS_MAC instance_ = new MacSpellChecker(); #elif defined(HAVE_ENCHANT) instance_ = new EnchantChecker(); #elif defined(HAVE_ASPELL) instance_ = new ASpellChecker(); #else instance_ = new SpellChecker(); #endif } return instance_; } SpellChecker::SpellChecker() : QObject(QCoreApplication::instance()) { } SpellChecker::~SpellChecker() { } bool SpellChecker::available() const { return false; } bool SpellChecker::writable() const { return true; } bool SpellChecker::isCorrect(const QString&) { return true; } QList SpellChecker::suggestions(const QString&) { return QList(); } bool SpellChecker::add(const QString&) { return false; } SpellChecker* SpellChecker::instance_ = NULL; psi-0.14/src/libpsi/tools/globalshortcut/0000755000175000017500000000000011305557617016612 5ustar janjanpsi-0.14/src/libpsi/tools/globalshortcut/globalshortcuttrigger.h0000644000175000017500000000265211305557617023410 0ustar janjan/* * globalshortcuttrigger.h - Helper class activating global shortcut * Copyright (C) 2006 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GLOBALSHORTCUTTRIGGER_H #define GLOBALSHORTCUTTRIGGER_H #include "globalshortcutmanager.h" #include class GlobalShortcutManager::KeyTrigger : public QObject { Q_OBJECT public: /** * Is there any slot connected to this hotkey? */ bool isUsed() const { return QObject::receivers(SIGNAL(triggered())) > 0; } signals: void triggered(); private: /** * Registers the \a key. */ KeyTrigger(const QKeySequence& key); /** * Unregisters the key. */ ~KeyTrigger(); friend class GlobalShortcutManager; /** * Platform-specific helper */ class Impl; Impl* d; }; #endif psi-0.14/src/libpsi/tools/globalshortcut/globalshortcut.pri0000644000175000017500000000051711305557617022365 0ustar janjanHEADERS += $$PWD/globalshortcutmanager.h $$PWD/globalshortcuttrigger.h SOURCES += $$PWD/globalshortcutmanager.cpp INCLUDEPATH += $$PWD DEPENDPATH += $$PWD unix:!mac { SOURCES += $$PWD/globalshortcutmanager_x11.cpp } win32: { SOURCES += $$PWD/globalshortcutmanager_win.cpp } mac: { SOURCES += $$PWD/globalshortcutmanager_mac.cpp } psi-0.14/src/libpsi/tools/globalshortcut/globalshortcutmanager.h0000644000175000017500000000266311305557617023361 0ustar janjan/* * globalshortcutmanager.h - Class managing global shortcuts * Copyright (C) 2006 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GLOBALSHORTCUTMANAGER_H #define GLOBALSHORTCUTMANAGER_H #include #include #include class QObject; class KeyTrigger; class GlobalShortcutManager : public QObject { public: static GlobalShortcutManager* instance(); static void connect(const QKeySequence& key, QObject* receiver, const char* slot); static void disconnect(const QKeySequence& key, QObject* receiver, const char* slot); static void clear(); private: GlobalShortcutManager(); ~GlobalShortcutManager(); static GlobalShortcutManager* instance_; class KeyTrigger; QMap triggers_; }; #endif psi-0.14/src/libpsi/tools/globalshortcut/globalshortcutmanager_x11.cpp0000644000175000017500000002744511305557617024412 0ustar janjan/* * globalshortcutmanager_x11.cpp - X11 implementation of global shortcuts * Copyright (C) 2003-2007 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "globalshortcutmanager.h" #include "globalshortcuttrigger.h" #include #include #include #include #include #include #include #ifdef KeyPress // defined by X11 headers const int XKeyPress = KeyPress; const int XKeyRelease = KeyRelease; #undef KeyPress #endif class X11KeyTrigger { public: virtual ~X11KeyTrigger() {} virtual void activate() = 0; virtual bool isAccepted(int qkey) const = 0; }; class X11KeyTriggerManager : public QObject { public: static X11KeyTriggerManager* instance() { if(!instance_) instance_ = new X11KeyTriggerManager(); return instance_; } void addTrigger(X11KeyTrigger* trigger) { triggers_ << trigger; } void removeTrigger(X11KeyTrigger* trigger) { triggers_.removeAll(trigger); } struct Qt_XK_Keygroup { char num; int sym[3]; }; protected: // reimplemented bool eventFilter(QObject* o, QEvent* e) { if(e->type() == QEvent::KeyPress) { QKeyEvent* k = static_cast(e); int qkey = k->key(); if (k->modifiers() & Qt::ShiftModifier) qkey |= Qt::SHIFT; if (k->modifiers() & Qt::ControlModifier) qkey |= Qt::CTRL; if (k->modifiers() & Qt::AltModifier) qkey |= Qt::ALT; if (k->modifiers() & Qt::MetaModifier) qkey |= Qt::META; foreach(X11KeyTrigger* trigger, triggers_) { if (trigger->isAccepted(qkey)) { trigger->activate(); return true; } } } return QObject::eventFilter(o, e); } private: X11KeyTriggerManager() : QObject(QCoreApplication::instance()) { QCoreApplication::instance()->installEventFilter(this); } static X11KeyTriggerManager* instance_; QList triggers_; private: struct Qt_XK_Keymap { int key; Qt_XK_Keygroup xk; }; static Qt_XK_Keymap qt_xk_table[]; static long alt_mask; static long meta_mask; static long super_mask; static long hyper_mask; static long numlock_mask; static bool haveMods; // adapted from qapplication_x11.cpp static void ensureModifiers() { if (haveMods) return; Display* appDpy = QX11Info::display(); XModifierKeymap* map = XGetModifierMapping(appDpy); if (map) { // XKeycodeToKeysym helper code adapeted from xmodmap int min_keycode, max_keycode, keysyms_per_keycode = 1; XDisplayKeycodes (appDpy, &min_keycode, &max_keycode); XFree(XGetKeyboardMapping (appDpy, min_keycode, (max_keycode - min_keycode + 1), &keysyms_per_keycode)); int i, maskIndex = 0, mapIndex = 0; for (maskIndex = 0; maskIndex < 8; maskIndex++) { for (i = 0; i < map->max_keypermod; i++) { if (map->modifiermap[mapIndex]) { KeySym sym; int symIndex = 0; do { sym = XKeycodeToKeysym(appDpy, map->modifiermap[mapIndex], symIndex); symIndex++; } while ( !sym && symIndex < keysyms_per_keycode); if (alt_mask == 0 && (sym == XK_Alt_L || sym == XK_Alt_R)) { alt_mask = 1 << maskIndex; } if (meta_mask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R)) { meta_mask = 1 << maskIndex; } if (super_mask == 0 && (sym == XK_Super_L || sym == XK_Super_R)) { super_mask = 1 << maskIndex; } if (hyper_mask == 0 && (sym == XK_Hyper_L || sym == XK_Hyper_R)) { hyper_mask = 1 << maskIndex; } if (numlock_mask == 0 && (sym == XK_Num_Lock)) { numlock_mask = 1 << maskIndex; } } mapIndex++; } } XFreeModifiermap(map); // logic from qt source see gui/kernel/qkeymapper_x11.cpp if (meta_mask == 0 || meta_mask == alt_mask) { // no meta keys... s,meta,super, meta_mask = super_mask; if (meta_mask == 0 || meta_mask == alt_mask) { // no super keys either? guess we'll use hyper then meta_mask = hyper_mask; } } } else { // assume defaults alt_mask = Mod1Mask; meta_mask = Mod4Mask; } haveMods = true; } public: static bool convertKeySequence(const QKeySequence& ks, unsigned int* _mod, Qt_XK_Keygroup* _kg) { int code = ks; ensureModifiers(); unsigned int mod = 0; if (code & Qt::META) mod |= meta_mask; if (code & Qt::SHIFT) mod |= ShiftMask; if (code & Qt::CTRL) mod |= ControlMask; if (code & Qt::ALT) mod |= alt_mask; Qt_XK_Keygroup kg; kg.num = 0; kg.sym[0] = 0; code &= ~Qt::KeyboardModifierMask; bool found = false; for (int n = 0; qt_xk_table[n].key != Qt::Key_unknown; ++n) { if (qt_xk_table[n].key == code) { kg = qt_xk_table[n].xk; found = true; break; } } if (!found) { // try latin1 if (code >= 0x20 && code <= 0x7f) { kg.num = 1; kg.sym[0] = code; } } if (!kg.num) return false; if (_mod) *_mod = mod; if (_kg) *_kg = kg; return true; } static QList ignModifiersList() { QList ret; if (numlock_mask) { ret << 0 << LockMask << numlock_mask << (LockMask | numlock_mask); } else { ret << 0 << LockMask; } return ret; } }; X11KeyTriggerManager* X11KeyTriggerManager::instance_ = NULL; class GlobalShortcutManager::KeyTrigger::Impl : public X11KeyTrigger { private: KeyTrigger* trigger_; int qkey_; struct GrabbedKey { int code; uint mod; }; QList grabbedKeys_; static bool failed; static int XGrabErrorHandler(Display *, XErrorEvent *) { qWarning("failed to grab key"); failed = true; return 0; } void bind(int keysym, unsigned int mod) { int code = XKeysymToKeycode(QX11Info::display(), keysym); // don't grab keys with empty code (because it means just the modifier key) if (keysym && !code) return; failed = false; XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler); WId w = QX11Info::appRootWindow(); foreach(long mask_mod, X11KeyTriggerManager::ignModifiersList()) { XGrabKey(QX11Info::display(), code, mod | mask_mod, w, False, GrabModeAsync, GrabModeAsync); GrabbedKey grabbedKey; grabbedKey.code = code; grabbedKey.mod = mod | mask_mod; grabbedKeys_ << grabbedKey; } XSync(QX11Info::display(), False); XSetErrorHandler(savedErrorHandler); } public: /** * Constructor registers the hotkey. */ Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks) : trigger_(t) , qkey_(ks) { X11KeyTriggerManager::instance()->addTrigger(this); X11KeyTriggerManager::Qt_XK_Keygroup kg; unsigned int mod; if (X11KeyTriggerManager::convertKeySequence(ks, &mod, &kg)) for (int n = 0; n < kg.num; ++n) bind(kg.sym[n], mod); } /** * Destructor unregisters the hotkey. */ ~Impl() { X11KeyTriggerManager::instance()->removeTrigger(this); foreach(GrabbedKey key, grabbedKeys_) XUngrabKey(QX11Info::display(), key.code, key.mod, QX11Info::appRootWindow()); } void activate() { emit trigger_->triggered(); } bool isAccepted(int qkey) const { return qkey_ == qkey; } }; bool GlobalShortcutManager::KeyTrigger::Impl::failed; long X11KeyTriggerManager::alt_mask = 0; long X11KeyTriggerManager::meta_mask = 0; long X11KeyTriggerManager::super_mask = 0; long X11KeyTriggerManager::hyper_mask = 0; long X11KeyTriggerManager::numlock_mask = 0; bool X11KeyTriggerManager::haveMods = false; X11KeyTriggerManager::Qt_XK_Keymap X11KeyTriggerManager::qt_xk_table[] = { { Qt::Key_Escape, {1, { XK_Escape }}}, { Qt::Key_Tab, {2, { XK_Tab, XK_KP_Tab }}}, { Qt::Key_Backtab, {1, { XK_ISO_Left_Tab }}}, { Qt::Key_Backspace, {1, { XK_BackSpace }}}, { Qt::Key_Return, {1, { XK_Return }}}, { Qt::Key_Enter, {1, { XK_KP_Enter }}}, { Qt::Key_Insert, {2, { XK_Insert, XK_KP_Insert }}}, { Qt::Key_Delete, {3, { XK_Delete, XK_KP_Delete, XK_Clear }}}, { Qt::Key_Pause, {1, { XK_Pause }}}, { Qt::Key_Print, {1, { XK_Print }}}, { Qt::Key_SysReq, {1, { XK_Sys_Req }}}, { Qt::Key_Clear, {1, { XK_KP_Begin }}}, { Qt::Key_Home, {2, { XK_Home, XK_KP_Home }}}, { Qt::Key_End, {2, { XK_End, XK_KP_End }}}, { Qt::Key_Left, {2, { XK_Left, XK_KP_Left }}}, { Qt::Key_Up, {2, { XK_Up, XK_KP_Up }}}, { Qt::Key_Right, {2, { XK_Right, XK_KP_Right }}}, { Qt::Key_Down, {2, { XK_Down, XK_KP_Down }}}, { Qt::Key_PageUp, {2, { XK_Prior, XK_KP_Prior }}}, { Qt::Key_PageDown, {2, { XK_Next, XK_KP_Next }}}, { Qt::Key_Shift, {3, { XK_Shift_L, XK_Shift_R, XK_Shift_Lock }}}, { Qt::Key_Control, {2, { XK_Control_L, XK_Control_R }}}, { Qt::Key_Meta, {2, { XK_Meta_L, XK_Meta_R }}}, { Qt::Key_Alt, {2, { XK_Alt_L, XK_Alt_R }}}, { Qt::Key_CapsLock, {1, { XK_Caps_Lock }}}, { Qt::Key_NumLock, {1, { XK_Num_Lock }}}, { Qt::Key_ScrollLock, {1, { XK_Scroll_Lock }}}, { Qt::Key_Space, {2, { XK_space, XK_KP_Space }}}, { Qt::Key_Equal, {2, { XK_equal, XK_KP_Equal }}}, { Qt::Key_Asterisk, {2, { XK_asterisk, XK_KP_Multiply }}}, { Qt::Key_Plus, {2, { XK_plus, XK_KP_Add }}}, { Qt::Key_Comma, {2, { XK_comma, XK_KP_Separator }}}, { Qt::Key_Minus, {2, { XK_minus, XK_KP_Subtract }}}, { Qt::Key_Period, {2, { XK_period, XK_KP_Decimal }}}, { Qt::Key_Slash, {2, { XK_slash, XK_KP_Divide }}}, { Qt::Key_F1, {1, { XK_F1 }}}, { Qt::Key_F2, {1, { XK_F2 }}}, { Qt::Key_F3, {1, { XK_F3 }}}, { Qt::Key_F4, {1, { XK_F4 }}}, { Qt::Key_F5, {1, { XK_F5 }}}, { Qt::Key_F6, {1, { XK_F6 }}}, { Qt::Key_F7, {1, { XK_F7 }}}, { Qt::Key_F8, {1, { XK_F8 }}}, { Qt::Key_F9, {1, { XK_F9 }}}, { Qt::Key_F10, {1, { XK_F10 }}}, { Qt::Key_F11, {1, { XK_F11 }}}, { Qt::Key_F12, {1, { XK_F12 }}}, { Qt::Key_F13, {1, { XK_F13 }}}, { Qt::Key_F14, {1, { XK_F14 }}}, { Qt::Key_F15, {1, { XK_F15 }}}, { Qt::Key_F16, {1, { XK_F16 }}}, { Qt::Key_F17, {1, { XK_F17 }}}, { Qt::Key_F18, {1, { XK_F18 }}}, { Qt::Key_F19, {1, { XK_F19 }}}, { Qt::Key_F20, {1, { XK_F20 }}}, { Qt::Key_F21, {1, { XK_F21 }}}, { Qt::Key_F22, {1, { XK_F22 }}}, { Qt::Key_F23, {1, { XK_F23 }}}, { Qt::Key_F24, {1, { XK_F24 }}}, { Qt::Key_F25, {1, { XK_F25 }}}, { Qt::Key_F26, {1, { XK_F26 }}}, { Qt::Key_F27, {1, { XK_F27 }}}, { Qt::Key_F28, {1, { XK_F28 }}}, { Qt::Key_F29, {1, { XK_F29 }}}, { Qt::Key_F30, {1, { XK_F30 }}}, { Qt::Key_F31, {1, { XK_F31 }}}, { Qt::Key_F32, {1, { XK_F32 }}}, { Qt::Key_F33, {1, { XK_F33 }}}, { Qt::Key_F34, {1, { XK_F34 }}}, { Qt::Key_F35, {1, { XK_F35 }}}, { Qt::Key_Super_L, {1, { XK_Super_L }}}, { Qt::Key_Super_R, {1, { XK_Super_R }}}, { Qt::Key_Menu, {1, { XK_Menu }}}, { Qt::Key_Hyper_L, {1, { XK_Hyper_L }}}, { Qt::Key_Hyper_R, {1, { XK_Hyper_R }}}, { Qt::Key_Help, {1, { XK_Help }}}, { Qt::Key_Direction_L, {0, { 0 }}}, { Qt::Key_Direction_R, {0, { 0 }}}, { Qt::Key_unknown, {0, { 0 }}}, }; GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key) { d = new Impl(this, key); } GlobalShortcutManager::KeyTrigger::~KeyTrigger() { delete d; d = 0; } psi-0.14/src/libpsi/tools/globalshortcut/globalshortcutmanager.cpp0000644000175000017500000000520011305557617023702 0ustar janjan/* * globalshortcutmanager.cpp - Class managing global shortcuts * Copyright (C) 2006 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "globalshortcutmanager.h" #include #include "globalshortcuttrigger.h" /** * \brief Constructs new GlobalShortcutManager. */ GlobalShortcutManager::GlobalShortcutManager() : QObject(QCoreApplication::instance()) { } GlobalShortcutManager::~GlobalShortcutManager() { clear(); } GlobalShortcutManager* GlobalShortcutManager::instance_ = 0; /** * \brief Returns the instance of GlobalShortcutManager. */ GlobalShortcutManager* GlobalShortcutManager::instance() { if (!instance_) instance_ = new GlobalShortcutManager(); return instance_; } /** * \brief Connects a key sequence with a slot. * \param key, global shortcut to be connected * \param receiver, object which should receive the notification * \param slot, the SLOT() of the \a receiver which should be triggerd if the \a key is activated */ void GlobalShortcutManager::connect(const QKeySequence& key, QObject* receiver, const char* slot) { KeyTrigger* t = instance()->triggers_[key]; if (!t) { t = new KeyTrigger(key); instance()->triggers_.insert(key, t); } QObject::connect(t, SIGNAL(triggered()), receiver, slot); } /** * \brief Disonnects a key sequence from a slot. * \param key, global shortcut to be disconnected * \param receiver, object which \a slot is about to be disconnected * \param slot, the SLOT() of the \a receiver which should no longer be triggerd if the \a key is activated */ void GlobalShortcutManager::disconnect(const QKeySequence& key, QObject* receiver, const char* slot) { KeyTrigger* t = instance()->triggers_[key]; if (!t) { return; } QObject::disconnect(t, SIGNAL(triggered()), receiver, slot); if (!t->isUsed()) { delete instance()->triggers_.take(key); } } void GlobalShortcutManager::clear() { foreach (KeyTrigger* t, instance()->triggers_) delete t; instance()->triggers_.clear(); } psi-0.14/src/libpsi/tools/globalshortcut/globalshortcutmanager_mac.cpp0000644000175000017500000002525011305557617024531 0ustar janjan/* * globalshortcutmanager_mac.cpp - Mac OS X implementation of global shortcuts * Copyright (C) 2003-2007 Eric Smith, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "globalshortcutmanager.h" #include "globalshortcuttrigger.h" // TODO: // - don't invoke hotkey if there is a modal dialog? // - do multi-mapping, like the x11 version #include #include class MacKeyTrigger { public: virtual ~MacKeyTrigger() {} virtual void activate() = 0; virtual bool isAccepted(int id) const = 0; }; class MacKeyTriggerManager : public QObject { public: static MacKeyTriggerManager* instance() { if(!instance_) instance_ = new MacKeyTriggerManager(); return instance_; } void addTrigger(MacKeyTrigger* trigger) { triggers_ << trigger; } void removeTrigger(MacKeyTrigger* trigger) { triggers_.removeAll(trigger); } private: MacKeyTriggerManager() : QObject(QCoreApplication::instance()) { initAscii2KeyCodeTable(&key_codes_); hot_key_function_ = NewEventHandlerUPP(hotKeyHandler); EventTypeSpec type; type.eventClass = kEventClassKeyboard; type.eventKind = kEventHotKeyPressed; InstallApplicationEventHandler(hot_key_function_, 1, &type, this, NULL); } /** * Callback function invoked when the user hits a hot-key. */ static pascal OSStatus hotKeyHandler(EventHandlerCallRef /*nextHandler*/, EventRef theEvent, void* userData) { EventHotKeyID hkID; GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID); static_cast(userData)->activated(hkID.id); return noErr; } void activated(int id) { foreach(MacKeyTrigger* trigger, triggers_) { if (trigger->isAccepted(id)) { trigger->activate(); break; } } } static MacKeyTriggerManager* instance_; QList triggers_; typedef struct { short kchrID; Str255 KCHRname; short transtable[256]; } Ascii2KeyCodeTable; enum { kTableCountOffset = 256 + 2, kFirstTableOffset = 256 + 4, kTableSize = 128 }; static EventHandlerUPP hot_key_function_; static Ascii2KeyCodeTable key_codes_; private: /** * initAscii2KeyCodeTable initializes the ascii to key code * look up table using the currently active KCHR resource. This * routine calls GetResource so it cannot be called at interrupt time. */ static OSStatus initAscii2KeyCodeTable(Ascii2KeyCodeTable* ttable) { unsigned char* theCurrentKCHR, *ithKeyTable; short count, i, j, resID; Handle theKCHRRsrc; ResType rType; // set up our table to all minus ones for (i = 0; i < 256; i++) ttable->transtable[i] = -1; // find the current kchr resource ID ttable->kchrID = (short)GetScriptVariable(smCurrentScript, smScriptKeys); // get the current KCHR resource theKCHRRsrc = GetResource('KCHR', ttable->kchrID); if (theKCHRRsrc == NULL) return resNotFound; GetResInfo(theKCHRRsrc, &resID, &rType, ttable->KCHRname); // dereference the resource theCurrentKCHR = (unsigned char *)(*theKCHRRsrc); // get the count from the resource count = *(short*)(theCurrentKCHR + kTableCountOffset); // build inverse table by merging all key tables for (i = 0; i < count; i++) { ithKeyTable = theCurrentKCHR + kFirstTableOffset + (i * kTableSize); for (j = 0; j < kTableSize; j++) { if (ttable->transtable[ ithKeyTable[j] ] == -1) ttable->transtable[ ithKeyTable[j] ] = j; } } return noErr; } /** * validateAscii2KeyCodeTable verifies that the ascii to key code * lookup table is synchronized with the current KCHR resource. If * it is not synchronized, then the table is re-built. This routine calls * GetResource so it cannot be called at interrupt time. * * Should probably call this at some point, in case the user has switched keyboard * layouts while we were running. */ static OSStatus validateAscii2KeyCodeTable(Ascii2KeyCodeTable* ttable, Boolean* wasChanged) { short theID; theID = (short) GetScriptVariable(smCurrentScript, smScriptKeys); if (theID != ttable->kchrID) { *wasChanged = true; return initAscii2KeyCodeTable(ttable); } else { *wasChanged = false; return noErr; } } /** * asciiToKeyCode looks up the ascii character in the key * code look up table and returns the virtual key code for that * letter. If there is no virtual key code for that letter, then * the value -1 will be returned. */ static short asciiToKeyCode(Ascii2KeyCodeTable* ttable, short asciiCode) { if (asciiCode >= 0 && asciiCode <= 255) return ttable->transtable[asciiCode]; else return false; } /** * Not used. */ static char keyCodeToAscii(short virtualKeyCode) { unsigned long state; long keyTrans; char charCode; Ptr kchr; state = 0; kchr = (Ptr)GetScriptVariable(smCurrentScript, smKCHRCache); keyTrans = KeyTranslate(kchr, virtualKeyCode, &state); charCode = keyTrans; if (!charCode) charCode = (keyTrans >> 16); return charCode; } private: struct Qt_Mac_Keymap { int qt_key; int mac_key; }; static Qt_Mac_Keymap qt_keymap[]; public: static bool convertKeySequence(const QKeySequence& ks, quint32* _key, quint32* _mod) { int code = ks[0]; quint32 mod = 0; if (code & Qt::META) mod |= controlKey; if (code & Qt::SHIFT) mod |= shiftKey; if (code & Qt::CTRL) mod |= cmdKey; if (code & Qt::ALT) mod |= optionKey; code &= ~Qt::KeyboardModifierMask; quint32 key = 0; for (int n = 0; qt_keymap[n].qt_key != Qt::Key_unknown; ++n) { if (qt_keymap[n].qt_key == code) { key = qt_keymap[n].mac_key; break; } } if (key == 0) { key = asciiToKeyCode(&key_codes_, code & 0xffff); } if (_mod) *_mod = mod; if (_key) *_key = key; return true; } }; MacKeyTriggerManager* MacKeyTriggerManager::instance_ = NULL; EventHandlerUPP MacKeyTriggerManager::hot_key_function_ = NULL; MacKeyTriggerManager::Ascii2KeyCodeTable MacKeyTriggerManager::key_codes_; class GlobalShortcutManager::KeyTrigger::Impl : public MacKeyTrigger { private: KeyTrigger* trigger_; EventHotKeyRef hotKey_; int id_; static int nextId; public: /** * Constructor registers the hotkey. */ Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks) : trigger_(t) , id_(0) { MacKeyTriggerManager::instance()->addTrigger(this); quint32 key, mod; if (MacKeyTriggerManager::convertKeySequence(ks, &key, &mod)) { EventHotKeyID hotKeyID; hotKeyID.signature = 'QtHK'; hotKeyID.id = nextId; OSStatus ret = RegisterEventHotKey(key, mod, hotKeyID, GetApplicationEventTarget(), 0, &hotKey_); if (ret != 0) { qWarning("RegisterEventHotKey(%d, %d): %d", key, mod, (int)ret); return; } id_ = nextId++; } } /** * Destructor unregisters the hotkey. */ ~Impl() { MacKeyTriggerManager::instance()->removeTrigger(this); if (id_) UnregisterEventHotKey(hotKey_); } void activate() { emit trigger_->triggered(); } bool isAccepted(int id) const { return id_ == id; } }; /* * The following table is from Apple sample-code. * Apple's headers don't appear to define any constants for the virtual key * codes of special keys, but these constants are somewhat documented in the chart at * * * The constants on the chartappear to be the same values as are used in Apple's iGetKeys * sample. * . * * See also . */ MacKeyTriggerManager::Qt_Mac_Keymap MacKeyTriggerManager::qt_keymap[] = { { Qt::Key_Escape, 0x35 }, { Qt::Key_Tab, 0x30 }, { Qt::Key_Backtab, 0 }, { Qt::Key_Backspace, 0x33 }, { Qt::Key_Return, 0x24 }, { Qt::Key_Enter, 0x4c }, // Return & Enter are different on the Mac { Qt::Key_Insert, 0 }, { Qt::Key_Delete, 0x75 }, { Qt::Key_Pause, 0 }, { Qt::Key_Print, 0 }, { Qt::Key_SysReq, 0 }, { Qt::Key_Clear, 0x47 }, { Qt::Key_Home, 0x73 }, { Qt::Key_End, 0x77 }, { Qt::Key_Left, 0x7b }, { Qt::Key_Up, 0x7e }, { Qt::Key_Right, 0x7c }, { Qt::Key_Down, 0x7d }, { Qt::Key_PageUp, 0x74 }, // Page Up { Qt::Key_PageDown, 0x79 }, // Page Down { Qt::Key_Shift, 0x38 }, { Qt::Key_Control, 0x3b }, { Qt::Key_Meta, 0x37 }, // Command { Qt::Key_Alt, 0x3a }, // Option { Qt::Key_CapsLock, 57 }, { Qt::Key_NumLock, 0 }, { Qt::Key_ScrollLock, 0 }, { Qt::Key_F1, 0x7a }, { Qt::Key_F2, 0x78 }, { Qt::Key_F3, 0x63 }, { Qt::Key_F4, 0x76 }, { Qt::Key_F5, 0x60 }, { Qt::Key_F6, 0x61 }, { Qt::Key_F7, 0x62 }, { Qt::Key_F8, 0x64 }, { Qt::Key_F9, 0x65 }, { Qt::Key_F10, 0x6d }, { Qt::Key_F11, 0x67 }, { Qt::Key_F12, 0x6f }, { Qt::Key_F13, 0x69 }, { Qt::Key_F14, 0x6b }, { Qt::Key_F15, 0x71 }, { Qt::Key_F16, 0 }, { Qt::Key_F17, 0 }, { Qt::Key_F18, 0 }, { Qt::Key_F19, 0 }, { Qt::Key_F20, 0 }, { Qt::Key_F21, 0 }, { Qt::Key_F22, 0 }, { Qt::Key_F23, 0 }, { Qt::Key_F24, 0 }, { Qt::Key_F25, 0 }, { Qt::Key_F26, 0 }, { Qt::Key_F27, 0 }, { Qt::Key_F28, 0 }, { Qt::Key_F29, 0 }, { Qt::Key_F30, 0 }, { Qt::Key_F31, 0 }, { Qt::Key_F32, 0 }, { Qt::Key_F33, 0 }, { Qt::Key_F34, 0 }, { Qt::Key_F35, 0 }, { Qt::Key_Super_L, 0 }, { Qt::Key_Super_R, 0 }, { Qt::Key_Menu, 0 }, { Qt::Key_Hyper_L, 0 }, { Qt::Key_Hyper_R, 0 }, { Qt::Key_Help, 0x72 }, { Qt::Key_Direction_L, 0 }, { Qt::Key_Direction_R, 0 }, { Qt::Key_unknown, 0 } }; int GlobalShortcutManager::KeyTrigger::Impl::nextId = 1; GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key) { d = new Impl(this, key); } GlobalShortcutManager::KeyTrigger::~KeyTrigger() { delete d; d = 0; } psi-0.14/src/libpsi/tools/globalshortcut/globalshortcutmanager_win.cpp0000644000175000017500000001215611305557617024567 0ustar janjan/* * globalshortcutmanager_win.cpp - Windows implementation of global shortcuts * Copyright (C) 2003-2006 Justin Karneges, Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "globalshortcutmanager.h" #include "globalshortcuttrigger.h" #include #include class GlobalShortcutManager::KeyTrigger::Impl : public QWidget { public: /** * Constructor registers the hotkey. */ Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks) : trigger_(t) , id_(0) { UINT mod, key; if (convertKeySequence(ks, &mod, &key)) if (RegisterHotKey(winId(), nextId, mod, key)) id_ = nextId++; } /** * Destructor unregisters the hotkey. */ ~Impl() { if (id_) UnregisterHotKey(winId(), id_); } /** * Triggers triggered() signal when the hotkey is activated. */ bool winEvent(MSG* m, long* result) { if (m->message == WM_HOTKEY && m->wParam == id_) { emit trigger_->triggered(); return true; } return QWidget::winEvent(m, result); } private: KeyTrigger* trigger_; int id_; static int nextId; private: struct Qt_VK_Keymap { int key; UINT vk; }; static Qt_VK_Keymap qt_vk_table[]; static bool convertKeySequence(const QKeySequence& ks, UINT* mod_, UINT* key_) { int code = ks; UINT mod = 0; if (code & Qt::META) mod |= MOD_WIN; if (code & Qt::SHIFT) mod |= MOD_SHIFT; if (code & Qt::CTRL) mod |= MOD_CONTROL; if (code & Qt::ALT) mod |= MOD_ALT; UINT key = 0; code &= ~Qt::KeyboardModifierMask; if (code >= 0x20 && code <= 0x7f) key = code; else { for (int n = 0; qt_vk_table[n].key != Qt::Key_unknown; ++n) { if (qt_vk_table[n].key == code) { key = qt_vk_table[n].vk; break; } } if (!key) return false; } if (mod) *mod_ = mod; if (key) *key_ = key; return true; } }; GlobalShortcutManager::KeyTrigger::Impl::Qt_VK_Keymap GlobalShortcutManager::KeyTrigger::Impl::qt_vk_table[] = { { Qt::Key_Escape, VK_ESCAPE }, { Qt::Key_Tab, VK_TAB }, { Qt::Key_Backtab, 0 }, { Qt::Key_Backspace, VK_BACK }, { Qt::Key_Return, VK_RETURN }, { Qt::Key_Enter, VK_RETURN }, { Qt::Key_Insert, VK_INSERT }, { Qt::Key_Delete, VK_DELETE }, { Qt::Key_Pause, VK_PAUSE }, { Qt::Key_Print, VK_PRINT }, { Qt::Key_SysReq, 0 }, { Qt::Key_Clear, VK_CLEAR }, { Qt::Key_Home, VK_HOME }, { Qt::Key_End, VK_END }, { Qt::Key_Left, VK_LEFT }, { Qt::Key_Up, VK_UP }, { Qt::Key_Right, VK_RIGHT }, { Qt::Key_Down, VK_DOWN }, { Qt::Key_PageUp, VK_PRIOR }, { Qt::Key_PageDown, VK_NEXT }, { Qt::Key_Shift, VK_SHIFT }, { Qt::Key_Control, VK_CONTROL }, { Qt::Key_Meta, VK_LWIN }, { Qt::Key_Alt, VK_MENU }, { Qt::Key_CapsLock, VK_CAPITAL }, { Qt::Key_NumLock, VK_NUMLOCK }, { Qt::Key_ScrollLock, VK_SCROLL }, { Qt::Key_F1, VK_F1 }, { Qt::Key_F2, VK_F2 }, { Qt::Key_F3, VK_F3 }, { Qt::Key_F4, VK_F4 }, { Qt::Key_F5, VK_F5 }, { Qt::Key_F6, VK_F6 }, { Qt::Key_F7, VK_F7 }, { Qt::Key_F8, VK_F8 }, { Qt::Key_F9, VK_F9 }, { Qt::Key_F10, VK_F10 }, { Qt::Key_F11, VK_F11 }, { Qt::Key_F12, VK_F12 }, { Qt::Key_F13, VK_F13 }, { Qt::Key_F14, VK_F14 }, { Qt::Key_F15, VK_F15 }, { Qt::Key_F16, VK_F16 }, { Qt::Key_F17, VK_F17 }, { Qt::Key_F18, VK_F18 }, { Qt::Key_F19, VK_F19 }, { Qt::Key_F20, VK_F20 }, { Qt::Key_F21, VK_F21 }, { Qt::Key_F22, VK_F22 }, { Qt::Key_F23, VK_F23 }, { Qt::Key_F24, VK_F24 }, { Qt::Key_F25, 0 }, { Qt::Key_F26, 0 }, { Qt::Key_F27, 0 }, { Qt::Key_F28, 0 }, { Qt::Key_F29, 0 }, { Qt::Key_F30, 0 }, { Qt::Key_F31, 0 }, { Qt::Key_F32, 0 }, { Qt::Key_F33, 0 }, { Qt::Key_F34, 0 }, { Qt::Key_F35, 0 }, { Qt::Key_Super_L, 0 }, { Qt::Key_Super_R, 0 }, { Qt::Key_Menu, 0 }, { Qt::Key_Hyper_L, 0 }, { Qt::Key_Hyper_R, 0 }, { Qt::Key_Help, 0 }, { Qt::Key_Direction_L, 0 }, { Qt::Key_Direction_R, 0 }, { Qt::Key_unknown, 0 }, }; int GlobalShortcutManager::KeyTrigger::Impl::nextId = 1; GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key) { d = new Impl(this, key); } GlobalShortcutManager::KeyTrigger::~KeyTrigger() { delete d; d = 0; } psi-0.14/src/libpsi/tools/atomicxmlfile/0000755000175000017500000000000011305557617016413 5ustar janjanpsi-0.14/src/libpsi/tools/atomicxmlfile/atomicxmlfile.h0000644000175000017500000000606011305557617021423 0ustar janjan/* * atomicxmlfile.h - atomic saving of QDomDocuments in files * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ATOMICXMLFILE_H #define ATOMICXMLFILE_H #include #include #include #include #include class AtomicXmlFileReader : public QXmlStreamReader { public: virtual ~AtomicXmlFileReader() {} virtual bool read(QIODevice* device) = 0; }; class AtomicXmlFileWriter : public QXmlStreamWriter { public: virtual ~AtomicXmlFileWriter() {} virtual bool write(QIODevice* device) = 0; }; class QDomDocument; class AtomicXmlFile { public: AtomicXmlFile(QString fileName); /** * Atomically save \a writer to specified name. Prior to saving, back up * of old config data is created, and only then data is saved. */ template bool saveDocument(T writer) const { if (!saveDocument(writer, tempFileName())) { qWarning("AtomicXmlFile::saveDocument(): Unable to save '%s'. Possibly drive is full.", qPrintable(tempFileName())); return false; } if (QFile::exists(backupFileName())) QFile::remove(backupFileName()); if (QFile::exists(fileName_)) { if (!QFile::rename(fileName_, backupFileName())) { qWarning("AtomicXmlFile::saveDocument(): Unable to rename '%s' to '%s'.", qPrintable(fileName_), qPrintable(backupFileName())); return false; } } if (!QFile::rename(tempFileName(), fileName_)) { qWarning("AtomicXmlFile::saveDocument(): Unable to rename '%s' to '%s'.", qPrintable(tempFileName()), qPrintable(fileName_)); return false; } return true; } /** * Tries to load \a reader from config file, or if that fails, from a back up. */ template bool loadDocument(T reader) const { Q_ASSERT(reader); foreach(QString fileName, loadCandidateList()) { if (loadDocument(reader, fileName)) { return true; } } return false; } static bool exists(QString fileName); private: QString fileName_; QString tempFileName() const; QString backupFileName() const; QStringList loadCandidateList() const; bool saveDocument(const QDomDocument& doc, QString fileName) const; bool loadDocument(QDomDocument* doc, QString fileName) const; bool saveDocument(AtomicXmlFileWriter* writer, QString fileName) const; bool loadDocument(AtomicXmlFileReader* reader, QString fileName) const; }; #endif psi-0.14/src/libpsi/tools/atomicxmlfile/atomicxmlfile.cpp0000644000175000017500000000633311305557617021761 0ustar janjan/* * atomicxmlfile.cpp - atomic saving of QDomDocuments in files * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "atomicxmlfile.h" #include #include #include /** * Creates new instance of AtomicXmlFile class that will be able to * atomically save config file, so if application is terminated while * saving config file, data is not lost. */ AtomicXmlFile::AtomicXmlFile(QString fileName) : fileName_(fileName) { } QStringList AtomicXmlFile::loadCandidateList() const { QStringList fileNames; fileNames << fileName_ << tempFileName() << backupFileName(); return fileNames; } /** * Returns name of the file the config is first written to. */ QString AtomicXmlFile::tempFileName() const { return fileName_ + ".temp"; } /** * Returns name of the back up file. */ QString AtomicXmlFile::backupFileName() const { return fileName_ + ".backup"; } bool AtomicXmlFile::saveDocument(const QDomDocument& doc, QString fileName) const { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { return false; } QTextStream text; text.setDevice(&file); text.setCodec("UTF-8"); text << doc.toString(); return file.error() == QFile::NoError; } bool AtomicXmlFile::loadDocument(QDomDocument* doc, QString fileName) const { Q_ASSERT(doc); QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { return false; } return doc->setContent(&file); } bool AtomicXmlFile::saveDocument(AtomicXmlFileWriter* writer, QString fileName) const { Q_ASSERT(writer); QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { return false; } if (!writer->write(&file)) { return false; } return file.error() == QFile::NoError; } bool AtomicXmlFile::loadDocument(AtomicXmlFileReader* reader, QString fileName) const { Q_ASSERT(reader); QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { return false; } if (!reader->read(&file)) { qWarning("Parse error in file %s at line %d, column %d:\n%s", qPrintable(fileName), (int)reader->lineNumber(), (int)reader->columnNumber(), qPrintable(reader->errorString())); return false; } return true; } /** * Check if an AtomicXmlFile exists. * returns true if any of the files loadDocument tries to read exists, * it *doesn't* check that there is at least one uncorupted file. */ bool AtomicXmlFile::exists(QString fileName) { AtomicXmlFile tmp(fileName); foreach(QString fileName, tmp.loadCandidateList()) { if (QFile::exists(fileName)) { return true; } } return false; } psi-0.14/src/libpsi/tools/atomicxmlfile/atomicxmlfile.pri0000644000175000017500000000016611305557617021767 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += \ $$PWD/atomicxmlfile.cpp HEADERS += \ $$PWD/atomicxmlfile.h psi-0.14/src/libpsi/tools/systemwatch/0000755000175000017500000000000011305557617016131 5ustar janjanpsi-0.14/src/libpsi/tools/systemwatch/systemwatch_mac.cpp0000644000175000017500000000530511305557617022033 0ustar janjan/* * systemwatch_mac.cpp - Detect changes in the system state (Mac OS X). * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include "systemwatch_mac.h" // ----------------------------------------------------------------------------- // Callbacks // ----------------------------------------------------------------------------- io_connect_t root_port; void sleepCallBack(void* systemWatch, io_service_t, natural_t messageType, void * messageArgument) { //printf("messageType %08lx, arg %08lx\n", // (long unsigned int)messageType, (long unsigned int)messageArgument); MacSystemWatch* macSystemWatch = static_cast(systemWatch); switch (messageType) { case kIOMessageSystemWillSleep: // Sleep macSystemWatch->emitSleep(); IOAllowPowerChange(root_port, (long)messageArgument); break; case kIOMessageCanSystemSleep: // Idle time sleep // TODO: Check if file transfers are running, and don't go to sleep // if there are. //IOCancelPowerChange(root_port, (long)messageArgument); macSystemWatch->emitIdleSleep(); IOAllowPowerChange(root_port, (long)messageArgument); break; case kIOMessageSystemHasPoweredOn: // Wakeup macSystemWatch->emitWakeup(); break; } } // ----------------------------------------------------------------------------- // MacSystemWatch // ----------------------------------------------------------------------------- MacSystemWatch::MacSystemWatch() { // Initialize sleep callback IONotificationPortRef notify; io_object_t anIterator; root_port = IORegisterForSystemPower(this, ¬ify, sleepCallBack, &anIterator); if (!root_port) { printf("IORegisterForSystemPower failed\n"); } else { CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notify), kCFRunLoopCommonModes); } } psi-0.14/src/libpsi/tools/systemwatch/systemwatch.pri0000644000175000017500000000055511305557617021225 0ustar janjanHEADERS += $$PWD/systemwatch.h SOURCES += $$PWD/systemwatch.cpp INCLUDEPATH += $$PWD DEPENDPATH += $$PWD unix:!mac { HEADERS += $$PWD/systemwatch_unix.h SOURCES += $$PWD/systemwatch_unix.cpp } win32: { HEADERS += $$PWD/systemwatch_win.h SOURCES += $$PWD/systemwatch_win.cpp } mac: { HEADERS += $$PWD/systemwatch_mac.h SOURCES += $$PWD/systemwatch_mac.cpp } psi-0.14/src/libpsi/tools/systemwatch/systemwatch_unix.h0000644000175000017500000000174511305557617021727 0ustar janjan/* * systemwatch_unix.h - Detect changes in the system state (Unix). * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SYSTEMWATCH_UNIX_H #define SYSTEMWATCH_UNIX_H #include "systemwatch.h" class UnixSystemWatch : public SystemWatch { public: UnixSystemWatch(); }; #endif psi-0.14/src/libpsi/tools/systemwatch/systemwatch.h0000644000175000017500000000213411305557617020655 0ustar janjan/* * systemwatch.h - Detect changes in the system state. * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SYSTEMWATCH_H #define SYSTEMWATCH_H #include class SystemWatch : public QObject { Q_OBJECT public: static SystemWatch* instance(); signals: void sleep(); void idleSleep(); void wakeup(); protected: SystemWatch(); private: static SystemWatch* instance_; }; #endif psi-0.14/src/libpsi/tools/systemwatch/systemwatch_win.cpp0000644000175000017500000000700011305557617022062 0ustar janjan/* * systemwatch_win.cpp - Detect changes in the system state (Windows). * Copyright (C) 2005, 2008 James Chaldecott, Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "systemwatch_win.h" #include #include // workaround for the very old MinGW version bundled with Qt #ifndef PBT_APMSUSPEND #include #endif /* Implementor notes: This class needs to get Windows messages. The easiest way is to get them from a top level QWidget instance. There was an attempt to use QApplication::winEventFilter(), but - as its name says - this is a filter, so all messages to all widgets go through it. So as a consequence, sleep() and wakeup() are emited many times during one event. Right now, there is a dummy window created just for SystemWatch. This may seem to be an unnecesary waste of resources, but the example above shows that too aggressive optimizations may hurt. A possible solution "in between" would be to catch events in already existing window (main window, probably) and pass them (by using ugly casting) directly to processWinEvent() But this would break the beauty of this tool. */ // ----------------------------------------------------------------------------- // WinSystemWatch // ----------------------------------------------------------------------------- class WinSystemWatch::MessageWindow : public QWidget { public: MessageWindow(WinSystemWatch *parent) : syswatch(parent) { create(); // really create the window to enable messages } bool winEvent(MSG *m, long* result) { if (syswatch->processWinEvent(m, result)) { return true; } else { return QWidget::winEvent(m, result); } } WinSystemWatch *syswatch; }; WinSystemWatch::WinSystemWatch() { d = new MessageWindow(this); } WinSystemWatch::~WinSystemWatch() { delete d; d = 0; } bool WinSystemWatch::processWinEvent(MSG *m, long* result) { if(WM_POWERBROADCAST == m->message) { switch (m->wParam) { case PBT_APMSUSPEND: emit sleep(); break; case PBT_APMRESUMESUSPEND: emit wakeup(); break; case PBT_APMRESUMECRITICAL: // The system previously went into SUSPEND state (suddenly) // without sending PBT_APMSUSPEND. Net connections are // probably invalid. Not sure what to do about this. // Maybe: emit sleep(); emit wakeup(); break; case PBT_APMQUERYSUSPEND: // TODO: Check if file transfers are running, and don't go // to sleep if there are. To refuse to suspend, we somehow // need to return BROADCAST_QUERY_DENY from the actual // windows procedure. break; } } else if (WM_QUERYENDSESSION == m->message) { // TODO : If we allow the user to cancel suspend if they // are doing a file transfer, we should probably also give // them the chance to cancel a shutdown or log-off } return false; // Let Qt handle the right return value. } psi-0.14/src/libpsi/tools/systemwatch/systemwatch_mac.h0000644000175000017500000000224111305557617021474 0ustar janjan/* * systemwatch_mac.h - Detect changes in the system state (Mac OS X). * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SYSTEMWATCH_MAC_H #define SYSTEMWATCH_MAC_H #include "systemwatch.h" class MacSystemWatch : public SystemWatch { public: MacSystemWatch(); // These shouldn't be called from outside, but i can't hide them atm. void emitSleep() { emit sleep(); } void emitIdleSleep() { emit idleSleep(); } void emitWakeup() { emit wakeup(); } }; #endif psi-0.14/src/libpsi/tools/systemwatch/systemwatch_win.h0000644000175000017500000000045611305557617021537 0ustar janjan#ifndef SYSTEMWATCH_WIN_H #define SYSTEMWATCH_WIN_H #include "systemwatch.h" #include class WinSystemWatch : public SystemWatch { public: WinSystemWatch(); ~WinSystemWatch(); private: class MessageWindow; MessageWindow *d; bool processWinEvent(MSG *m, long* result); }; #endif psi-0.14/src/libpsi/tools/systemwatch/systemwatch_unix.cpp0000644000175000017500000000160511305557617022255 0ustar janjan/* * systemwatch_unix.h - Detect changes in the system state (Unix). * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "systemwatch_unix.h" UnixSystemWatch::UnixSystemWatch() { } psi-0.14/src/libpsi/tools/systemwatch/systemwatch.cpp0000644000175000017500000000252311305557617021212 0ustar janjan/* * systemwatch.h - Detect changes in the system state. * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "systemwatch.h" #if defined(Q_OS_MAC) #include "systemwatch_mac.h" #elif defined(Q_OS_WIN32) #include "systemwatch_win.h" #else #include "systemwatch_unix.h" #endif #include SystemWatch::SystemWatch() : QObject(qApp) { } SystemWatch* SystemWatch::instance() { if (!instance_) { #if defined(Q_WS_MAC) instance_ = new MacSystemWatch(); #elif defined(Q_WS_WIN) instance_ = new WinSystemWatch(); #else instance_ = new UnixSystemWatch(); #endif } return instance_; } SystemWatch* SystemWatch::instance_ = 0; psi-0.14/src/libpsi/tools/simplecli/0000755000175000017500000000000011305557617015537 5ustar janjanpsi-0.14/src/libpsi/tools/simplecli/simplecli.cpp0000644000175000017500000001520611305557617020230 0ustar janjan/* * simplecli.cpp - Simple CommandLine Interface parser / manager * Copyright (C) 2009 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "simplecli.h" #include /** * \class SimpleCli * \brief Simple Commandline Interface parser. * * This class allows you to define Commandline Interface for your application * and then use this information to convert argv to a map of options and their values. * * Please note that support for short options (-x) is very limited * and provided only to support options like -h and -v. */ /** * \brief Define a switch (option that does not have a value) */ void SimpleCli::defineSwitch(const QString& name, const QString& help) { argdefs[name] = Arg(name, "", help, false); aliases[name] = name; } /** * \brief Define a parameter (option that requires a value) */ void SimpleCli::defineParam(const QString& name, const QString& valueHelp, const QString& help) { argdefs[name] = Arg(name, valueHelp, help, true); aliases[name] = name; } /** * \brief Add alias for already existing option. * \a alias will be mapped to \a originalName in parse() result. */ void SimpleCli::defineAlias(const QString& alias, const QString& originalName) { if (!argdefs.contains(originalName)) { qDebug("CLI: cannot add alias '%s' because name '%s' does not exist", qPrintable(alias), qPrintable(originalName)); return; } argdefs[originalName].aliases.append(alias); aliases[alias] = originalName; if (alias.length() == 1 && argdefs[originalName].shortName.isNull()) { argdefs[originalName].shortName = alias.at(0); } } /** * \brief Parse \a argv into a name,value map. * \param terminalArgs stop parsing when one of these options is found (it will be included in result) * \param safeArgs if not NULL, will be used to pass number of arguments before terminal argument (or argc if there was no terminal argument) * * Supported options syntax: --switch; --param=value; --param value; -switch; -param=value; -param value. * Additionally on Windows: /switch; /param:value; /param value. * * When creating the map, alias names are converted to original option names. * * Use \a terminalArgs if you want need to stop parsing after certain options for security reasons, etc. */ QMap SimpleCli::parse(int argc, char* argv[], const QStringList& terminalArgs, int* safeArgc) { #ifdef Q_WS_WIN const bool winmode = true; #else const bool winmode = false; #endif QMap map; int safe = 1; int n = 1; for (; n < argc; ++n) { QString str = QString::fromLocal8Bit(argv[n]); QString left, right; int sep = str.indexOf('='); if (sep == -1) { left = str; right = QString::null; } else { left = str.mid(0, sep); right = str.mid(sep + 1); } bool unnamedArgument = true; if (left.startsWith("--")) { left = left.mid(2); unnamedArgument = false; } else if (left.startsWith('-') || (left.startsWith('/') && winmode)) { left = left.mid(1); unnamedArgument = false; } QString name, value; if (unnamedArgument) { value = left; } else { name = left; value = right; if (aliases.contains(name)) { name = argdefs[aliases[name]].name; if (argdefs[name].needsValue && value.isNull() && n + 1 < argc) { value = QString::fromLocal8Bit(argv[++n]); } } } if (map.contains(name)) { qDebug("CLI: Ignoring next value ('%s') for '%s' arg.", qPrintable(value), qPrintable(name)); } else { map[name] = value; } if (terminalArgs.contains(name)) { break; } else { safe = n + 1; } } if (safeArgc) { *safeArgc = safe; } return map; } /** * \brief Produce options description, for use in --help. * \param textWidth wrap text when wider than \a textWidth */ QString SimpleCli::optionsHelp(int textWidth) { QString ret; int margin = 2; int longest = -1; bool foundShort = false; foreach (Arg arg, argdefs) { if (arg.needsValue) { longest = qMax(arg.name.length() + arg.valueHelp.length() + 1, longest); } else { longest = qMax(arg.name.length(), longest); } foundShort = foundShort || !arg.shortName.isNull(); } longest += 2; // 2 = length("--") int helpPadding = longest + 6; // 6 = 2 (left margin) + 2 (space before help) + 2 (next line indent) if (foundShort) { helpPadding += 4; // 4 = length("-x, ") } foreach (Arg arg, argdefs) { QString line; line.fill(' ', margin); if (foundShort) { if (arg.shortName.isNull()) { line += " "; } else { line += '-' + arg.shortName + ", "; } } QString longarg = "--" + arg.name; if (arg.needsValue) { longarg += '=' + arg.valueHelp; } line += longarg; line += QString().fill(' ', longest - longarg.length() + 2); // 2 (space before help) line += arg.help; ret += wrap(line, textWidth, helpPadding, 0); } return ret; } /** * \brief Wrap text for printing on console. * \param text text to be wrapped * \param width width of the text * \param margin left margin (filled with spaces) * \param firstMargin margin in first line * Note: This function is designed for text that do not contain tabs or line breaks. * Results may be not pretty if such \a text is passed. */ QString SimpleCli::wrap(QString text, int width, int margin, int firstMargin) { if (firstMargin < 0) { firstMargin = margin; } QString output; int prevBreak = -1; int currentMargin = firstMargin; int nextBreak; do { nextBreak = prevBreak + width + 1 - currentMargin; if (nextBreak < text.length()) { int lastSpace = text.lastIndexOf(' ', nextBreak); if (lastSpace > prevBreak) { nextBreak = lastSpace; } else { // will be a bit longer... nextBreak = text.indexOf(' ', nextBreak); if (nextBreak == -1) { nextBreak = text.length(); } } } else { nextBreak = text.length(); } output += QString().fill(' ', currentMargin); output += text.mid(prevBreak + 1, nextBreak - prevBreak - 1); output += '\n'; prevBreak = nextBreak; currentMargin = margin; } while (nextBreak < text.length()); return output; } psi-0.14/src/libpsi/tools/simplecli/simplecli.pri0000644000175000017500000000014611305557617020235 0ustar janjanHEADERS += $$PWD/simplecli.h SOURCES += $$PWD/simplecli.cpp INCLUDEPATH += $$PWD DEPENDPATH += $$PWD psi-0.14/src/libpsi/tools/simplecli/simplecli.h0000644000175000017500000000361411305557617017675 0ustar janjan/* * simplecli.h - Simple CommandLine Interface parser / manager * Copyright (C) 2009 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SIMPLECLI_H #define SIMPLECLI_H #include #include class SimpleCli : public QObject { public: void defineSwitch(const QString& name, const QString& help = QString()); void defineParam(const QString& name, const QString& valueHelp = QString("ARG"), const QString& help = QString()); void defineAlias(const QString& alias, const QString& originalName); QMap parse(int argc, char* argv[], const QStringList& terminalArgs = QStringList(), int* safeArgc = 0); QString optionsHelp(int textWidth); static QString wrap(QString text, int width, int margin = 0, int firstMargin = -1); private: struct Arg { QString name; QStringList aliases; QChar shortName; bool needsValue; QString help; QString valueHelp; Arg(const QString& argName, const QString& argValueHelp, const QString& argHelp, bool argNeedsValue) : name(argName), needsValue(argNeedsValue), help(argHelp), valueHelp(argValueHelp) {} Arg() : needsValue(false) {} // needed only by QMap }; QMap argdefs; QMap aliases; }; #endif psi-0.14/src/libpsi/tools/zip/0000755000175000017500000000000011305557617014360 5ustar janjanpsi-0.14/src/libpsi/tools/zip/zip.pri0000644000175000017500000000042111305557617015673 0ustar janjanHEADERS += \ $$PWD/zip.h SOURCES += \ $$PWD/zip.cpp \ $$PWD/minizip/unzip.c INCLUDEPATH += $$PWD DEPENDPATH += $$PWD win32: { INCLUDEPATH += $$PWD/minizip/win32 DEPENDPATH += $$PWD/minizip/win32 LIBS += $$PWD/minizip/win32/libz.a } mac: { QMAKE_LFLAGS += -lz } psi-0.14/src/libpsi/tools/zip/zip.cpp0000644000175000017500000000607011305557617015671 0ustar janjan/* * zip.cpp - zip/unzip files * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "minizip/unzip.h" #include "zip.h" class UnZipPrivate { public: UnZipPrivate() {} QString name; unzFile uf; QStringList listing; }; UnZip::UnZip(const QString &name) { d = new UnZipPrivate; d->uf = 0; d->name = name; } UnZip::~UnZip() { close(); delete d; } void UnZip::setName(const QString &name) { d->name = name; } const QString & UnZip::name() const { return d->name; } bool UnZip::open() { close(); d->uf = unzOpen(QFile::encodeName(d->name).data()); if(!d->uf) return false; return getList(); } void UnZip::close() { if(d->uf) { unzClose(d->uf); d->uf = 0; } d->listing.clear(); } const QStringList & UnZip::list() const { return d->listing; } bool UnZip::getList() { unz_global_info gi; int err = unzGetGlobalInfo(d->uf, &gi); if(err != UNZ_OK) return false; QStringList l; for(int n = 0; n < (int)gi.number_entry; ++n) { char filename_inzip[256]; unz_file_info file_info; int err = unzGetCurrentFileInfo(d->uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); if(err != UNZ_OK) return false; l += filename_inzip; if((n+1) < (int)gi.number_entry) { err = unzGoToNextFile(d->uf); if(err != UNZ_OK) return false; } } d->listing = l; return true; } bool UnZip::readFile(const QString &fname, QByteArray *buf, int max) { int err = unzLocateFile(d->uf, QFile::encodeName(fname).data(), 0); if(err != UNZ_OK) return false; char filename_inzip[256]; unz_file_info file_info; err = unzGetCurrentFileInfo(d->uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); if(err != UNZ_OK) return false; err = unzOpenCurrentFile(d->uf); if(err != UNZ_OK) return false; QByteArray a(0); QByteArray chunk; chunk.resize(16384); while(1) { err = unzReadCurrentFile(d->uf, chunk.data(), chunk.size()); if(err < 0) { unzCloseCurrentFile(d->uf); return false; } if(err == 0) break; int oldsize = a.size(); if(max > 0 && oldsize + err > max) err = max - oldsize; a.resize(oldsize + err); memcpy(a.data() + oldsize, chunk.data(), err); if(max > 0 && (int)a.size() >= max) break; } err = unzCloseCurrentFile(d->uf); if(err != UNZ_OK) return false; *buf = a; return true; } psi-0.14/src/libpsi/tools/zip/zip.h0000644000175000017500000000226311305557617015336 0ustar janjan/* * zip.h - zip/unzip files * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_ZIP_H #define CS_ZIP_H class QString; class QStringList; class UnZip { public: UnZip(const QString &fname=""); ~UnZip(); void setName(const QString &); const QString & name() const; bool open(); void close(); const QStringList & list() const; bool readFile(const QString &, QByteArray *, int max=0); private: class UnZipPrivate *d; bool getList(); }; #endif psi-0.14/src/libpsi/tools/zip/minizip/0000755000175000017500000000000011305557617016037 5ustar janjanpsi-0.14/src/libpsi/tools/zip/minizip/other/0000755000175000017500000000000011305557617017160 5ustar janjanpsi-0.14/src/libpsi/tools/zip/minizip/other/zip.def0000644000175000017500000000025711305557617020446 0ustar janjan zipOpen @80 zipOpenNewFileInZip @81 zipWriteInFileInZip @82 zipCloseFileInZip @83 zipClose @84 psi-0.14/src/libpsi/tools/zip/minizip/other/zip.h0000644000175000017500000001174211305557617020140 0ustar janjan/* zip.h -- IO for compress .zip files using zlib Version 0.15 alpha, Mar 19th, 1998, Copyright (C) 1998 Gilles Vollant This unzip package allow creates .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible. Encryption and multi volume ZipFile (span) are not supported. Old compressions used by old PKZip 1.x are not supported For uncompress .zip file, look at unzip.h THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE CAN CHANGE IN FUTURE VERSION !! I WAIT FEEDBACK at mail info@winimage.com Visit also http://www.winimage.com/zLibDll/zip.htm for evolution Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip PkWare has also a specification at : ftp://ftp.pkware.com/probdesc.zip */ #ifndef _zip_H #define _zip_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_INTERNALERROR (-104) /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); /* Create a zipfile. pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on an Unix computer "zlib/zlib111.zip". if the file pathname exist and append=1, the zip will be created at the end of the file. (useful if the file contain a self extractor code) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const voidp buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ #ifdef __cplusplus } #endif #endif /* _zip_H */ psi-0.14/src/libpsi/tools/zip/minizip/other/zip.c0000644000175000017500000005144711305557617020141 0ustar janjan/* zip.c -- IO on .zip files using zlib Version 0.15 beta, Mar 19th, 1998, Read zip.h for more info */ #include #include #include #include "zlib.h" #include "zip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x0) /* platform depedent */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (16384) #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif const char zip_copyright[] = " zip 0.15 Copyright 1998 Gilles Vollant "; #define SIZEDATA_INDATABLOCK (4096-(4*4)) #define LOCALHEADERMAGIC (0x04034b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignement */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal* first_block; linkedlist_datablock_internal* last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ uLong pos_local_header; /* offset of the local header of the file currenty writing */ char* central_header; /* central header data for the current file */ uLong size_centralheader; /* size of the central header for cur file */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currenty wr.*/ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; } curfile_info; typedef struct { FILE * filezip; linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile_info ci; /* info on the file curretly writing */ uLong begin_pos; /* position of the beginning of the zipfile */ uLong number_entry; } zip_internal; local linkedlist_datablock_internal* allocate_new_datablock() { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(ldi) linkedlist_datablock_internal* ldi; { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } local void init_linkedlist(ll) linkedlist_data* ll; { ll->first_block = ll->last_block = NULL; } local void free_linkedlist(ll) linkedlist_data* ll; { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } local int add_data_in_datablock(ll,buf,len) linkedlist_data* ll; const void* buf; uLong len; { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; if (ldi->avail_in_this_block==0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock ; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i=0;ifilled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this ; len -= copy_this; } return ZIP_OK; } local int write_datablock(fout,ll) FILE * fout; linkedlist_data* ll; { linkedlist_datablock_internal* ldi; ldi = ll->first_block; while (ldi!=NULL) { if (ldi->filled_in_this_block > 0) if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,1,fout)!=1) return ZIP_ERRNO; ldi = ldi->next_datablock; } return ZIP_OK; } /****************************************************************************/ /* =========================================================================== Outputs a long in LSB order to the given file nbByte == 1, 2 or 4 (byte, short or long) */ local int ziplocal_putValue OF((FILE *file, uLong x, int nbByte)); local int ziplocal_putValue (file, x, nbByte) FILE *file; uLong x; int nbByte; { unsigned char buf[4]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (fwrite(buf,nbByte,1,file)!=1) return ZIP_ERRNO; else return ZIP_OK; } local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); local void ziplocal_putValue_inmemory (dest, x, nbByte) void* dest; uLong x; int nbByte; { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } } /****************************************************************************/ local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) tm_zip* ptm; uLong dosDate; { uLong year = (uLong)ptm->tm_year; if (year>1980) year-=1980; else if (year>80) year-=80; return (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ extern zipFile ZEXPORT zipOpen (pathname, append) const char *pathname; int append; { zip_internal ziinit; zip_internal* zi; ziinit.filezip = fopen(pathname,(append == 0) ? "wb" : "ab"); if (ziinit.filezip == NULL) return NULL; ziinit.begin_pos = ftell(ziinit.filezip); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; init_linkedlist(&(ziinit.central_dir)); zi = (zip_internal*)ALLOC(sizeof(zip_internal)); if (zi==NULL) { fclose(ziinit.filezip); return NULL; } *zi = ziinit; return (zipFile)zi; } extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level) zipFile file; const char* filename; const zip_fileinfo* zipfi; const void* extrafield_local; uInt size_extrafield_local; const void* extrafield_global; uInt size_extrafield_global; const char* comment; int method; int level; { zip_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; } if (filename==NULL) filename="-"; if (comment==NULL) size_comment = 0; else size_comment = strlen(comment); size_filename = strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); } zi->ci.flag = 0; if ((level==8) || (level==9)) zi->ci.flag |= 2; if ((level==2)) zi->ci.flag |= 4; if ((level==1)) zi->ci.flag |= 6; zi->ci.crc32 = 0; zi->ci.method = method; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.pos_local_header = ftell(zi->filezip); zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); /* version info */ ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ if (zipfi==NULL) ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); else ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); if (zipfi==NULL) ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); else ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header,4); for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = *(((const char*)extrafield_global)+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ size_extrafield_global+i) = *(filename+i); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; /* write the local header */ err = ziplocal_putValue(zi->filezip,(uLong)LOCALHEADERMAGIC,4); if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)20,2);/* version needed to extract */ if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.flag,2); if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.method,2); if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.dosDate,4); if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* crc 32, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* compressed size, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* uncompressed size, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)size_filename,2); if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)size_extrafield_local,2); if ((err==ZIP_OK) && (size_filename>0)) if (fwrite(filename,(uInt)size_filename,1,zi->filezip)!=1) err = ZIP_ERRNO; if ((err==ZIP_OK) && (size_extrafield_local>0)) if (fwrite(extrafield_local,(uInt)size_extrafield_local,1,zi->filezip) !=1) err = ZIP_ERRNO; zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED)) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)0; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); if (err==Z_OK) zi->ci.stream_initialised = 1; } if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipWriteInFileInZip (file, buf, len) zipFile file; const voidp buf; unsigned len; { zip_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.next_in = buf; zi->ci.stream.avail_in = len; zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip) !=1) err = ZIP_ERRNO; zi->ci.pos_in_buffered_data = 0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if (zi->ci.method == Z_DEFLATED) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i=0;ici.stream.next_out)+i) = *(((const char*)zi->ci.stream.next_in)+i); { zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out-= copy_this; zi->ci.stream.next_in+= copy_this; zi->ci.stream.next_out+= copy_this; zi->ci.stream.total_in+= copy_this; zi->ci.stream.total_out+= copy_this; zi->ci.pos_in_buffered_data += copy_this; } } } return 0; } extern int ZEXPORT zipCloseFileInZip (file) zipFile file; { zip_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if (zi->ci.method == Z_DEFLATED) while (err==ZIP_OK) { uLong uTotalOutBefore; if (zi->ci.stream.avail_out == 0) { if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip) !=1) err = ZIP_ERRNO; zi->ci.pos_in_buffered_data = 0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } if (err==Z_STREAM_END) err=ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip) !=1) err = ZIP_ERRNO; if ((zi->ci.method == Z_DEFLATED) && (err==ZIP_OK)) { err=deflateEnd(&zi->ci.stream); zi->ci.stream_initialised = 0; } ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)zi->ci.crc32,4); /*crc*/ ziplocal_putValue_inmemory(zi->ci.central_header+20, (uLong)zi->ci.stream.total_out,4); /*compr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+24, (uLong)zi->ci.stream.total_in,4); /*uncompr size*/ if (err==ZIP_OK) err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err==ZIP_OK) { long cur_pos_inzip = ftell(zi->filezip); if (fseek(zi->filezip, zi->ci.pos_local_header + 14,SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.crc32,4); /* crc 32, unknown */ if (err==ZIP_OK) /* compressed size, unknown */ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_out,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_in,4); if (fseek(zi->filezip, cur_pos_inzip,SEEK_SET)!=0) err = ZIP_ERRNO; } zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipClose (file, global_comment) zipFile file; const char* global_comment; { zip_internal* zi; int err = 0; uLong size_centraldir = 0; uLong centraldir_pos_inzip ; uInt size_global_comment; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); } if (global_comment==NULL) size_global_comment = 0; else size_global_comment = strlen(global_comment); centraldir_pos_inzip = ftell(zi->filezip); if (err==ZIP_OK) { linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; while (ldi!=NULL) { if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block, 1,zi->filezip) !=1 ) err = ZIP_ERRNO; size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_datablock(zi->central_dir.first_block); if (err==ZIP_OK) /* Magic End */ err = ziplocal_putValue(zi->filezip,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = ziplocal_putValue(zi->filezip,(uLong)0,2); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = ziplocal_putValue(zi->filezip,(uLong)0,2); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2); if (err==ZIP_OK) /* total number of entries in the central dir */ err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2); if (err==ZIP_OK) /* size of the central directory */ err = ziplocal_putValue(zi->filezip,(uLong)size_centraldir,4); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ err = ziplocal_putValue(zi->filezip,(uLong)centraldir_pos_inzip ,4); if (err==ZIP_OK) /* zipfile comment length */ err = ziplocal_putValue(zi->filezip,(uLong)size_global_comment,2); if ((err==ZIP_OK) && (size_global_comment>0)) if (fwrite(global_comment,(uInt)size_global_comment,1,zi->filezip) !=1 ) err = ZIP_ERRNO; fclose(zi->filezip); TRYFREE(zi); return err; } psi-0.14/src/libpsi/tools/zip/minizip/unzip.h0000644000175000017500000002331211305557617017356 0ustar janjan/* unzip.h -- IO for uncompress .zip files using zlib Version 0.15 beta, Mar 19th, 1998, Copyright (C) 1998 Gilles Vollant This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible. Encryption and multi volume ZipFile (span) are not supported. Old compressions used by old PKZip 1.x are not supported THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE CAN CHANGE IN FUTURE VERSION !! I WAIT FEEDBACK at mail info@winimage.com Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip PkWare has also a specification at : ftp://ftp.pkware.com/probdesc.zip */ #ifndef _unz_H #define _unz_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((const char *path)); /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer "zlib/zlib111.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ #ifdef __cplusplus } #endif #endif /* _unz_H */ psi-0.14/src/libpsi/tools/zip/minizip/unzip.c0000644000175000017500000010340611305557617017354 0ustar janjan/* unzip.c -- IO on .zip files using zlib Version 0.15 beta, Mar 19th, 1998, Read unzip.h for more info */ #include #include #include #include "zlib.h" #include "unzip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ !defined(CASESENSITIVITYDEFAULT_NO) #define CASESENSITIVITYDEFAULT_NO #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif const char unz_copyright[] = " unzip 0.15 Copyright 1998 Gilles Vollant "; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info_internal_s { uLong offset_curfile;/* relative offset of local header 4 bytes */ } unz_file_info_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ uLong offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ uLong pos_local_extrafield; /* position in the local extra field in read*/ uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ uLong rest_read_compressed; /* number of byte to be decompressed */ uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ FILE* file; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ } file_in_zip_read_info_s; /* unz_s contain internal information about the zipfile */ typedef struct { FILE* file; /* io structore of the zipfile */ unz_global_info gi; /* public global information */ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ uLong num_file; /* number of the current file in the zipfile*/ uLong pos_in_central_dir; /* pos of the current file in the central dir*/ uLong current_file_ok; /* flag about the usability of the current file*/ uLong central_pos; /* position of the beginning of the central dir*/ uLong size_central_dir; /* size of the central directory */ uLong offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info cur_file_info; /* public info about the current file in zip*/ unz_file_info_internal cur_file_info_internal; /* private info about it*/ file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ } unz_s; /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int unzlocal_getByte(fin,pi) FILE *fin; int *pi; { unsigned char c; int err = fread(&c, 1, 1, fin); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ferror(fin)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unzlocal_getShort (fin,pX) FILE* fin; uLong *pX; { uLong x ; int i; int err; err = unzlocal_getByte(fin,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unzlocal_getLong (fin,pX) FILE* fin; uLong *pX; { uLong x ; int i; int err; err = unzlocal_getByte(fin,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<16; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal (fileName1,fileName2) const char* fileName1; const char* fileName2; { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) const char* fileName1; const char* fileName2; int iCaseSensitivity; { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #define BUFREADCOMMENT (0x400) /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local uLong unzlocal_SearchCentralDir(fin) FILE *fin; { unsigned char* buf; uLong uSizeFile; uLong uBackRead; uLong uMaxBack=0xffff; /* maximum size of global comment */ uLong uPosFound=0; if (fseek(fin,0,SEEK_END) != 0) return 0; uSizeFile = ftell( fin ); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (fseek(fin,uReadPos,SEEK_SET)!=0) break; if (fread(buf,(uInt)uReadSize,1,fin)!=1) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer "zlib/zlib109.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ extern unzFile ZEXPORT unzOpen (path) const char *path; { unz_s us; unz_s *s; uLong central_pos,uL; FILE * fin ; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ uLong number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; fin=fopen(path,"rb"); if (fin==NULL) return NULL; central_pos = unzlocal_SearchCentralDir(fin); if (central_pos==0) err=UNZ_ERRNO; if (fseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir */ if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* zipfile comment length */ if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); fclose(s->file); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) unzFile file; unz_global_info *pglobal_info; { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; *pglobal_info=s->gi; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) uLong ulDosDate; tm_unz* ptm; { uLong uDate; uDate = (uLong)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unzlocal_GetCurrentFileInfoInternal (file, pfile_info, pfile_info_internal, szFileName, fileNameBufferSize, extraField, extraFieldBufferSize, szComment, commentBufferSize) unzFile file; unz_file_info *pfile_info; unz_file_info_internal *pfile_info_internal; char *szFileName; uLong fileNameBufferSize; void *extraField; uLong extraFieldBufferSize; char *szComment; uLong commentBufferSize; { unz_s* s; unz_file_info file_info; unz_file_info_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; lSeek -= uSizeRead; } if ((err==UNZ_OK) && (extraField!=NULL)) { uLong uSizeRead ; if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; lSeek += file_info.size_file_extra - uSizeRead; } else lSeek+=file_info.size_file_extra; if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; lSeek+=file_info.size_file_comment - uSizeRead; } else lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo (file, pfile_info, szFileName, fileNameBufferSize, extraField, extraFieldBufferSize, szComment, commentBufferSize) unzFile file; unz_file_info *pfile_info; char *szFileName; uLong fileNameBufferSize; void *extraField; uLong extraFieldBufferSize; char *szComment; uLong commentBufferSize; { return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (file) unzFile file; { int err=UNZ_OK; unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (file) unzFile file; { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzipStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) unzFile file; const char *szFileName; int iCaseSensitivity; { unz_s* s; int err; uLong num_fileSaved; uLong pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; unzGetCurrentFileInfo(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; return err; } /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, poffset_local_extrafield, psize_local_extrafield) unz_s* s; uInt* piSizeVar; uLong *poffset_local_extrafield; uInt *psize_local_extrafield; { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (fseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile (file) unzFile file; { int err=UNZ_OK; int Store; uInt iSizeVar; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uLong offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip_read_info_s*) ALLOC(sizeof(file_in_zip_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; Store = s->cur_file_info.compression_method==0; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->file=s->file; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if (!Store) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=1; /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; return UNZ_OK; } /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile (file, buf, len) unzFile file; voidp buf; unsigned len; { int err=UNZ_OK; uInt iRead = 0; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if (len>pfile_in_zip_read_info->rest_read_uncompressed) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (fseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if (pfile_in_zip_read_info->compression_method==0) { uInt uDoCopy,i ; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else { uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (file) unzFile file; { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (file) unzFile file; { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) unzFile file; voidp buf; unsigned len; { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uInt read_now; uLong size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (fseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) return UNZ_ERRNO; if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzipOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (file) unzFile file; { int err=UNZ_OK; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) unzFile file; char *szComment; uLong uSizeBuf; { //int err=UNZ_OK; unz_s* s; uLong uReadThis ; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } psi-0.14/src/libpsi/tools/zip/minizip/zlibvc.def0000644000175000017500000000455011305557617020014 0ustar janjanLIBRARY "zlib" DESCRIPTION '"""zlib data compression library"""' VERSION 1.11 HEAPSIZE 1048576,8192 EXPORTS adler32 @1 compress @2 crc32 @3 deflate @4 deflateCopy @5 deflateEnd @6 deflateInit2_ @7 deflateInit_ @8 deflateParams @9 deflateReset @10 deflateSetDictionary @11 gzclose @12 gzdopen @13 gzerror @14 gzflush @15 gzopen @16 gzread @17 gzwrite @18 inflate @19 inflateEnd @20 inflateInit2_ @21 inflateInit_ @22 inflateReset @23 inflateSetDictionary @24 inflateSync @25 uncompress @26 zlibVersion @27 gzprintf @28 gzputc @29 gzgetc @30 gzseek @31 gzrewind @32 gztell @33 gzeof @34 gzsetparams @35 zError @36 inflateSyncPoint @37 get_crc_table @38 compress2 @39 gzputs @40 gzgets @41 unzOpen @61 unzClose @62 unzGetGlobalInfo @63 unzGetCurrentFileInfo @64 unzGoToFirstFile @65 unzGoToNextFile @66 unzOpenCurrentFile @67 unzReadCurrentFile @68 unztell @70 unzeof @71 unzCloseCurrentFile @72 unzGetGlobalComment @73 unzStringFileNameCompare @74 unzLocateFile @75 unzGetLocalExtrafield @76 zipOpen @80 zipOpenNewFileInZip @81 zipWriteInFileInZip @82 zipCloseFileInZip @83 zipClose @84 psi-0.14/src/libpsi/tools/zip/minizip/zlibvc.dsp0000644000175000017500000004021611305557617020043 0ustar janjan# Microsoft Developer Studio Project File - Name="zlibvc" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 5.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 # TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602 CFG=zlibvc - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "zlibvc.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "zlibvc.mak" CFG="zlibvc - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "zlibvc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "zlibvc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "zlibvc - Win32 ReleaseAxp" (based on\ "Win32 (ALPHA) Dynamic-Link Library") !MESSAGE "zlibvc - Win32 ReleaseWithoutAsm" (based on\ "Win32 (x86) Dynamic-Link Library") !MESSAGE "zlibvc - Win32 ReleaseWithoutCrtdll" (based on\ "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "zlibvc - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir ".\Release" # PROP BASE Intermediate_Dir ".\Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\Release" # PROP Intermediate_Dir ".\Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" CPP=cl.exe # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c # SUBTRACT CPP /YX MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 RSC=rc.exe # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 # ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir ".\Debug" # PROP BASE Intermediate_Dir ".\Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\Debug" # PROP Intermediate_Dir ".\Debug" # PROP Target_Dir "" CPP=cl.exe # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c # ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /FD /c # SUBTRACT CPP /YX MTL=midl.exe # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 RSC=rc.exe # ADD BASE RSC /l 0x40c /d "_DEBUG" # ADD RSC /l 0x40c /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\zlib.dll" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "zlibvc__" # PROP BASE Intermediate_Dir "zlibvc__" # PROP BASE Ignore_Export_Lib 0 # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "zlibvc__" # PROP Intermediate_Dir "zlibvc__" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 CPP=cl.exe # ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c # ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c # SUBTRACT CPP /YX RSC=rc.exe # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:".\Release\zlib.dll" # SUBTRACT BASE LINK32 /pdb:none # ADD LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:"zlibvc__\zlib.dll" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "zlibvc_0" # PROP BASE Intermediate_Dir "zlibvc_0" # PROP BASE Ignore_Export_Lib 0 # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "zlibvc_0" # PROP Intermediate_Dir "zlibvc_0" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" CPP=cl.exe # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c # SUBTRACT CPP /YX MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 RSC=rc.exe # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll" # SUBTRACT BASE LINK32 /pdb:none # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_0\zlib.dll" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "zlibvc_1" # PROP BASE Intermediate_Dir "zlibvc_1" # PROP BASE Ignore_Export_Lib 0 # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "zlibvc_1" # PROP Intermediate_Dir "zlibvc_1" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" CPP=cl.exe # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c # SUBTRACT CPP /YX MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 RSC=rc.exe # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll" # SUBTRACT BASE LINK32 /pdb:none # ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_1\zlib.dll" # SUBTRACT LINK32 /pdb:none !ENDIF # Begin Target # Name "zlibvc - Win32 Release" # Name "zlibvc - Win32 Debug" # Name "zlibvc - Win32 ReleaseAxp" # Name "zlibvc - Win32 ReleaseWithoutAsm" # Name "zlibvc - Win32 ReleaseWithoutCrtdll" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" # Begin Source File SOURCE=.\adler32.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_ADLER=\ ".\zconf.h"\ ".\zlib.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\compress.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_COMPR=\ ".\zconf.h"\ ".\zlib.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\crc32.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_CRC32=\ ".\zconf.h"\ ".\zlib.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\deflate.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_DEFLA=\ ".\deflate.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\gvmat32c.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\gzio.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_GZIO_=\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\infblock.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_INFBL=\ ".\infblock.h"\ ".\infcodes.h"\ ".\inftrees.h"\ ".\infutil.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\infcodes.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_INFCO=\ ".\infblock.h"\ ".\infcodes.h"\ ".\inffast.h"\ ".\inftrees.h"\ ".\infutil.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\inffast.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_INFFA=\ ".\infblock.h"\ ".\infcodes.h"\ ".\inffast.h"\ ".\inftrees.h"\ ".\infutil.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\inflate.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_INFLA=\ ".\infblock.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\inftrees.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_INFTR=\ ".\inftrees.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\infutil.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_INFUT=\ ".\infblock.h"\ ".\infcodes.h"\ ".\inftrees.h"\ ".\infutil.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\trees.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_TREES=\ ".\deflate.h"\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\uncompr.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_UNCOM=\ ".\zconf.h"\ ".\zlib.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\unzip.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\zip.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # Begin Source File SOURCE=.\zlib.rc # End Source File # Begin Source File SOURCE=.\zlibvc.def # End Source File # Begin Source File SOURCE=.\zutil.c !IF "$(CFG)" == "zlibvc - Win32 Release" !ELSEIF "$(CFG)" == "zlibvc - Win32 Debug" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp" DEP_CPP_ZUTIL=\ ".\zconf.h"\ ".\zlib.h"\ ".\zutil.h"\ !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm" !ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll" !ENDIF # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" # Begin Source File SOURCE=.\deflate.h # End Source File # Begin Source File SOURCE=.\infblock.h # End Source File # Begin Source File SOURCE=.\infcodes.h # End Source File # Begin Source File SOURCE=.\inffast.h # End Source File # Begin Source File SOURCE=.\inftrees.h # End Source File # Begin Source File SOURCE=.\infutil.h # End Source File # Begin Source File SOURCE=.\zconf.h # End Source File # Begin Source File SOURCE=.\zlib.h # End Source File # Begin Source File SOURCE=.\zutil.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" # End Group # End Target # End Project psi-0.14/src/libpsi/tools/zip/minizip/zlibvc.dsw0000644000175000017500000000125511305557617020052 0ustar janjanMicrosoft Developer Studio Workspace File, Format Version 5.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "zlibstat"=.\zlibstat.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "zlibvc"=.\zlibvc.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### psi-0.14/src/libpsi/tools/zip/minizip/readme.txt0000644000175000017500000000253711305557617020044 0ustar janjan UnZip 0.15 additionnal library This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g, WinZip, InfoZip tools and compatible. Multi volume ZipFile (span) are not supported, and old compression used by old PKZip 1.x are not supported. See probdesc.zip from PKWare for specification of .ZIP format. What is Unzip The Zlib library support the deflate compression and the creation of gzip (.gz) file. Zlib is free and small. The .Zip format, which can contain several compressed files (.gz can containt only one file) is a very popular format. This is why I've written a package for reading file compressed in Zipfile. Using Unzip package You need source of Zlib (get zlib111.zip and read zlib.h). Get unzlb015.zip and read unzip.h (whith documentation of unzip functions) The Unzip package is only two file : unzip.h and unzip.c. But it use the Zlib files. unztst.c is a simple sample program, which list file in a zipfile and display README.TXT or FILE_ID.DIZ (if these files are found). miniunz.c is a mini unzip program. I'm also currenlyt writing a zipping portion (zip.h, zip.c and test with minizip.c) Please email me for feedback. I hope my source is compatible with Unix system, but I need your help for be sure Latest revision : Mar 04th, 1998 Check http://www.winimage.com/zLibDll/unzip.html for up to date info. psi-0.14/src/libpsi/tools/zip/minizip/miniunz.c0000644000175000017500000002572511305557617017707 0ustar janjan#include #include #include #include #include #include #ifdef unix # include # include #else # include # include #endif #include "unzip.h" #define CASESENSITIVITY (0) #define WRITEBUFFERSIZE (8192) /* mini unzip, demo of unzip package usage : Usage : miniunz [-exvlo] file.zip [file_to_extract] list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT if it exists */ /* change_file_date : change the date/time of a file filename : the filename of the file where date/time must be modified dosdate : the new date at the MSDos format (4 bytes) tmu_date : the SAME new date at the tm_unz format */ void change_file_date(filename,dosdate,tmu_date) const char *filename; uLong dosdate; tm_unz tmu_date; { #ifdef WIN32 HANDLE hFile; FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE, 0,NULL,OPEN_EXISTING,0,NULL); GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); LocalFileTimeToFileTime(&ftLocal,&ftm); SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); CloseHandle(hFile); #else #ifdef unix struct utimbuf ut; struct tm newdate; newdate.tm_sec = tmu_date.tm_sec; newdate.tm_min=tmu_date.tm_min; newdate.tm_hour=tmu_date.tm_hour; newdate.tm_mday=tmu_date.tm_mday; newdate.tm_mon=tmu_date.tm_mon; if (tmu_date.tm_year > 1900) newdate.tm_year=tmu_date.tm_year - 1900; else newdate.tm_year=tmu_date.tm_year ; newdate.tm_isdst=-1; ut.actime=ut.modtime=mktime(&newdate); utime(filename,&ut); #endif #endif } /* mymkdir and change_file_date are not 100 % portable As I don't know well Unix, I wait feedback for the unix portion */ int mymkdir(dirname) const char* dirname; { int ret=0; #ifdef WIN32 ret = mkdir(dirname); #else #ifdef unix ret = mkdir (dirname,0775); #endif #endif return ret; } int makedir (newdir) char *newdir; { char *buffer ; char *p; int len = strlen(newdir); if (len <= 0) return 0; buffer = (char*)malloc(len+1); strcpy(buffer,newdir); if (buffer[len-1] == '/') { buffer[len-1] = '\0'; } if (mymkdir(buffer) == 0) { free(buffer); return 1; } p = buffer+1; while (1) { char hold; while(*p && *p != '\\' && *p != '/') p++; hold = *p; *p = 0; if ((mymkdir(buffer) == -1) && (errno == ENOENT)) { printf("couldn't create directory %s\n",buffer); free(buffer); return 0; } if (hold == 0) break; *p++ = hold; } free(buffer); return 1; } void do_banner() { printf("MiniUnz 0.15, demo of zLib + Unz package written by Gilles Vollant\n"); printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n"); } void do_help() { printf("Usage : miniunz [-exvlo] file.zip [file_to_extract]\n\n") ; } int do_list(uf) unzFile uf; { uLong i; unz_global_info gi; int err; err = unzGetGlobalInfo (uf,&gi); if (err!=UNZ_OK) printf("error %d with zipfile in unzGetGlobalInfo \n",err); printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); for (i=0;i0) ratio = (file_info.compressed_size*100)/file_info.uncompressed_size; if (file_info.compression_method==0) string_method="Stored"; else if (file_info.compression_method==Z_DEFLATED) { uInt iLevel=(uInt)((file_info.flag & 0x6)/2); if (iLevel==0) string_method="Defl:N"; else if (iLevel==1) string_method="Defl:X"; else if ((iLevel==2) || (iLevel==3)) string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ } else string_method="Unkn. "; printf("%7lu %6s %7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", file_info.uncompressed_size,string_method,file_info.compressed_size, ratio, (uLong)file_info.tmu_date.tm_mon + 1, (uLong)file_info.tmu_date.tm_mday, (uLong)file_info.tmu_date.tm_year % 100, (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, (uLong)file_info.crc,filename_inzip); if ((i+1)='a') && (rep<='z')) rep -= 0x20; } while ((rep!='Y') && (rep!='N') && (rep!='A')); } if (rep == 'N') skip = 1; if (rep == 'A') *popt_overwrite=1; } if ((skip==0) && (err==UNZ_OK)) { fout=fopen(write_filename,"wb"); /* some zipfile don't contain directory alone before file */ if ((fout==NULL) && ((*popt_extract_without_path)==0) && (filename_withoutpath!=(char*)filename_inzip)) { char c=*(filename_withoutpath-1); *(filename_withoutpath-1)='\0'; makedir(write_filename); *(filename_withoutpath-1)=c; fout=fopen(write_filename,"wb"); } if (fout==NULL) { printf("error opening %s\n",write_filename); } } if (fout!=NULL) { printf(" extracting: %s\n",write_filename); do { err = unzReadCurrentFile(uf,buf,size_buf); if (err<0) { printf("error %d with zipfile in unzReadCurrentFile\n",err); break; } if (err>0) if (fwrite(buf,err,1,fout)!=1) { printf("error in writing extracted file\n"); err=UNZ_ERRNO; break; } } while (err>0); fclose(fout); if (err==0) change_file_date(write_filename,file_info.dosDate, file_info.tmu_date); } if (err==UNZ_OK) { err = unzCloseCurrentFile (uf); if (err!=UNZ_OK) { printf("error %d with zipfile in unzCloseCurrentFile\n",err); } } else unzCloseCurrentFile(uf); /* don't lose the error */ } free(buf); return err; } int do_extract(uf,opt_extract_without_path,opt_overwrite) unzFile uf; int opt_extract_without_path; int opt_overwrite; { uLong i; unz_global_info gi; int err; FILE* fout=NULL; err = unzGetGlobalInfo (uf,&gi); if (err!=UNZ_OK) printf("error %d with zipfile in unzGetGlobalInfo \n",err); for (i=0;i # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR _cdecl _export # endif # endif # if defined (__BORLANDC__) # if (__BORLANDC__ >= 0x0500) && defined (WIN32) # include # define ZEXPORT __declspec(dllexport) WINAPI # define ZEXPORTRVA __declspec(dllexport) WINAPIV # else # if defined (_Windows) && defined (__DLL__) # define ZEXPORT _export # define ZEXPORTVA _export # endif # endif # endif #endif #if defined (__BEOS__) # if defined (ZLIB_DLL) # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef FAR # define FAR #endif #if !defined(MACOS) && !defined(TARGET_OS_MAC) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #ifdef HAVE_UNISTD_H # include /* for off_t */ # include /* for SEEK_* and off_t */ # define z_off_t off_t #endif #ifndef SEEK_SET # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) # pragma map(deflateInit_,"DEIN") # pragma map(deflateInit2_,"DEIN2") # pragma map(deflateEnd,"DEEND") # pragma map(inflateInit_,"ININ") # pragma map(inflateInit2_,"ININ2") # pragma map(inflateEnd,"INEND") # pragma map(inflateSync,"INSY") # pragma map(inflateSetDictionary,"INSEDI") # pragma map(inflate_blocks,"INBL") # pragma map(inflate_blocks_new,"INBLNE") # pragma map(inflate_blocks_free,"INBLFR") # pragma map(inflate_blocks_reset,"INBLRE") # pragma map(inflate_codes_free,"INCOFR") # pragma map(inflate_codes,"INCO") # pragma map(inflate_fast,"INFA") # pragma map(inflate_flush,"INFLU") # pragma map(inflate_mask,"INMA") # pragma map(inflate_set_dictionary,"INSEDI2") # pragma map(inflate_copyright,"INCOPY") # pragma map(inflate_trees_bits,"INTRBI") # pragma map(inflate_trees_dynamic,"INTRDY") # pragma map(inflate_trees_fixed,"INTRFI") # pragma map(inflate_trees_free,"INTRFR") #endif #endif /* _ZCONF_H */ psi-0.14/src/libpsi/tools/zip/minizip/win32/zlib.h0000644000175000017500000011770411305557617020124 0ustar janjan/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.1.4, March 11th, 2002 Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ #ifndef _ZLIB_H #define _ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.1.4" /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough (for example if an input file is mmap'ed), or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: ascii or binary */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 /* Allowed flush values; see deflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative * values are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_ASCII 1 #define Z_UNKNOWN 2 /* Possible values of the data_type field */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade the compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least 0.1% larger than avail_in plus 12 bytes. If deflate does not return Z_STREAM_END, then it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update data_type if it can make a good guess about the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from reading the zlib header if present: this will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unchanged.) */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may some introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much output as possible to the output buffer. The flushing behavior of inflate is not specified for values of the flush parameter other than Z_SYNC_FLUSH and Z_FINISH, but the current implementation actually flushes as much output as possible anyway. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all the uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH is never required, but can be used to inform inflate that a faster routine may be used for the single inflate() call. If a preset dictionary is needed at this point (see inflateSetDictionary below), inflate sets strm-adler to the adler32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the adler32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then call inflateSync to look for a good compression block. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no string match). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid method). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. This function must be called immediately after deflateInit, deflateInit2 or deflateReset, before any call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size in deflate or deflate2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. Upon return of this function, strm->adler is set to the Adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent (for example if deflate has already been called for this stream or if the compression method is bsort). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative memLevel). msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from reading the zlib header if present: this will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unchanged.) */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler32 value returned by this call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). */ /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can easily be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. This function can be used to compress a whole file at once if the input file is mmap'ed. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. This function can be used to decompress a whole file at once if the input file is mmap'ed. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted. */ typedef voidp gzFile; ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); /* Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman only compression as in "wb1h". (See the description of deflateInit2 for more information about the strategy parameter.) gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. gzopen returns NULL if the file could not be opened or if there was insufficient memory to allocate the (de)compression state; errno can be checked to distinguish the two cases (if errno is zero, the zlib error is Z_MEM_ERROR). */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen() associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (in the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd), mode) closes the file descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). gzdopen returns NULL if there was insufficient memory to allocate the (de)compression state. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file was not in gzip format, gzread copies the given number of bytes into the buffer. gzread returns the number of uncompressed bytes actually read (0 for end of file, -1 for error). */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes actually written (0 in case of error). */ ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); /* Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written (0 in case of error). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. The string is then terminated with a null character. gzgets returns buf, or Z_NULL in case of error. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush returns Z_OK if the flush parameter is Z_FINISH and all output could be flushed. gzflush should be called only when strictly necessary because it can degrade compression. */ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); /* Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); /* Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream. gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns 1 when EOF has previously been detected reading the given input stream, otherwise zero. */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates all the (de)compression state. The return value is the zlib error number (see function gzerror below). */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running crc with the bytes buf[0..len-1] and return the updated crc. If buf is NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; /* hack for buggy compilers */ #endif ZEXTERN const char * ZEXPORT zError OF((int err)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); #ifdef __cplusplus } #endif #endif /* _ZLIB_H */ psi-0.14/src/libpsi/tools/zip/minizip/unzip.def0000644000175000017500000000101511305557617017661 0ustar janjan unzOpen @61 unzClose @62 unzGetGlobalInfo @63 unzGetCurrentFileInfo @64 unzGoToFirstFile @65 unzGoToNextFile @66 unzOpenCurrentFile @67 unzReadCurrentFile @68 unztell @70 unzeof @71 unzCloseCurrentFile @72 unzGetGlobalComment @73 unzStringFileNameCompare @74 unzLocateFile @75 unzGetLocalExtrafield @76 psi-0.14/src/libpsi/tools/zip/minizip/Makefile0000644000175000017500000000067111305557617017503 0ustar janjanCC=cc CFLAGS=-O -I../.. UNZ_OBJS = miniunz.o unzip.o ../../libz.a ZIP_OBJS = minizip.o zip.o ../../libz.a .c.o: $(CC) -c $(CFLAGS) $*.c all: miniunz minizip miniunz: $(UNZ_OBJS) $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) minizip: $(ZIP_OBJS) $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) test: miniunz minizip ./minizip test readme.txt ./miniunz -l test.zip mv readme.txt readme.old ./miniunz test.zip clean: /bin/rm -f *.o *~ minizip miniunz psi-0.14/src/libpsi/tools/zip/minizip/minizip.c0000644000175000017500000001655011305557617017671 0ustar janjan#include #include #include #include #include #include #ifdef unix # include # include # include # include #else # include # include #endif #include "zip.h" #define WRITEBUFFERSIZE (16384) #define MAXFILENAME (256) #ifdef WIN32 uLong filetime(f, tmzip, dt) char *f; /* name of file to get info on */ tm_zip *tmzip; /* return value: access, modific. and creation times */ uLong *dt; /* dostime */ { int ret = 0; { FILETIME ftLocal; HANDLE hFind; WIN32_FIND_DATA ff32; hFind = FindFirstFile(f,&ff32); if (hFind != INVALID_HANDLE_VALUE) { FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); FindClose(hFind); ret = 1; } } return ret; } #else #ifdef unix uLong filetime(f, tmzip, dt) char *f; /* name of file to get info on */ tm_zip *tmzip; /* return value: access, modific. and creation times */ uLong *dt; /* dostime */ { int ret=0; struct stat s; /* results of stat() */ struct tm* filedate; time_t tm_t=0; if (strcmp(f,"-")!=0) { char name[MAXFILENAME]; int len = strlen(f); strcpy(name, f); if (name[len - 1] == '/') name[len - 1] = '\0'; /* not all systems allow stat'ing a file with / appended */ if (stat(name,&s)==0) { tm_t = s.st_mtime; ret = 1; } } filedate = localtime(&tm_t); tmzip->tm_sec = filedate->tm_sec; tmzip->tm_min = filedate->tm_min; tmzip->tm_hour = filedate->tm_hour; tmzip->tm_mday = filedate->tm_mday; tmzip->tm_mon = filedate->tm_mon ; tmzip->tm_year = filedate->tm_year; return ret; } #else uLong filetime(f, tmzip, dt) char *f; /* name of file to get info on */ tm_zip *tmzip; /* return value: access, modific. and creation times */ uLong *dt; /* dostime */ { return 0; } #endif #endif int check_exist_file(filename) const char* filename; { FILE* ftestexist; int ret = 1; ftestexist = fopen(filename,"rb"); if (ftestexist==NULL) ret = 0; else fclose(ftestexist); return ret; } void do_banner() { printf("MiniZip 0.15, demo of zLib + Zip package written by Gilles Vollant\n"); printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n"); } void do_help() { printf("Usage : minizip [-o] file.zip [files_to_add]\n\n") ; } int main(argc,argv) int argc; char *argv[]; { int i; int opt_overwrite=0; int opt_compress_level=Z_DEFAULT_COMPRESSION; int zipfilenamearg = 0; char filename_try[MAXFILENAME]; int zipok; int err=0; int size_buf=0; void* buf=NULL, do_banner(); if (argc==1) { do_help(); exit(0); return 0; } else { for (i=1;i='0') && (c<='9')) opt_compress_level = c-'0'; } } else if (zipfilenamearg == 0) zipfilenamearg = i ; } } size_buf = WRITEBUFFERSIZE; buf = (void*)malloc(size_buf); if (buf==NULL) { printf("Error allocating memory\n"); return ZIP_INTERNALERROR; } if (zipfilenamearg==0) zipok=0; else { int i,len; int dot_found=0; zipok = 1 ; strcpy(filename_try,argv[zipfilenamearg]); len=strlen(filename_try); for (i=0;i='a') && (rep<='z')) rep -= 0x20; } while ((rep!='Y') && (rep!='N')); if (rep=='N') zipok = 0; } } if (zipok==1) { zipFile zf; int errclose; zf = zipOpen(filename_try,0); if (zf == NULL) { printf("error opening %s\n",filename_try); err= ZIP_ERRNO; } else printf("creating %s\n",filename_try); for (i=zipfilenamearg+1;(i0) { err = zipWriteInFileInZip (zf,buf,size_read); if (err<0) { printf("error in writing %s in the zipfile\n", filenameinzip); } } } while ((err == ZIP_OK) && (size_read>0)); fclose(fin); if (err<0) err=ZIP_ERRNO; else { err = zipCloseFileInZip(zf); if (err!=ZIP_OK) printf("error in closing %s in the zipfile\n", filenameinzip); } } } errclose = zipClose(zf,NULL); if (errclose != ZIP_OK) printf("error in closing %s\n",filename_try); } free(buf); exit(0); return 0; /* to avoid warning */ } psi-0.14/src/libpsi/tools/idle/0000755000175000017500000000000011305557617014473 5ustar janjanpsi-0.14/src/libpsi/tools/idle/idle.pri0000644000175000017500000000033411305557617016124 0ustar janjanHEADERS += $$PWD/idle.h SOURCES += $$PWD/idle.cpp INCLUDEPATH += $$PWD DEPENDPATH += $$PWD unix:!mac { SOURCES += $$PWD/idle_x11.cpp } win32: { SOURCES += $$PWD/idle_win.cpp } mac: { SOURCES += $$PWD/idle_mac.cpp } psi-0.14/src/libpsi/tools/idle/idle_x11.cpp0000644000175000017500000000430011305557617016602 0ustar janjan/* * idle_x11.cpp - detect desktop idle time * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "idle.h" #ifndef HAVE_XSS IdlePlatform::IdlePlatform() {} IdlePlatform::~IdlePlatform() {} bool IdlePlatform::init() { return false; } int IdlePlatform::secondsIdle() { return 0; } #else #include #include #include #include #include #include static XErrorHandler old_handler = 0; extern "C" int xerrhandler(Display* dpy, XErrorEvent* err) { if(err->error_code == BadDrawable) return 0; return (*old_handler)(dpy, err); } class IdlePlatform::Private { public: Private() {} XScreenSaverInfo *ss_info; }; IdlePlatform::IdlePlatform() { d = new Private; d->ss_info = 0; } IdlePlatform::~IdlePlatform() { if(d->ss_info) XFree(d->ss_info); if(old_handler) { XSetErrorHandler(old_handler); old_handler = 0; } delete d; } bool IdlePlatform::init() { if(d->ss_info) return true; old_handler = XSetErrorHandler(xerrhandler); int event_base, error_base; if(XScreenSaverQueryExtension(QApplication::desktop()->screen()->x11Display(), &event_base, &error_base)) { d->ss_info = XScreenSaverAllocInfo(); return true; } return false; } int IdlePlatform::secondsIdle() { if(!d->ss_info) return 0; if(!XScreenSaverQueryInfo(QApplication::desktop()->screen()->x11Display(), QX11Info::appRootWindow(), d->ss_info)) return 0; return d->ss_info->idle / 1000; } #endif psi-0.14/src/libpsi/tools/idle/idle.h0000644000175000017500000000243511305557617015565 0ustar janjan/* * idle.h - detect desktop idle time * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef IDLE_H #define IDLE_H #include class IdlePlatform; class Idle : public QObject { Q_OBJECT public: Idle(); ~Idle(); bool isActive() const; bool usingPlatform() const; void start(); void stop(); signals: void secondsIdle(int); private slots: void doCheck(); private: class Private; Private *d; }; class IdlePlatform { public: IdlePlatform(); ~IdlePlatform(); bool init(); int secondsIdle(); private: class Private; Private *d; }; #endif psi-0.14/src/libpsi/tools/idle/idle.cpp0000644000175000017500000000566611305557617016131 0ustar janjan/* * idle.cpp - detect desktop idle time * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "idle.h" #include #include #include static IdlePlatform *platform = 0; static int platform_ref = 0; class Idle::Private { public: Private() {} QPoint lastMousePos; QDateTime idleSince; bool active; int idleTime; QDateTime startTime; QTimer checkTimer; }; Idle::Idle() { d = new Private; d->active = false; d->idleTime = 0; // try to use platform idle if(!platform) { IdlePlatform *p = new IdlePlatform; if(p->init()) platform = p; else delete p; } if(platform) ++platform_ref; connect(&d->checkTimer, SIGNAL(timeout()), SLOT(doCheck())); } Idle::~Idle() { if(platform) { --platform_ref; if(platform_ref == 0) { delete platform; platform = 0; } } delete d; } bool Idle::isActive() const { return d->active; } bool Idle::usingPlatform() const { return (platform ? true: false); } void Idle::start() { d->startTime = QDateTime::currentDateTime(); if(!platform) { // generic idle d->lastMousePos = QCursor::pos(); d->idleSince = QDateTime::currentDateTime(); } // poll every second (use a lower value if you need more accuracy) d->checkTimer.start(1000); } void Idle::stop() { d->checkTimer.stop(); } void Idle::doCheck() { int i; if(platform) i = platform->secondsIdle(); else { QPoint curMousePos = QCursor::pos(); QDateTime curDateTime = QDateTime::currentDateTime(); if(d->lastMousePos != curMousePos) { d->lastMousePos = curMousePos; d->idleSince = curDateTime; } i = d->idleSince.secsTo(curDateTime); } // set 'beginIdle' to the beginning of the idle time (by backtracking 'i' seconds from now) QDateTime beginIdle = QDateTime::currentDateTime().addSecs(-i); // set 't' to hold the number of seconds between 'beginIdle' and 'startTime' int t = beginIdle.secsTo(d->startTime); // beginIdle later than (or equal to) startTime? if(t <= 0) { // scoot ourselves up to the new idle start d->startTime = beginIdle; } // beginIdle earlier than startTime? else if(t > 0) { // do nothing } // how long have we been idle? int idleTime = d->startTime.secsTo(QDateTime::currentDateTime()); secondsIdle(idleTime); } psi-0.14/src/libpsi/tools/idle/idle_win.cpp0000644000175000017500000000452211305557617016774 0ustar janjan/* * idle_win.cpp - detect desktop idle time * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "idle.h" #include #include #if defined(Q_OS_WIN32) && !defined(Q_CC_GNU) && (_WIN32_WINNT < 0x0500) typedef struct tagLASTINPUTINFO { UINT cbSize; DWORD dwTime; } LASTINPUTINFO, *PLASTINPUTINFO; #endif class IdlePlatform::Private { public: Private() { GetLastInputInfo = 0; IdleUIGetLastInputTime = 0; lib = 0; } BOOL (__stdcall * GetLastInputInfo)(PLASTINPUTINFO); DWORD (__stdcall * IdleUIGetLastInputTime)(void); QLibrary *lib; }; IdlePlatform::IdlePlatform() { d = new Private; } IdlePlatform::~IdlePlatform() { delete d->lib; delete d; } bool IdlePlatform::init() { if(d->lib) return true; void *p; // try to find the built-in Windows 2000 function d->lib = new QLibrary("user32"); if(d->lib->load() && (p = d->lib->resolve("GetLastInputInfo"))) { d->GetLastInputInfo = (BOOL (__stdcall *)(PLASTINPUTINFO))p; return true; } else { delete d->lib; d->lib = 0; } // fall back on idleui d->lib = new QLibrary("idleui"); if(d->lib->load() && (p = d->lib->resolve("IdleUIGetLastInputTime"))) { d->IdleUIGetLastInputTime = (DWORD (__stdcall *)(void))p; return true; } else { delete d->lib; d->lib = 0; } return false; } int IdlePlatform::secondsIdle() { int i; if(d->GetLastInputInfo) { LASTINPUTINFO li; li.cbSize = sizeof(LASTINPUTINFO); bool ok = d->GetLastInputInfo(&li); if(!ok) return 0; i = li.dwTime; } else if(d->IdleUIGetLastInputTime) { i = d->IdleUIGetLastInputTime(); } else return 0; return (GetTickCount() - i) / 1000; } psi-0.14/src/libpsi/tools/idle/idle_mac.cpp0000644000175000017500000001104411305557617016734 0ustar janjan/* * idle_mac.cpp - detect desktop idle time * Copyright (C) 2003 Tarkvara Design Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "idle.h" #include // Why does Apple have to make this so complicated? static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) { OSStatus err; FSRef frameworksFolderRef; CFURLRef baseURL; CFURLRef bundleURL; if ( bundlePtr == nil ) return( -1 ); *bundlePtr = nil; baseURL = nil; bundleURL = nil; err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef); if (err == noErr) { baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef); if (baseURL == nil) { err = coreFoundationUnknownErr; } } if (err == noErr) { bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false); if (bundleURL == nil) { err = coreFoundationUnknownErr; } } if (err == noErr) { *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); if (*bundlePtr == nil) { err = coreFoundationUnknownErr; } } if (err == noErr) { if ( ! CFBundleLoadExecutable( *bundlePtr ) ) { err = coreFoundationUnknownErr; } } // Clean up. if (err != noErr && *bundlePtr != nil) { CFRelease(*bundlePtr); *bundlePtr = nil; } if (bundleURL != nil) { CFRelease(bundleURL); } if (baseURL != nil) { CFRelease(baseURL); } return err; } class IdlePlatform::Private { public: EventLoopTimerRef mTimerRef; int mSecondsIdle; Private() : mTimerRef(0), mSecondsIdle(0) {} static pascal void IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void* inUserData); }; pascal void IdlePlatform::Private::IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void* inUserData) { switch (inState) { case kEventLoopIdleTimerStarted: case kEventLoopIdleTimerStopped: // Get invoked with this constant at the start of the idle period, // or whenever user activity cancels the idle. ((IdlePlatform::Private*)inUserData)->mSecondsIdle = 0; break; case kEventLoopIdleTimerIdling: // Called every time the timer fires (i.e. every second). ((IdlePlatform::Private*)inUserData)->mSecondsIdle++; break; } } IdlePlatform::IdlePlatform() { d = new Private(); } IdlePlatform::~IdlePlatform() { RemoveEventLoopTimer(d->mTimerRef); delete d; } // Typedef for the function we're getting back from CFBundleGetFunctionPointerForName. typedef OSStatus (*InstallEventLoopIdleTimerPtr)(EventLoopRef inEventLoop, EventTimerInterval inFireDelay, EventTimerInterval inInterval, EventLoopIdleTimerUPP inTimerProc, void * inTimerData, EventLoopTimerRef * outTimer); bool IdlePlatform::init() { // May already be init'ed. if (d->mTimerRef) { return true; } // According to the docs, InstallEventLoopIdleTimer is new in 10.2. // According to the headers, it has been around since 10.0. // One of them is lying. We'll play it safe and weak-link the function. // Load the "Carbon.framework" bundle. CFBundleRef carbonBundle; if (LoadFrameworkBundle( CFSTR("Carbon.framework"), &carbonBundle ) != noErr) { return false; } // Load the Mach-O function pointers for the routine we will be using. InstallEventLoopIdleTimerPtr myInstallEventLoopIdleTimer = (InstallEventLoopIdleTimerPtr)CFBundleGetFunctionPointerForName(carbonBundle, CFSTR("InstallEventLoopIdleTimer")); if (myInstallEventLoopIdleTimer == 0) { return false; } EventLoopIdleTimerUPP timerUPP = NewEventLoopIdleTimerUPP(Private::IdleTimerAction); if ((*myInstallEventLoopIdleTimer)(GetMainEventLoop(), kEventDurationSecond, kEventDurationSecond, timerUPP, 0, &d->mTimerRef)) { return true; } return false; } int IdlePlatform::secondsIdle() { return d->mSecondsIdle; } psi-0.14/src/libpsi/tools/idle/win32/0000755000175000017500000000000011321133122015410 5ustar janjanpsi-0.14/src/libpsi/tools/idle/win32/idleui.def0000644000175000017500000000022011305557617017362 0ustar janjanLIBRARY "IdleUI" DESCRIPTION 'IdleUI DLL by Paul DiLascia' SECTIONS .IdleUI READ WRITE SHARED EXPORTS IdleUIGetLastInputTime psi-0.14/src/libpsi/tools/idle/win32/idleui.cpp0000644000175000017500000000661111305557617017420 0ustar janjan//////////////////////////////////////////////////////////////// // 2000 Microsoft Systems Journal. // If this program works, it was written by Paul DiLascia. // If not, I don't know who wrote it. // This program compiles with Visual C++ 6.0 on Windows 98 // // See IdleUI.h // #include #include #include #define DLLEXPORT __declspec(dllexport) #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////// // The following global data is SHARED among all instances of the DLL // (processes); i.e., these are system-wide globals. // #pragma data_seg (".IdleUI") // you must define as SHARED in .def HHOOK g_keyboardHook = NULL; // one instance for all processes HHOOK g_mouseHook = NULL; // one instance for all processes DWORD g_lastInputTick = 0; // tick time of last input event /** Last mouse position. */ POINT g_lastMousePos; #pragma data_seg () /** Flag indicating whether the DLL's owning process is the loading DLL. */ bool g_isHandleOwner = false; // // Public interface // ////////////////// // Initialize DLL: install kbd/mouse hooks. // DLLEXPORT BOOL IdleUIInit() { return TRUE; } ////////////////// // Terminate DLL: remove hooks. // DLLEXPORT void IdleUITerm() { } ///////////////// // Get tick count of last keyboard or mouse event // DLLEXPORT DWORD IdleUIGetLastInputTime() { return g_lastInputTick; } // // Internals // ///////////////// // Keyboard hook: record tick count // LRESULT CALLBACK keyboardHookCallback(int code, WPARAM wParam, LPARAM lParam) { if (code == HC_ACTION) { g_lastInputTick = GetTickCount(); } return ::CallNextHookEx(g_keyboardHook, code, wParam, lParam); } ///////////////// // Mouse hook: record tick count // LRESULT CALLBACK mouseHookCallback(int code, WPARAM wParam, LPARAM lParam) { if (code == HC_ACTION) { // Update timestamp if event indicates mouse action bool change = false; if (wParam == WM_MOUSEMOVE && lParam != 0) { PMOUSEHOOKSTRUCT mhs = (PMOUSEHOOKSTRUCT) lParam; if (mhs->pt.x != g_lastMousePos.x || mhs->pt.y != g_lastMousePos.y) { change = true; g_lastMousePos = mhs->pt; } } else { change = true; } if (change) { g_lastInputTick = GetTickCount(); } } return ::CallNextHookEx(g_mouseHook, code, wParam, lParam); } void initialize(HINSTANCE module) { if (g_keyboardHook == 0) { g_keyboardHook = SetWindowsHookEx(WH_KEYBOARD, keyboardHookCallback, module, 0); g_mouseHook = SetWindowsHookEx(WH_MOUSE, mouseHookCallback, module, 0); g_lastInputTick = GetTickCount(); g_isHandleOwner = true; } assert(g_keyboardHook); assert(g_mouseHook); } void shutdown() { // Only handle-owning process may unhook if (g_isHandleOwner) { if (g_keyboardHook != 0) { UnhookWindowsHookEx(g_keyboardHook); g_keyboardHook = 0; } if (g_mouseHook != 0) { UnhookWindowsHookEx(g_mouseHook); g_mouseHook = 0; } } } // // DLL entry point // BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) { switch (reason) { case DLL_PROCESS_ATTACH: { initialize(module); break; } case DLL_PROCESS_DETACH: { shutdown(); break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: { // Ignore break; } } return TRUE; } psi-0.14/src/libpsi/tools/idle/win32/idleui.h0000644000175000017500000000165711305557617017072 0ustar janjan//////////////////////////////////////////////////////////////// // 2000 Microsoft Systems Journal. // If this program works, it was written by Paul DiLascia. // If not, I don't know who wrote it. // This program compiles with Visual C++ 6.0 on Windows 98 // #define DLLIMPORT __declspec(dllimport) // IdleUI is a DLL that lets you tell when the user interface has been idle // for a specified amount of time. The DLL works by installing windows keyboard // and mouse hooks. The DLL records the tick count whenever input is received. // // To use, you must // - call IdleUIInit when your app starts up // - call IdleUITerm when your app terminates // - call IdleUIGetLastInputTime to get the time, and compare this with // the current GetTickCount(); // // See TestIdleUI.cpp for an example of how to use IdleUI // DLLIMPORT BOOL IdleUIInit(); DLLIMPORT void IdleUITerm(); DLLIMPORT DWORD IdleUIGetLastInputTime(); psi-0.14/src/libpsi/tools/idle/win32/Makefile0000644000175000017500000000031511305557617017074 0ustar janjanSOURCES = idleui.cpp DLL_NAME = idleui.dll DEF_NAME = idleui.def all: $(DLL_NAME) $(DLL_NAME): $(SOURCES) cl /nologo /MD $(SOURCES) /link /def:$(DEF_NAME) user32.lib kernel32.lib /dll /out:$(DLL_NAME) psi-0.14/src/passphrase.ui0000644000175000017500000003612611305557613013650 0ustar janjan Passphrase 0 0 385 118 OpenPGP Passphrase 0 0 image0 true 20 30 Expanding Vertical 0 Your passphrase is needed to use OpenPGP security. Please enter your passphrase below: QLineEdit::Password 0 243 20 Expanding Horizontal &Cancel &OK true le_pass 789ccd9ad7ae2d377286eff51407c3bb81c1e91c60f862e79cf3367cc1cc5e3be730f0bb9babfeea96ceb1c2e848328c2d01fad424ab58ac2a16c9f58fbf7f39dfdff9f2f77ffcf0f4ac9e07f3c544f5f8e5eff6e5e6e6e33fffeb3ffef9c3dfaaee4bfaa7cdfa2fc5dffeed87bf1d3c7f315f76ef6edd1cdc620291d9a22a2d714eec8aa6cae6ec57c155dfb6c41b73ce8b425515f135b306db9eb84c5cd37892b82a6cd5507b4bdce65d49eddd327157665547bc4fec8bac24fdbc1eb922e5fd07735e1a6a7f3be7222900fded297389ef619db82c6d9dd3f78eb82a0dd895c47562ccf793b829da0aedef98fbaa9cb311c46dd1433f7b3232e6e796c055dd507fff4edc151dda3b8cd727fb28fa5e80abbe817dd7997583ef865815a3be90afaaac267ddc1eb19eec7fcb6c61af0079ba2a6afa1e6e987de369fc8ad8a4efb45e6a93d8561df47707c4aef090af7b7055d6d07781d89779d5d377ea9f56b3c57743f62cf3f45d537bc75c62fe7a035c972dd9df9d839bbaa3f67a9b382d20c64fae4d9cec43f6368a387d66ffba02577d8dfeb7ccaa267f5039b8ce1bf297c0df937ccc8ffca3aceaba857da17fddb41db5d73bc44dd95498df02738bf998b391b13e6a6cdfa3bdc2fc9b647ff2773f809baec37a603e6da91a5a3f57802b53d3f80af6e84a85f1dceec4d4dfc07e7d9247fa9a7770e56bc413c57ba94a057fd7f7cc1afdddc4f8ae5e990de23360bd52ef86be0b016efa8eec2ba09f2e3de25f93bfa5e8722de96f1bf0d8dee1bb4df149f31505b3873c733a31ec5382eb82e3ab9e98ec2d2e99ab86d6df1e13bbd2c17fd50bb8ca2bc4e313b16f5c4ffdfdd69cab6cb2d726b8ae118f8af4abf2343ee96bc95e5531c58f67ae607fb9c7dc623efa81b84cf143fa8837e606f16128bfa5de0d8f5732b7682ff1bdae7ac4838813537f45f19c46eb6afa2e47ee2bac0ff97fd246231f28b25fd5a57821960db385bd078a87aacf7d46eb6d2438b527ffd3b0974af145f69107cc0efd35e59f4a2779d4deb6e0c6b4f45d9e82dbb6277dedeac4349ec07c4dc5f95bee82eb0cfe693370ea8ef9413f9b98ece1b28911ffb097ab5c4df942417f57fb06fe78096e5c87f586bce47d1c7f015ce7f00fb1c35cf0fcdf992bb627e58fa46dc1f9e089d923ff485adf341ae753b1054e1b10b59787c4c9bbf05d3d4f4cfdbd18b9237f11bbcc0daf3fe99746e7fe229b98ec23c9ff92b63dda0fb43e75128ff5b60be0d6f558cf75709729ec8f2bccb9423e9811a7ec5f239f6c32f71dd95b16cc1edf05d9b34ede037bca0566079ed1fe5fa7fd0dfac82b706d317f39631edb53feac4d99a1bd8be0da75147f92ea95da3663fef2ccae237b6bac87ed6acccfaf11bbb6ebb0de940fd3eaa916fb2df4f7ad817ff919b3eb693d0ce6ebbb4ed1fcedcbc4b41e03f97f931596edbd076e0af89fa47cdae44d83fd425d10175daf48beb86556184f5f4f8c78a2fd256d579c6fcd2338c517e913ae9915e4e92b70ea4ff22cd9afa9d2fe84f85a068fdf07daef9aba2ca1ffb00faeb28cf49135b851f077f50e6e5bd8db62bcba2b907f07b257d3544546fa0d94af9aae32397d9f09669fa37ec4fcbaa41fe2730ddc79cc7f46f55393f6bf1cf5c201b8d1d8cfe53e73f200fa3e31f66383f548d6c37802ebd5f739cf9ff255a3ca8ae74ffed3e8ca413f8bf174637bf81be6afdb0cf5b4cc990def8714ff8d49fa213f65e0240ff918f6b295c9a0df13b8f1185f5d82fb42d17803f96be3ca1afacd2433c7d3b002ae7486fc087d5d97439f01ed7d55613d8719b82e72b287417f9f0a5a8c47ebd366659761bf1dc0693c9c2f281fb579d5a2ffb006aeeb9ce4c92370e738def87b5f633e91ea8fb618fd2d96e03a877f0c57cc0dc65377e0be5134de40f9a12dcb9ef57b03b7b643fd01f965df6ad41314af69f356c87f6a1d9cb617fa1e293edbba7219f47d04f71af688743e689baa86fde231b84e53a4f6d0afe9c6fd4983d3f8d06f6362f2a781f27fdb969c2fc20c9ce217f9ea9299f399da63f6989fdd1db9877f523dd876bdd194af22ad77db970dec138f983533f4edeb2ea7f9c605709317a8271a703be6fb169cd61ff15332b7585f49f1d9aaa41ff62ff88beab20efba7602e711e0857cc5d4ff3d154dfb4bab5a81f34e6a7933ce4af07e6122cf6987bf4572db346be0e74be694d5dc29f24d6c37415e2c19e31f3f9442a66d3637da91e6cd3f929237dc20538f937ce4b6fcca644beaec1299fa2bef2e0713d24d6c7257de18f57ccaa47fdb809ee3be4078bf5732ad3a89f213fed37c867e29399e7eb9726a6f5d24fcc1ef59320ff4dab617a9c7f1e991dd7676760956bea1fc9de5d5ee519d9377e329719e2f383b9e7fd7c00f719fbff3d388d47f223ed6f5daaaf793cc39c4a74d2ff029ce21df9f4159cf483ff58701a1ff531f42b927d906f3f98730dffe4f15501fb29c55c699aafa3fdb24b07b802fa4a70b217eaa33df0284fde4e8cfdf799b9c57e22e9fc93bcab427e34b0775dbb02eb83f1ebae817f899ed9f6143f01f64a1b20f657a3c1e90088f30dd58f5d3bb28ccc5cdf58d8ab55b5463d49f9ac4ba707ae47d6c09de2fa7105dce7f007b9c45cf17897e0341eea8575e616f653588f543d18acff05b3827c47f1dce9b62ab0bf5e3377b88f8ae89fe295ebb763f068ef007d4dd5c23f2cfcd5a6f840bc637dad5206f721f03f97e295ec3d40df745ae5fb29f84bf276d45b91f6afceb71efa885570b22fd6f792b957188ff68f3eabb99e369b60a535f94ba4fcd6e795827f8b7b702ac7b19e1d5819d8cb537eed8b3ec7f92562bcb22e512fb96df07c47a7fe3d581706f99ff2799f0e9488c748f5565fd72a43be5c022b0ffdf4d1c806f9e7029cca05d427e4dfa99c2ac0e289b9040f94effab6d5889741339b02fa8ddf1deedb14e69bfc11f94cd27ed3cffd09f3a778e955e3b01f8973701a1ef9ae64ae9967cce9c049e3a1bd4eed918f305fd394a87f22ec954e175c1f1d805b8bfd2d90bff5ae2932dc1f5d82d3ffc1fa2e825587fac0421faf7b83fa86eabb947dc6fc43e70795f71efee528be54d11505ee1b1fc08af71ffd0a4ee3e1beb36256187fa07a51954d9d217f92bfa8aa36988f7e03a7feb08f633616f3a5f852e900c8f505adbf6a6ac7f1710eee9a82ec6f307ea38d41fdb3c16c2df9db40fea052c1c3f6ec99d9befa10ac9dc57d23ed6f6a9e7f501f0ee0b6407ed70aac2de6ef28be55afbdc1fd50049b0c2cc8df52b46718dfc33e26d90bfa435f33b6b7989fd59c1f22dabbd11fe222b86f0bdcf7413f670af48f585fdf78f88731e0341ef6f3c0ec0cee330f983d58bf834d81f5107662d2c72c33a70330b5a7fc93bca9c0fe253b66037fd727605362fe5a305760f13c31b50f347f9d372ec7faa17fdef2fab905b0e9a0cf40fea78bb6cdb15fdc8093ff223ff1f74ea3de8da7e05ec1bfe323381578c8df9b605d348837cca74ceb8ffb1f0736b9c1febac1dc5adcdf858971fe5e65eec092f6075d9906fa8b4366ee1f28de74adeb16fbc535b3c6f9c3415eaab6787f5f07a7f208f2a89e4cd1a5c03e673616f505f457a93dea874f6605fb4b8a179d96cf62bf9c315b8b7a04f3d136b7a8bfc91fb419e36980fd4daf0bd44b9067359f6f05d6c31acdfaae333be8a78f993de43bf8871de519f2efe4ad25ea454bfaa6e8b1b09f09609b617e91e66fd2790efb792479a6681be82b16c1e3f832632e2ce299fc3115cb36277d22f3fcc188e445706a8ff5391ad9219f90fd4cca6f5c9fd4e0b1fd40fbb9a9bb1ef94dec83c7ef86fcc3b4c6237e23e51fd325f9388fdf81fb16fa098c9fbc0df610d713e3bde8636487fb7db44fd542017b2c81d38683f69f13e3bc9f33f7989ffa9818fb19d59f46f5bc7f445abf940c1cd7dbc760db42be5860e6fea69e18f5f323b302478cef3a8bfdc52f83ade6f69713e3be80e2c57895f3faef820ddfe78a03b0ed91efdc19b371f04fd23779478e7a5e1d31a71d83dabf331b87f3a667f6902f299ee7dee470ffb73931f20dd9d326ffe2fd2e803bdefffc2bb86f4be87b03b68ec77f66f60ef76d176097e37ba0f549c7418ff36464ee2bf88b7b038ffde50a38f5c77b28e5cbb9b7e07bc0f7b6cfe17fe18cb9e0f1af4746fc8796b9cc512f40df368d8ffbb0b58921ff9eb974885fda3fd3e15ac13f3dc6eb8dc77db65060577bb24fa078b1aaef73ec8737cc1af2875bb0ca72e4cf65b0ab1dada7c6fc749f4a18eaffceece1cf0ef2b4e6f75787f5d1ae71a8c728bf59a3f8bd42ae82c7ef7a7f62eaaf0e2746bdf0c0dc79f4a7fadddab1bdc9985bb0f7ccdcde633dd2e93347be407f97e21bf505e6e35c87fe361f19fd03e557ebbb71bf853f25efc57ac89eb987beea86597bd46734becb8cc17b68a0f9bb545fb23fec8035df9f9925b0332c9fe2d1a5f32ff6efc1802dbf1745aacf5ca93b8e8f1d66ae2fe50938e9037fa0fcecaa341ef69716ec3ad42bf68dd9a0bda9982dd893fd5cdd3bd67f17ac159f4f0bb0731ef741cfcc1ef688e41f2e9d4ff01eeea05f5a4d7c0f18bf1de763676037ee8f547fa5d5293cdeef0e986b8f78a4fad7f55ac15efa149c3c16f3277f71ca299ca73cd533a9f8ab512f0db04faa47e1cfc321d894f8bd41a07cec9ce1fd52435fe77b8ff715acafb735e2514bf0f87d20fd7ca6c7783a9b18f1e9990dde2b03e5779fea3bc4ab237ff365b210f6d317b0ef3cf64ff24f9faa47f60fcaffbe36fc1e680fc08eef33dd3138e947e347cab7be3105de27c3297389f1063acffa56fb12fbff3ed818bcf78457b0cd4abca7af80e70535d903e377bde5f3c33278f26ffe6e6abcdf0709b615ea5185f977deb23dc9ff7c3a30727c513ded55928fdf6bec33e7fcfb9075b0cb1bfc1e463397b8aff1940fbd3625d6c71e82bdc6f94909660ff991e23569637bcc17fa78d540bec37a7bcdbfbff177e0940e10df4fcc2dde93b467eef11ea70b66050e8fcc9e7f9f82f5f1b6c2ef25c21bb3c27bfa703432ee27864f668bf7eca026a6f889336657e3bee78199df07c3c9c82c0ff6f5aec0fbb73f602ef1fe6fc5c4b81fbc67aec0c3d6c4b8af657bb81aefd1c3257383f1ccd5c4b06f3b728bdf4368e616bf3730dbcc1df41ddcc498cf3bf3f87b9fc3915bf8d3e7c4a89fd8fe4ef3ef51d6980dde1f633b31d9d7aa8931de33b3853d878591a19fb99e18f5503932eeefe3c1c488bf51be457e8b35b3c378766362d4cf3b1363bfe4f5752964898f46e6f709b6a7cff19ea1cf26c679f49899dfc7073f31e26d7364bc27e8f389713f6626463ef89818fef83631f6ebb17d89f6766b62dc9fdc4e8cfd6d6964dcd79a1be61afdfde3c4d83f2c730b763f327ebff43931ecb93b31ec37daa3c3fb9fb513637d2e26c6fe594c8cf976ccfc3e3c8cf6e3f7a46026c6fcc6f114bfbfe889514fde4d0c7b6d4f8cf92e328ffba39b18bf67ea26467c3f4d4cf315d3777e0f1bc71bfd756564fefd879b18fbc1c2c4d8ef9626467cb03f2703217eef47867e616162e4fb9389e12fa33c8ff71cb73e31fcf97262f8fbcec4341f6d26463db13831fc359b18f7b57e62dc271d4f8cf7fcd9c4f0273b31cecb3ff6473d3ccd07f7af6ab4a7c7fdab9ae6cfef93a71363bf9af4c5fda75a9a18e7b7ab8971de6e27c6fd713331e6f7637bdc872c4f8c7a61d21fe7413dd99fefafe3c8b83f8fc3c4a4af799d18f5d6343ecefbf67a62f8d7eac4588f7c62dc071e4d8cdf83f413e3be66d207e75d33f917f6fbb03d31ee375e26463d723e31c63b1c19f701fe7962dc87ed4d0cff9aec8bf3b55e9b18f69aec837a5a9d4d8cdfa3fcc8d4fee0f9affdfbff2c430aa9a4feeb644823ad74d2cb20a31ce44c5ea5bfeb3f4f86bc91b7f24edecb07f9289fe4b37c91aff22dfdbdcb0ff92917feb80cb92897e47292b02257e59a5c971b72536ec96db92377e59edc9707f2f08fc89047c942c72ce1449eca33792e2fe4a5cc644edf0b59ca4ad6b291c577cb686547121e642fa41042092d8cb0c2093fb611414431a47f67df27435c896bac83b811b7e24edc8b07f1289ec4b37811af53ab997813efe2e33b657c8a0592b02896c4b25811abf24cac8975b12136c5d64fdacdc4b6d811bbdf25634fec93840371288ec4b13849324ec599381717e2f2ab9699c845f15d324a512509b568442b3ad12ba9c4fcf9787e85aedcd76d955741c5df2f430d6251cdd495ba124dfab755d7ea46ddaa3b75af1ed4a37afaaaedb37a51afbf4f867a53efea437daa05b5a896929c65b59266d3a855b5a6d6d586da545bdff4d8563b6af75f95a1f6d4be3a9067ea501da96375926670aaced4b93a4e525a75a12e55a672f54d4ca872fe33de7f45866ad4fc0783bd965a68a5b536da6a970ead41473de8d9dc66fa4a5feb1b7dfb754f7da7eff5c36fcbd08ffa493feb17fdaadff4bbfed09f7a412fa65197f4b25ed1ab7a2dcd6b2e655d6fe8cd6ffa6ee96dbdf3eb32f4aeded3fbfa401fea237dac4ff4a93ed3e7fa425fea4ce7bad0e5fc27cbbad1b3f98f8be63f0ffababf914618f5cb32a431da18638d33de0413cd6066e6ca5c9b1b736beee6f632f7e6c13c9a27f36c5ed4b179356fe6fd1b191fe6d32cfcbc0c7993c65f344b66d9ac9855b366d6cd4692b069b6ccb6d9d1e766776e2f75a2aecc9ed93707e6d01ca905736c4ebe91716aceccf9cfc93017e6d264263785294d656ad398364998bf74492bacb2f327586b9df56a452dda60a31deccc5ed96b7bf3b50c7b6befecfdb732ec837db44ff6d9bed857fb66dfed87fdb40b76d12ed965bb6257ed9a5db71b76d36ed96dbb937c6a412dd95dbb67f7ed8168eda13dfa8984637b624f471a65d8337b6e2feca5cd6c6e0bb9624b5bd93a8dddd8d6ce7f4023ddfc664e9b1d679c75e93f9c4f71b2e2828b6e7033ddb82bc7fbadbb71b7eecedd7f2bc33db847f7e49edd8b7b756feedd7db84fb7e016dd925b1edbba15b7ead6602fb76e3d4959701b6e33fd6db96db7e376d3df9edb77076eefc7594d320edd913b7627eed49db97377e12e5de6d2fee60a57b284cad5ae71ad55fadc6eb98eedb538ff6198975ea4bff913f3fc913c89ffe9da8c32e4adcd534917ec9b8f7ef0337fe5af9dfc694b7fe36ffd9d68fcbd7fb0c63ffaa7e4c5b334932bffec5ffcab7ff3effec37ffa05bff8f5fa8f32fc925ff62b7e551ffb35bfee377c8a5bff933ce7b7fd8edff57b7edf1ff8437f64b7fcb13fd1993ad1b93ff567fedc5ffc52be98645cfacce7eec917bef4552a9eeaafe6d078fa695b904104157430c15a139cbe544bc1871062187e49c28f32c22c5c85eb70136ec3ddb76dc27d78088fe1293c8797f01adec27bf8089f61212c86a5b01c56c26a58fb65095fc760584ffe29c3c6ff92b1a95dd80adb6127ec86bdb01f0ec261380ac7e1c4bc86d37016cec32fdae95b193fff172e4316f250882694a10a7568421bba907260945144157534bf3ec26fc98836bae86308cb31c621cee255bc8e3791778b7817efe3c3af4bf817643cc6a7f89cacbe1d5fe26b7c8beff1237ec69fad6bbf4f465c8c4b7139ae041f57e35a5c8f1b71336ec5eddf23e1d765c49db81bf7e2be3a8e07f1509ec594f5e2713cf93de3ffa68cd37816cfd569bc8897318b792c62f97bc7ff7519b18a756cec556c63a76dec07398841fd9932063d98c10e6ef04318a25e1c8621d5e2c3d59f2763b81e6e86dbe16eb81f1e86c7e169781e5e86d7df3ffaafca781bde870fb5307c0e0bc3e2b0342c0f2bc3eaf0ab19e377cb581f3686cd616bd81e7686dd616fd8ffde39fcb28c24e560381c8e86e3e164384d7f677f858c24e57cb8182e876cc887b5a118becb6b7f4b4692520df5d00ced1f99c36fc94852baa19fc999f82b651c3ccfd44ccf7e2377ff51197fc6dfff898cfffef71ffe07cc56e742 psi-0.14/src/psitrayicon.h0000644000175000017500000000155311305557613013651 0ustar janjan#ifndef PSITRAYICON_H #define PSITRAYICON_H #include #include #include class PsiIcon; class QMenu; class QPoint; class QPixmap; class PsiTrayIcon : public QObject { Q_OBJECT public: PsiTrayIcon(const QString &tip, QMenu *popup, QObject *parent=0); ~PsiTrayIcon(); void setContextMenu(QMenu*); void setToolTip(const QString &); void setIcon(const PsiIcon *, bool alert = false); void setAlert(const PsiIcon *); bool isAnimating() const; bool isWMDock(); signals: void clicked(const QPoint &, int); void doubleClicked(const QPoint &); void closed(); public slots: void show(); void hide(); private slots: void animate(); void trayicon_activated(QSystemTrayIcon::ActivationReason); protected: QPixmap makeIcon(); QRgb pixelBlend(QRgb p1, QRgb p2); private: PsiIcon* icon_; QSystemTrayIcon* trayicon_; }; #endif psi-0.14/src/options/0000755000175000017500000000000011305557613012623 5ustar janjanpsi-0.14/src/options/opt_shortcuts.ui0000644000175000017500000000541211305557613016104 0ustar janjan OptShortcuts 7 7 0 0 450 450 OptShortcutsUI 9 6 Qt::LeftToRight true true true 2 Description Shortcut 0 6 Add... Remove Edit... Qt::Horizontal 40 20 Restore defaults qPixmapFromMimeSource psi-0.14/src/options/opt_iconset_system.ui0000644000175000017500000000410411305557613017113 0ustar janjan IconsetSystem 0 0 178 203 IconsetSystemUI 9 6 System iconset: Qt::Horizontal &Show details Alt+S Qt::Horizontal QSizePolicy::Expanding 305 20 qPixmapFromMimeSource IconButton QPushButton
iconbutton.h
IconsetSelect QListWidget
iconsetselect.h
psi-0.14/src/options/opt_plugins.cpp0000644000175000017500000000716311305557613015701 0ustar janjan#include "opt_plugins.h" #include "common.h" #include "iconwidget.h" #include "pluginmanager.h" #include "psioptions.h" #include #include #include #include #include #include "ui_opt_plugins.h" class OptPluginsUI : public QWidget, public Ui::OptPlugins { public: OptPluginsUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabPlugins //---------------------------------------------------------------------------- OptionsTabPlugins::OptionsTabPlugins(QObject *parent) : OptionsTab(parent, "plugins", "", tr("Plugins"), tr("Options for Psi plugins"), "psi/advanced") { w = 0; } OptionsTabPlugins::~OptionsTabPlugins() { } QWidget *OptionsTabPlugins::widget() { if ( w ) return 0; w = new OptPluginsUI(); OptPluginsUI *d = (OptPluginsUI *)w; listPlugins(); /*d->ck_messageevents->setWhatsThis( tr("Enables the sending and requesting of message events such as " "'Contact is Typing', ..."));*/ connect(d->cb_plugins,SIGNAL(currentIndexChanged(int)),SLOT(pluginSelected(int))); connect(d->cb_loadPlugin,SIGNAL(stateChanged(int)),SLOT(loadToggled(int))); return w; } void OptionsTabPlugins::applyOptions(Options *opt) { if ( !w ) return; OptPluginsUI *d = (OptPluginsUI *)w; Q_UNUSED(d); Q_UNUSED(opt); } void OptionsTabPlugins::restoreOptions(const Options *opt) { if ( !w ) return; OptPluginsUI *d = (OptPluginsUI *)w; Q_UNUSED(opt); Q_UNUSED(d); } void OptionsTabPlugins::listPlugins() { if ( !w ) return; OptPluginsUI *d = (OptPluginsUI *)w; d->cb_plugins->clear(); PluginManager *pm=PluginManager::instance(); QStringList plugins=pm->availablePlugins(); foreach (QString plugin, plugins){ d->cb_plugins->addItem(plugin); } pluginSelected(0); } void OptionsTabPlugins::loadToggled(int state) { Q_UNUSED(state); if ( !w ) return; OptPluginsUI *d = (OptPluginsUI *)w; QString option=QString("%1.%2") .arg(PluginManager::loadOptionPrefix) .arg(PluginManager::instance()->shortName(d->cb_plugins->currentText())); bool value=d->cb_loadPlugin->isChecked(); PsiOptions::instance()->setOption(option, value); } void OptionsTabPlugins::pluginSelected(int index) { Q_UNUSED(index); if ( !w ) return; OptPluginsUI *d = (OptPluginsUI *)w; d->le_location->setText(tr("No plugin selected.")); d->cb_loadPlugin->setEnabled(false); delete d->pluginOptions; d->pluginOptions = new QLabel(tr("This plugin has no user configurable options")); if ( d->cb_plugins->count() > 0 ) { QString pluginName=d->cb_plugins->currentText(); d->le_location->setText(PluginManager::instance()->pathToPlugin( pluginName )); d->cb_loadPlugin->setEnabled(true); QWidget* pluginOptions = PluginManager::instance()->optionsWidget( pluginName ); d->cb_plugins->setEnabled(true); QString option=QString("%1.%2") .arg(PluginManager::loadOptionPrefix) .arg(PluginManager::instance()->shortName(pluginName)); int value=PsiOptions::instance()->getOption(option).toBool(); if (value) value=Qt::Checked; else value=Qt::Unchecked; d->cb_loadPlugin->setChecked(value); d->vboxLayout1->remove(d->pluginOptions); delete d->pluginOptions; d->pluginOptions=NULL; if (pluginOptions) { d->pluginOptions = pluginOptions; d->pluginOptions->setParent(d); qWarning("Showing Plugin options"); } else { d->pluginOptions = new QLabel(tr("This plugin has no user configurable options"),d); qWarning("Plugin has no options"); } d->vboxLayout1->addWidget(d->pluginOptions); //d->pluginOptions->show(); //d->updateGeometry(); } } psi-0.14/src/options/opt_appearance_misc.ui0000644000175000017500000001136211305557613017161 0ustar janjan OptAppearanceMisc 0 0 354 189 OptAppearanceMiscUI 9 6 Headings 8 6 Slim group headings Outline headings Opacity 8 6 10 100 Qt::Horizontal 30 0 100 Qt::AlignCenter 10 100 Qt::Horizontal Roster opacity: 30 0 100 Qt::AlignCenter Chat dialog opacity: qPixmapFromMimeSource ck_outlineHeadings ck_newHeadings sl_rosterop sl_chatdlgop sl_rosterop valueChanged(int) lb_rosterop_val setNum(int) 208 134 320 134 sl_chatdlgop valueChanged(int) lb_chatdlgop_val setNum(int) 208 159 320 159 psi-0.14/src/options/opt_avcall.h0000644000175000017500000000050611305557613015121 0ustar janjan#ifndef OPT_AVCALL_H #define OPT_AVCALL_H #include "optionstab.h" class QWidget; class QButtonGroup; class OptionsTabAvCall : public OptionsTab { Q_OBJECT public: OptionsTabAvCall(QObject *parent); ~OptionsTabAvCall(); QWidget *widget(); void applyOptions(); void restoreOptions(); private: QWidget *w; }; #endif psi-0.14/src/options/options.pri0000644000175000017500000000270011305557613015031 0ustar janjan# base dialog stuff HEADERS += \ $$PWD/optionsdlg.h \ $$PWD/optionstab.h SOURCES += \ $$PWD/optionstab.cpp \ $$PWD/optionsdlg.cpp INTERFACES += \ $$PWD/ui_options.ui # additional tabs HEADERS += \ $$PWD/opt_application.h \ $$PWD/opt_chat.h \ $$PWD/opt_events.h \ $$PWD/opt_status.h \ $$PWD/opt_appearance.h \ $$PWD/opt_iconset.h \ $$PWD/opt_groupchat.h \ $$PWD/opt_sound.h \ $$PWD/opt_avcall.h \ $$PWD/opt_toolbars.h \ $$PWD/opt_advanced.h \ $$PWD/opt_shortcuts.h HEADERS += $$PWD/opt_tree.h SOURCES += \ $$PWD/opt_application.cpp \ $$PWD/opt_chat.cpp \ $$PWD/opt_events.cpp \ $$PWD/opt_status.cpp \ $$PWD/opt_appearance.cpp \ $$PWD/opt_iconset.cpp \ $$PWD/opt_groupchat.cpp \ $$PWD/opt_sound.cpp \ $$PWD/opt_avcall.cpp \ $$PWD/opt_toolbars.cpp \ $$PWD/opt_advanced.cpp \ $$PWD/opt_shortcuts.cpp SOURCES += $$PWD/opt_tree.cpp INTERFACES += \ $$PWD/opt_application.ui \ $$PWD/opt_chat.ui \ $$PWD/opt_events.ui \ $$PWD/opt_status.ui \ $$PWD/opt_appearance.ui \ $$PWD/opt_appearance_misc.ui \ $$PWD/opt_sound.ui \ $$PWD/opt_avcall.ui \ $$PWD/opt_advanced.ui \ $$PWD/opt_lookfeel_toolbars.ui \ $$PWD/ui_isdetails.ui \ $$PWD/opt_iconset_emo.ui \ $$PWD/opt_iconset_system.ui \ $$PWD/opt_iconset_roster.ui \ $$PWD/opt_general_groupchat.ui \ $$PWD/opt_shortcuts.ui psi_plugins { INTERFACES += $$PWD/opt_plugins.ui SOURCES += $$PWD/opt_plugins.cpp HEADERS += $$PWD/opt_plugins.h } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD psi-0.14/src/options/opt_avcall.cpp0000644000175000017500000001520511305557613015456 0ustar janjan#include "opt_avcall.h" #include "common.h" #include "iconwidget.h" #include "psioptions.h" #include "../psimedia/psimedia.h" #include "../avcall/avcall.h" #include #include #include #include "ui_opt_avcall.h" class OptAvCallUI : public QWidget, public Ui::OptAvCall { public: OptAvCallUI() : QWidget() { setupUi(this); } }; // adapted from psimedia configure dialog class Configuration2 { public: QString audioOutDeviceId, audioInDeviceId, videoInDeviceId; }; class PsiMediaFeaturesSnapshot2 { public: QList audioOutputDevices; QList audioInputDevices; QList videoInputDevices; PsiMediaFeaturesSnapshot2() { PsiMedia::Features f; int types = 0; types |= PsiMedia::Features::AudioOut; types |= PsiMedia::Features::AudioIn; if(AvCallManager::isVideoSupported()) types |= PsiMedia::Features::VideoIn; f.lookup(types); f.waitForFinished(); audioOutputDevices = f.audioOutputDevices(); audioInputDevices = f.audioInputDevices(); videoInputDevices = f.videoInputDevices(); } }; // get default settings static Configuration2 getDefaultConfiguration(const PsiMediaFeaturesSnapshot2 &snap) { Configuration2 config; QList devs; devs = snap.audioOutputDevices; if(!devs.isEmpty()) config.audioOutDeviceId = devs.first().id(); devs = snap.audioInputDevices; if(!devs.isEmpty()) config.audioInDeviceId = devs.first().id(); devs = snap.videoInputDevices; if(!devs.isEmpty()) config.videoInDeviceId = devs.first().id(); return config; } // adjust any invalid settings to nearby valid ones static Configuration2 adjustConfiguration(const Configuration2 &in, const PsiMediaFeaturesSnapshot2 &snap) { Configuration2 out = in; bool found; if(!out.audioOutDeviceId.isEmpty()) { found = false; foreach(const PsiMedia::Device &dev, snap.audioOutputDevices) { if(out.audioOutDeviceId == dev.id()) { found = true; break; } } if(!found) { if(!snap.audioOutputDevices.isEmpty()) out.audioOutDeviceId = snap.audioOutputDevices.first().id(); else out.audioOutDeviceId.clear(); } } if(!out.audioInDeviceId.isEmpty()) { found = false; foreach(const PsiMedia::Device &dev, snap.audioInputDevices) { if(out.audioInDeviceId == dev.id()) { found = true; break; } } if(!found) { if(!snap.audioInputDevices.isEmpty()) out.audioInDeviceId = snap.audioInputDevices.first().id(); else out.audioInDeviceId.clear(); } } if(!out.videoInDeviceId.isEmpty()) { found = false; foreach(const PsiMedia::Device &dev, snap.videoInputDevices) { if(out.videoInDeviceId == dev.id()) { found = true; break; } } if(!found) { if(!snap.videoInputDevices.isEmpty()) out.videoInDeviceId = snap.videoInputDevices.first().id(); else out.videoInDeviceId.clear(); } } return out; } void options_avcall_update() { PsiMediaFeaturesSnapshot2 snap; Configuration2 config = getDefaultConfiguration(snap); QString id; id = PsiOptions::instance()->getOption("options.media.devices.audio-output").toString(); if(!id.isEmpty()) config.audioOutDeviceId = id; id = PsiOptions::instance()->getOption("options.media.devices.audio-input").toString(); if(!id.isEmpty()) config.audioInDeviceId = id; id = PsiOptions::instance()->getOption("options.media.devices.video-input").toString(); if(!id.isEmpty()) config.videoInDeviceId = id; config = adjustConfiguration(config, snap); PsiOptions::instance()->setOption("options.media.devices.audio-output", config.audioOutDeviceId); PsiOptions::instance()->setOption("options.media.devices.audio-input", config.audioInDeviceId); PsiOptions::instance()->setOption("options.media.devices.video-input", config.videoInDeviceId); } //---------------------------------------------------------------------------- // OptionsTabAvCall //---------------------------------------------------------------------------- OptionsTabAvCall::OptionsTabAvCall(QObject *parent) : OptionsTab(parent, "avcall", "", tr("Voice Calling"), AvCallManager::isVideoSupported() ? tr("Audio and video device configuration") : tr("Audio device configuration"), "psi/voice") { w = 0; } OptionsTabAvCall::~OptionsTabAvCall() { } QWidget *OptionsTabAvCall::widget() { if ( w ) return 0; w = new OptAvCallUI(); OptAvCallUI *d = (OptAvCallUI *)w; if(!AvCallManager::isVideoSupported()) { d->lb_videoInDevice->hide(); d->cb_videoInDevice->hide(); } return w; } void OptionsTabAvCall::applyOptions() { if ( !w ) return; OptAvCallUI *d = (OptAvCallUI *)w; PsiOptions::instance()->setOption("options.media.devices.audio-output", d->cb_audioOutDevice->itemData(d->cb_audioOutDevice->currentIndex()).toString()); PsiOptions::instance()->setOption("options.media.devices.audio-input", d->cb_audioInDevice->itemData(d->cb_audioInDevice->currentIndex()).toString()); PsiOptions::instance()->setOption("options.media.devices.video-input", d->cb_videoInDevice->itemData(d->cb_videoInDevice->currentIndex()).toString()); } void OptionsTabAvCall::restoreOptions() { if ( !w ) return; OptAvCallUI *d = (OptAvCallUI *)w; PsiMediaFeaturesSnapshot2 snap; d->cb_audioOutDevice->clear(); if(snap.audioOutputDevices.isEmpty()) d->cb_audioOutDevice->addItem("", QString()); foreach(const PsiMedia::Device &dev, snap.audioOutputDevices) d->cb_audioOutDevice->addItem(dev.name(), dev.id()); d->cb_audioInDevice->clear(); if(snap.audioInputDevices.isEmpty()) d->cb_audioInDevice->addItem("", QString()); foreach(const PsiMedia::Device &dev, snap.audioInputDevices) d->cb_audioInDevice->addItem(dev.name(), dev.id()); d->cb_videoInDevice->clear(); if(snap.videoInputDevices.isEmpty()) d->cb_videoInDevice->addItem("", QString()); foreach(const PsiMedia::Device &dev, snap.videoInputDevices) d->cb_videoInDevice->addItem(dev.name(), dev.id()); Configuration2 config = getDefaultConfiguration(snap); QString id; id = PsiOptions::instance()->getOption("options.media.devices.audio-output").toString(); if(!id.isEmpty()) config.audioOutDeviceId = id; id = PsiOptions::instance()->getOption("options.media.devices.audio-input").toString(); if(!id.isEmpty()) config.audioInDeviceId = id; id = PsiOptions::instance()->getOption("options.media.devices.video-input").toString(); if(!id.isEmpty()) config.videoInDeviceId = id; config = adjustConfiguration(config, snap); d->cb_audioOutDevice->setCurrentIndex(d->cb_audioOutDevice->findData(config.audioOutDeviceId)); d->cb_audioInDevice->setCurrentIndex(d->cb_audioInDevice->findData(config.audioInDeviceId)); d->cb_videoInDevice->setCurrentIndex(d->cb_videoInDevice->findData(config.videoInDeviceId)); } psi-0.14/src/options/optionsdlgiface.h0000644000175000017500000000032511305557613016146 0ustar janjan#ifndef OPTIONSDLGIFACE_H #define OPTIONSDLGIFACE_H class OptionsDlgIface : public QObject { Q_OBJECT public: OptionsDlgIface(QObject *parent, const char *name); ~OptionsDlgIface(); public slots: }; #endif psi-0.14/src/options/opt_groupchat.cpp0000644000175000017500000001330211305557613016204 0ustar janjan#include "opt_groupchat.h" #include "common.h" #include "iconwidget.h" #include "psioptions.h" #include #include #include #include #include #include #include #include #include #include #include "ui_opt_general_groupchat.h" class GeneralGroupchatUI : public QWidget, public Ui::GeneralGroupchat { public: GeneralGroupchatUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabGroupchat -- TODO: simplify the code //---------------------------------------------------------------------------- OptionsTabGroupchat::OptionsTabGroupchat(QObject *parent) : OptionsTab(parent, "groupchat", "", tr("Groupchat"), tr("Configure the groupchat"), "psi/groupChat") { w = 0; } void OptionsTabGroupchat::setData(PsiCon *, QWidget *_dlg) { dlg = _dlg; } QWidget *OptionsTabGroupchat::widget() { if ( w ) return 0; w = new GeneralGroupchatUI(); GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; connect(d->pb_nickColor, SIGNAL(clicked()), SLOT(chooseGCNickColor())); connect(d->lw_nickColors, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), SLOT(selectedGCNickColor(QListWidgetItem *))); connect(d->pb_addHighlightWord, SIGNAL(clicked()), SLOT(addGCHighlight())); connect(d->pb_removeHighlightWord, SIGNAL(clicked()), SLOT(removeGCHighlight())); connect(d->pb_addNickColor, SIGNAL(clicked()), SLOT(addGCNickColor())); connect(d->pb_removeNickColor, SIGNAL(clicked()), SLOT(removeGCNickColor())); // TODO: add QWhatsThis for all controls on widget return w; } void OptionsTabGroupchat::applyOptions() { if ( !w ) return; GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; PsiOptions::instance()->setOption("options.ui.muc.use-highlighting", d->ck_gcHighlights->isChecked()); PsiOptions::instance()->setOption("options.ui.muc.use-nick-coloring", d->ck_gcNickColoring->isChecked()); QStringList highlight; int i; for (i = 0; i < (int)d->lw_highlightWords->count(); i++) highlight << d->lw_highlightWords->item(i)->text(); PsiOptions::instance()->setOption("options.ui.muc.highlight-words", highlight); QStringList colors; for (i = 0; i < (int)d->lw_nickColors->count(); i++) colors << d->lw_nickColors->item(i)->text(); PsiOptions::instance()->setOption("options.ui.look.colors.muc.nick-colors", colors); } void OptionsTabGroupchat::restoreOptions() { if ( !w ) return; GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; // no need to call dataChanged() when these widgets are modified disconnect(d->le_newNickColor, SIGNAL(textChanged(const QString &)), 0, 0); disconnect(d->le_newHighlightWord, SIGNAL(textChanged(const QString &)), 0, 0); connect(d->le_newNickColor, SIGNAL(textChanged(const QString &)), SLOT(displayGCNickColor())); d->ck_gcHighlights->setChecked( true ); d->ck_gcHighlights->setChecked( PsiOptions::instance()->getOption("options.ui.muc.use-highlighting").toBool() ); d->ck_gcNickColoring->setChecked( true ); d->ck_gcNickColoring->setChecked( PsiOptions::instance()->getOption("options.ui.muc.use-nick-coloring").toBool() ); d->lw_highlightWords->clear(); d->lw_highlightWords->addItems( PsiOptions::instance()->getOption("options.ui.muc.highlight-words").toStringList() ); d->lw_nickColors->clear(); foreach(QString col, PsiOptions::instance()->getOption("options.ui.look.colors.muc.nick-colors").toStringList()) { addNickColor(col); } d->le_newHighlightWord->setText(""); d->le_newNickColor->setText("#FFFFFF"); } static QPixmap name2color(QString name) { QColor c(name); QPixmap pix(16, 16); QPainter p(&pix); p.fillRect(0, 0, pix.width(), pix.height(), QBrush(c)); p.setPen( QColor(0, 0, 0) ); p.drawRect(0, 0, pix.width(), pix.height()); p.end(); return pix; } void OptionsTabGroupchat::addNickColor(QString name) { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; d->lw_nickColors->addItem(new QListWidgetItem(name2color(name), name)); } void OptionsTabGroupchat::addGCHighlight() { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; if ( d->le_newHighlightWord->text().isEmpty() ) return; d->lw_highlightWords->addItem( d->le_newHighlightWord->text() ); d->le_newHighlightWord->setFocus(); d->le_newHighlightWord->setText(""); emit dataChanged(); } void OptionsTabGroupchat::removeGCHighlight() { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; int id = d->lw_highlightWords->currentRow(); if ( id == -1 ) return; d->lw_highlightWords->takeItem(id); emit dataChanged(); } void OptionsTabGroupchat::addGCNickColor() { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; if ( d->le_newNickColor->text().isEmpty() ) return; addNickColor( d->le_newNickColor->text() ); d->le_newNickColor->setFocus(); d->le_newNickColor->setText(""); emit dataChanged(); } void OptionsTabGroupchat::removeGCNickColor() { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; int id = d->lw_nickColors->currentRow(); if ( id == -1 ) return; d->lw_nickColors->takeItem(id); emit dataChanged(); } void OptionsTabGroupchat::chooseGCNickColor() { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; QColor c = QColorDialog::getColor(QColor(d->le_newNickColor->text()), dlg); if ( c.isValid() ) { QString cs = c.name(); d->le_newNickColor->setText(cs); } } void OptionsTabGroupchat::selectedGCNickColor(QListWidgetItem * item) { if (!item) return; // no selection on empty list GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; d->le_newNickColor->setText( item->text() ); } void OptionsTabGroupchat::displayGCNickColor() { GeneralGroupchatUI *d = (GeneralGroupchatUI *)w; d->pb_nickColor->setIcon( name2color(d->le_newNickColor->text()) ); } psi-0.14/src/options/opt_appearance.h0000644000175000017500000000247411305557613015764 0ustar janjan#ifndef OPT_APPEARANCEGENERAL_H #define OPT_APPEARANCEGENERAL_H #include "optionstab.h" #include #include class FontLabel : public QLineEdit { Q_OBJECT public: FontLabel(QWidget *parent = 0, const char *name = 0); void setFont(QString); QString fontName() const; QSize sizeHint() const; private: QString m_font; int m_defaultHeight; }; class QWidget; class QButtonGroup; class QLineEdit; class OptionsTabAppearance : public MetaOptionsTab { Q_OBJECT public: OptionsTabAppearance(QObject *parent); }; class OptionsTabAppearanceMisc : public OptionsTab { Q_OBJECT public: OptionsTabAppearanceMisc(QObject *parent); ~OptionsTabAppearanceMisc(); QWidget *widget(); void applyOptions(); void restoreOptions(); private slots: void setData(PsiCon *, QWidget *); private: QWidget *w, *parentWidget; }; class OptionsTabAppearanceGeneral : public OptionsTab { Q_OBJECT public: OptionsTabAppearanceGeneral(QObject *parent); ~OptionsTabAppearanceGeneral(); QWidget *widget(); void applyOptions(); void restoreOptions(); private slots: void setData(PsiCon *, QWidget *); void chooseColor(QAbstractButton* button); void chooseFont(QAbstractButton* button); private: QWidget *w, *parentWidget; QButtonGroup *bg_color; FontLabel *le_font[4]; QButtonGroup *bg_font; }; #endif psi-0.14/src/options/opt_advanced.h0000644000175000017500000000047411305557613015430 0ustar janjan#ifndef OPT_ADVANCED_H #define OPT_ADVANCED_H #include "optionstab.h" class QWidget; class OptionsTabAdvanced : public OptionsTab { Q_OBJECT public: OptionsTabAdvanced(QObject *parent); ~OptionsTabAdvanced(); QWidget *widget(); void applyOptions(); void restoreOptions(); private: QWidget *w; }; #endif psi-0.14/src/options/opt_status.h0000644000175000017500000000145111305557613015202 0ustar janjan#ifndef OPT_STATUS_H #define OPT_STATUS_H #include #include #include #include "optionstab.h" #include "statuspreset.h" class QWidget; class OptionsTabStatus : public OptionsTab { Q_OBJECT public: OptionsTabStatus(QObject *parent); ~OptionsTabStatus(); QWidget *widget(); void applyOptions(); void restoreOptions(); void setData(PsiCon *, QWidget *parentDialog); //bool stretchable() const { return true; } private slots: void selectStatusPreset(int x); void newStatusPreset(); void removeStatusPreset(); void changeStatusPreset(); private: void setStatusPresetWidgetsEnabled(bool); QWidget *w, *parentWidget; QMap presets; QSet dirtyPresets; QStringList deletedPresets; QMap newPresets; }; #endif psi-0.14/src/options/opt_plugins.h0000644000175000017500000000074011305557613015340 0ustar janjan#ifndef OPT_PLUGINS_H #define OPT_PLUGINS_H #include "optionstab.h" class QWidget; class Options; class OptionsTabPlugins : public OptionsTab { Q_OBJECT public: OptionsTabPlugins(QObject *parent); ~OptionsTabPlugins(); QWidget *widget(); void applyOptions(Options *opt); void restoreOptions(const Options *opt); private: QWidget *w; QWidget *pluginWidget; private slots: void listPlugins(); void pluginSelected(int index); void loadToggled(int state); }; #endif psi-0.14/src/options/opt_status.cpp0000644000175000017500000002632611305557613015545 0ustar janjan#include "opt_status.h" #include "common.h" #include "iconwidget.h" #include "psioptions.h" #include #include #include #include #include #include #include #include #include #include #include #include "ui_opt_status.h" class OptStatusUI : public QWidget, public Ui::OptStatus { public: OptStatusUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabStatus //---------------------------------------------------------------------------- OptionsTabStatus::OptionsTabStatus(QObject *parent) : OptionsTab(parent, "status", "", tr("Status"), tr("Status preferences"), "psi/status") { w = 0; } OptionsTabStatus::~OptionsTabStatus() { } QWidget *OptionsTabStatus::widget() { if ( w ) return 0; w = new OptStatusUI(); OptStatusUI *d = (OptStatusUI *)w; QString s = tr("Makes Psi automatically set your status to \"away\" if your" " computer is idle for the specified amount of time."); d->ck_asAway->setWhatsThis(s); d->sb_asAway->setWhatsThis(s); s = tr("Makes Psi automatically set your status to \"extended away\" if your" " computer is idle for the specified amount of time."); d->ck_asXa->setWhatsThis(s); d->sb_asXa->setWhatsThis(s); s = tr("Makes Psi automatically set your status to \"offline\" if your" " computer is idle for the specified amount of time." " This will disconnect you from the Jabber server."); if (!PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()) { d->ck_asXa->hide(); d->sb_asXa->hide(); d->lb_asXa->hide(); } d->ck_asOffline->setWhatsThis( s); d->sb_asOffline->setWhatsThis( s); d->te_asMessage->setWhatsThis( tr("Specifies an extended message to use if you allow Psi" " to set your status automatically. See options above.")); setStatusPresetWidgetsEnabled(false); connect(d->pb_spNew, SIGNAL(clicked()), SLOT(newStatusPreset())); connect(d->pb_spDelete, SIGNAL(clicked()), SLOT(removeStatusPreset())); connect(d->cb_preset, SIGNAL(currentIndexChanged(int)), SLOT(selectStatusPreset(int))); connect(d->te_sp, SIGNAL(textChanged()), SLOT(changeStatusPreset())); connect(d->le_sp_priority, SIGNAL(textChanged(const QString&)), SLOT(changeStatusPreset())); connect(d->cb_sp_status, SIGNAL(activated(int)), SLOT(changeStatusPreset())); d->pb_spNew->setWhatsThis( tr("Press this button to create a new status message preset.")); d->pb_spDelete->setWhatsThis( tr("Press this button to delete a status message preset.")); d->cb_preset->setWhatsThis( tr("Use this list to select a status message preset" " to view or edit in the box to the bottom.")); d->te_sp->setWhatsThis( tr("You may edit the message here for the currently selected" " status message preset in the list to the above.")); d->cb_sp_status->setWhatsThis( tr("Use this to choose the status that will be assigned to this preset")); d->le_sp_priority->setWhatsThis( tr("Fill in the priority that will be assigned to this preset." " If no priority is given, the default account priority will be used.")); d->ck_askOnline->setWhatsThis( tr("Jabber allows you to put extended status messages on" " all status types. Normally, Psi does not prompt you for" " an extended message when you set your status to \"online\"." " Check this option if you want to have this prompt.")); return w; } void OptionsTabStatus::applyOptions() { if ( !w ) return; OptStatusUI *d = (OptStatusUI *)w; PsiOptions::instance()->setOption("options.status.auto-away.away-after", d->sb_asAway->value()); PsiOptions::instance()->setOption("options.status.auto-away.not-availible-after", d->sb_asXa->value()); PsiOptions::instance()->setOption("options.status.auto-away.offline-after", d->sb_asOffline->value()); PsiOptions::instance()->setOption("options.status.auto-away.use-away", d->ck_asAway->isChecked()); PsiOptions::instance()->setOption("options.status.auto-away.use-not-availible", d->ck_asXa->isChecked()); PsiOptions::instance()->setOption("options.status.auto-away.use-offline", d->ck_asOffline->isChecked()); PsiOptions::instance()->setOption("options.status.auto-away.message", d->te_asMessage->toPlainText()); foreach (QString name, deletedPresets) { QString base = PsiOptions::instance()->mapLookup("options.status.presets", name); PsiOptions::instance()->removeOption(base , true); } deletedPresets.clear(); foreach (QString name, dirtyPresets.toList() + newPresets.keys()) { StatusPreset sp; if (newPresets.contains(name)) { sp = newPresets[name]; } else { sp = presets[name]; } PsiOptions *o = PsiOptions::instance(); sp.toOptions(o); } dirtyPresets.clear(); presets.unite(newPresets); newPresets.clear(); PsiOptions::instance()->setOption("options.status.ask-for-message-on-online", d->ck_askOnline->isChecked()); PsiOptions::instance()->setOption("options.status.ask-for-message-on-offline", d->ck_askOffline->isChecked()); } void OptionsTabStatus::restoreOptions() { if ( !w ) return; OptStatusUI *d = (OptStatusUI *)w; d->sb_asAway->setMinimum(0); d->sb_asAway->setMaximum(INT_MAX); d->sb_asAway->setValue( PsiOptions::instance()->getOption("options.status.auto-away.away-after").toInt() ); d->sb_asXa->setMinimum(0); d->sb_asXa->setMaximum(INT_MAX); d->sb_asXa->setValue( PsiOptions::instance()->getOption("options.status.auto-away.not-availible-after").toInt() ); d->sb_asOffline->setMinimum(0); d->sb_asOffline->setMaximum(INT_MAX); d->sb_asOffline->setValue( PsiOptions::instance()->getOption("options.status.auto-away.offline-after").toInt() ); /*if (PsiOptions::instance()->getOption("options.status.auto-away.away-after").toInt() <= 0 ) PsiOptions::instance()->getOption("options.status.auto-away.use-away").toBool() = false; if (PsiOptions::instance()->getOption("options.status.auto-away.not-availible-after").toInt() <= 0 ) PsiOptions::instance()->getOption("options.status.auto-away.use-not-availible").toBool() = false; if(d->opt.asOffline <= 0) PsiOptions::instance()->getOption("options.status.auto-away.use-offline").toBool() = false;*/ d->ck_asAway->setChecked( PsiOptions::instance()->getOption("options.status.auto-away.use-away").toBool() ); d->ck_asXa->setChecked( PsiOptions::instance()->getOption("options.status.auto-away.use-not-availible").toBool() ); d->ck_asOffline->setChecked( PsiOptions::instance()->getOption("options.status.auto-away.use-offline").toBool() ); d->te_asMessage->setText( PsiOptions::instance()->getOption("options.status.auto-away.message").toString() ); QStringList presetNames; foreach(QVariant name, PsiOptions::instance()->mapKeyList("options.status.presets")) { QString base = PsiOptions::instance()->mapLookup("options.status.presets", name.toString()); StatusPreset sp; sp.setName(name.toString()); sp.setMessage(PsiOptions::instance()->getOption(base+".message").toString()); if (PsiOptions::instance()->getOption(base+".force-priority").toBool()) { sp.setPriority(PsiOptions::instance()->getOption(base+".priority").toInt()); } XMPP::Status status; status.setType(PsiOptions::instance()->getOption(base+".status").toString()); sp.setStatus(status.type()); presets[name.toString()] = sp; presetNames += name.toString(); } d->cb_preset->addItems(presetNames); if(d->cb_preset->count() >= 1) { d->cb_preset->setCurrentIndex(0); selectStatusPreset(0); } d->ck_askOnline->setChecked( PsiOptions::instance()->getOption("options.status.ask-for-message-on-online").toBool() ); d->ck_askOffline->setChecked( PsiOptions::instance()->getOption("options.status.ask-for-message-on-offline").toBool() ); } void OptionsTabStatus::setData(PsiCon *, QWidget *parentDialog) { parentWidget = parentDialog; } void OptionsTabStatus::selectStatusPreset(int x) { OptStatusUI *d = (OptStatusUI *)w; //noDirty = true; disconnect(d->te_sp, SIGNAL(textChanged()), 0, 0); disconnect(d->le_sp_priority, SIGNAL(textChanged(const QString&)), 0, 0); if ( x == -1 ) { setStatusPresetWidgetsEnabled(false); d->te_sp->setText(""); d->le_sp_priority->clear(); //noDirty = false; connect(d->te_sp, SIGNAL(textChanged()), SLOT(changeStatusPreset())); connect(d->le_sp_priority, SIGNAL(textChanged(const QString&)), SLOT(changeStatusPreset())); return; } StatusPreset preset; QString name = d->cb_preset->itemText(x); if (newPresets.contains(name)) { preset = newPresets[name]; } else { preset = presets[name]; } d->te_sp->setText(preset.message()); if (preset.priority().hasValue()) d->le_sp_priority->setText(QString::number(preset.priority().value())); else d->le_sp_priority->clear(); d->cb_sp_status->setStatus(preset.status()); //noDirty = false; connect(d->te_sp, SIGNAL(textChanged()), SLOT(changeStatusPreset())); connect(d->le_sp_priority, SIGNAL(textChanged(const QString&)), SLOT(changeStatusPreset())); setStatusPresetWidgetsEnabled(true); } void OptionsTabStatus::newStatusPreset() { OptStatusUI *d = (OptStatusUI *)w; QString text; while(1) { bool ok = false; text = QInputDialog::getText(parentWidget, CAP(tr("New Status Preset")), tr("Please enter a name for the new status preset:"), QLineEdit::Normal, text, &ok); if(!ok) { return; } if(text.isEmpty()) { QMessageBox::information(parentWidget, tr("Error"), tr("Can't create a blank preset!")); } else if(presets.contains(text) || newPresets.contains(text)) { QMessageBox::information(parentWidget, tr("Error"), tr("You already have a preset with that name!")); } else { break; } } newPresets[text].setName(text); d->cb_preset->addItem(text); d->cb_preset->setCurrentIndex(d->cb_preset->count()-1); selectStatusPreset(d->cb_preset->count()-1); d->te_sp->setFocus(); emit dataChanged(); } void OptionsTabStatus::removeStatusPreset() { OptStatusUI *d = (OptStatusUI *)w; int id = d->cb_preset->currentIndex(); if(id == -1) return; emit dataChanged(); QString name = d->cb_preset->itemText(id); if (newPresets.contains(name)) { newPresets.remove(name); } else { deletedPresets += d->cb_preset->itemText(id); presets.remove(d->cb_preset->itemText(id)); } d->cb_preset->removeItem(id); // select a new entry if possible if(d->cb_preset->count() == 0) { selectStatusPreset(-1); return; } if(id >= (int)d->cb_preset->count()) id = d->cb_preset->count()-1; d->cb_preset->setCurrentIndex(id); selectStatusPreset(id); } void OptionsTabStatus::changeStatusPreset() { OptStatusUI *d = (OptStatusUI *)w; int id = d->cb_preset->currentIndex(); if(id == -1) return; StatusPreset sp; sp.setMessage(d->te_sp->toPlainText()); if (d->le_sp_priority->text().isEmpty()) sp.clearPriority(); else sp.setPriority(d->le_sp_priority->text().toInt()); sp.setStatus(d->cb_sp_status->status()); QString name = d->cb_preset->itemText(id); sp.setName(name); if (newPresets.contains(name)) { newPresets[name] = sp; } else { dirtyPresets += name; presets[name] = sp; } emit dataChanged(); } void OptionsTabStatus::setStatusPresetWidgetsEnabled(bool enabled) { OptStatusUI *d = (OptStatusUI *)w; d->cb_preset->setEnabled(enabled); d->pb_spDelete->setEnabled(enabled); d->cb_sp_status->setEnabled(enabled); d->le_sp_priority->setEnabled(enabled); d->te_sp->setEnabled(enabled); } psi-0.14/src/options/opt_toolbars.h0000644000175000017500000000246411305557613015511 0ustar janjan#ifndef OPT_TOOLBARDLG_H #define OPT_TOOLBARDLG_H #include "optionstab.h" class PsiCon; class PsiToolBar; class QAction; class IconButton; class QListWidget; class QTreeWidgetItem; class QListWidgetItem; class OptionsTabToolbars : public OptionsTab { Q_OBJECT public: OptionsTabToolbars(QObject* parent); ~OptionsTabToolbars(); bool stretchable() const {return true;}; //void setCurrentToolbar(PsiToolBar *); QWidget* widget(); void applyOptions(); void restoreOptions(); private slots: void setData(PsiCon*, QWidget*); void toolbarAdd(); void toolbarDelete(); void addToolbarAction(QListWidget *, QString name, int toolbarId); void addToolbarAction(QListWidget *, const QAction *action, QString name); void toolbarSelectionChanged(int); void rebuildToolbarKeys(); void toolbarNameChanged(); void toolbarActionUp(); void toolbarActionDown(); void toolbarAddAction(); void toolbarRemoveAction(); void toolbarDataChanged(); QString actionName(const QAction *a); void toolbarPosition(); void selAct_selectionChanged(QListWidgetItem *); void avaAct_selectionChanged(QTreeWidgetItem *); void toolbarPositionApply(); signals: void dataChanged(); private: void updateArrows(); QWidget *w; QWidget *parent; PsiCon *psi; bool noDirty; IconButton *pb_apply; class Private; Private *p; }; #endif psi-0.14/src/options/opt_toolbars.cpp0000644000175000017500000004025011305557613016037 0ustar janjan#include "opt_toolbars.h" #include "psicon.h" #include "common.h" #include "iconwidget.h" #include "psitoolbar.h" #include "iconaction.h" #include "psiactionlist.h" #include "psioptions.h" #include "ui_opt_lookfeel_toolbars.h" #include #include #include #include #include #include #include #include //Added by qt3to4: #include #include #include #include class LookFeelToolbarsUI : public QWidget, public Ui::LookFeelToolbars { public: LookFeelToolbarsUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabToolbars //---------------------------------------------------------------------------- class OptionsTabToolbars::Private { public: QMap toolbars; PsiActionList::ActionsType class2id() { int ret = (int)PsiActionList::Actions_Common; ret |= (int)PsiActionList::Actions_MainWin; return (PsiActionList::ActionsType)ret; } }; OptionsTabToolbars::OptionsTabToolbars(QObject *parent) : OptionsTab(parent, "toolbars", "", tr("Toolbars"), tr("Configure Psi toolbars"), "psi/toolbars") { w = 0; p = new Private(); noDirty = false; } QWidget *OptionsTabToolbars::widget() { if (w) return 0; w = new LookFeelToolbarsUI(); LookFeelToolbarsUI *d = (LookFeelToolbarsUI*) w; connect(d->pb_addToolbar, SIGNAL(clicked()), SLOT(toolbarAdd())); connect(d->pb_deleteToolbar, SIGNAL(clicked()), SLOT(toolbarDelete())); connect(d->cb_toolbars, SIGNAL(activated(int)), SLOT(toolbarSelectionChanged(int))); connect(d->le_toolbarName, SIGNAL(textChanged(const QString &)), SLOT(toolbarNameChanged())); // connect(d->pb_toolbarPosition, SIGNAL(clicked()), SLOT(toolbarPosition())); connect(d->tb_up, SIGNAL(clicked()), SLOT(toolbarActionUp())); connect(d->tb_down, SIGNAL(clicked()), SLOT(toolbarActionDown())); connect(d->tb_right, SIGNAL(clicked()), SLOT(toolbarAddAction())); connect(d->tb_left, SIGNAL(clicked()), SLOT(toolbarRemoveAction())); connect(d->ck_toolbarOn, SIGNAL(toggled(bool)), SLOT(toolbarDataChanged())); connect(d->ck_toolbarLocked, SIGNAL(toggled(bool)), SLOT(toolbarDataChanged())); // connect(d->ck_toolbarStretch, SIGNAL(toggled(bool)), SLOT(toolbarDataChanged())); connect(d->lw_selectedActions, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), SLOT(selAct_selectionChanged(QListWidgetItem *))); connect(d->tw_availActions, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(avaAct_selectionChanged(QTreeWidgetItem *))); connect(d->pb_deleteToolbar, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->tb_up, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->tb_down, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->tb_left, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->tb_right, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->pb_addToolbar, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->pb_deleteToolbar, SIGNAL(clicked()), SIGNAL(dataChanged())); d->tw_availActions->header()->hide(); return w; // TODO: add QWhatsThis to all widgets /* QFrame *line = new QFrame( this ); line->setFrameShape( QFrame::HLine ); line->setFrameShadow( QFrame::Sunken ); line->setFrameShape( QFrame::HLine ); vbox->addWidget( line ); QHBoxLayout *hbox = new QHBoxLayout( 0, 0, 6 ); vbox->addLayout(hbox); QSpacerItem *spacer = new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); hbox->addItem( spacer ); IconButton *pb_ok = new IconButton( this ); hbox->addWidget( pb_ok ); pb_ok->setText( tr("&OK") ); connect(pb_ok, SIGNAL(clicked()), SLOT(doApply())); connect(pb_ok, SIGNAL(clicked()), SLOT(accept())); //pb_apply = 0; pb_apply = new IconButton( this ); hbox->addWidget( pb_apply ); pb_apply->setText( tr("&Apply") ); connect(pb_apply, SIGNAL(clicked()), SLOT(doApply())); pb_apply->setEnabled(false); IconButton *pb_cancel = new IconButton( this ); hbox->addWidget( pb_cancel ); pb_cancel->setText( tr("&Cancel") ); connect(pb_cancel, SIGNAL(clicked()), SLOT(reject())); restoreOptions( &option ); resize( minimumSize() );*/ } OptionsTabToolbars::~OptionsTabToolbars() { delete p; } /** * setData is called by the OptionsDlg private, after calling * the constructor, to assign the PsiCon object and the parent window * to all tabs. * /par psi_: PsiCon* object to apply the changes when needed * /par parent_: QWidget which is parent from the current object */ void OptionsTabToolbars::setData(PsiCon * psi_, QWidget *parent_) { // the Psi con object is needed to apply the changes // the parent object is needed to show some popups psi = psi_; parent = parent_; } /*void OptionsTabToolbars::setCurrentToolbar(PsiToolBar *t) { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; if ( pb_apply->isEnabled() ) return; QMap::Iterator it = p->toolbars.begin(); for ( ; it != p->toolbars.end(); ++it ) { if ( it.data().group == t->group() && it.data().index == t->groupIndex() ) { d->cb_toolbars->setCurrentIndex( it.key() ); toolbarSelectionChanged( it.key() ); break; } } }*/ void OptionsTabToolbars::applyOptions() { if (!w) return; PsiOptions *o = PsiOptions::instance(); o->removeOption("options.ui.contactlist.toolbars", true); QMap::Iterator it = p->toolbars.begin(); for (; it != p->toolbars.end(); ++it) { PsiToolBar::structToOptions(o, it.value()); } } void OptionsTabToolbars::restoreOptions() { if (!w) return; LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; PsiOptions *o = PsiOptions::instance(); QStringList toolbarBases = o->getChildOptionNames("options.ui.contactlist.toolbars", true, true); foreach(QString base, toolbarBases) { ToolbarPrefs tb; tb.id = o->getOption(base + ".key").toString(); tb.name = o->getOption(base + ".name").toString(); tb.on = o->getOption(base + ".visible").toBool(); tb.locked = o->getOption(base + ".locked").toBool(); // tb.stretchable = o->getOption(base + ".stretchable").toBool(); tb.dock = (Qt3Dock)o->getOption(base + ".dock.position").toInt(); //FIXME // tb.index = o->getOption(base + ".dock.index").toInt(); tb.nl = o->getOption(base + ".dock.nl").toBool(); // tb.extraOffset = o->getOption(base + ".dock.extra-offset").toInt(); tb.keys = o->getOption(base + ".actions").toStringList(); p->toolbars[base] = tb; d->cb_toolbars->addItem(tb.name, base); } if (d->cb_toolbars->count() > 0) { d->cb_toolbars->setCurrentIndex(0); toolbarSelectionChanged(0); } else toolbarSelectionChanged(-1); } //---------------------------------------------------------------------------- void OptionsTabToolbars::toolbarAdd() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; ToolbarPrefs tb; int j = 0; bool ok; do { ok = true; tb.name = QObject::tr("").arg(j++); foreach(ToolbarPrefs other, p->toolbars) { if (other.name == tb.name) { ok = false; break; } } } while (!ok); tb.on = false; tb.locked = false; // tb.stretchable = false; tb.keys.clear(); tb.dock = Qt3Dock_Top; // tb.index = i; tb.nl = true; // tb.extraOffset = 0; tb.dirty = true; QString base; j = 0; do { ok = true; base = ".." + QString::number(j++); } while (p->toolbars.keys().contains(base)); p->toolbars[base] = tb; d->cb_toolbars->addItem(tb.name, base); d->cb_toolbars->setCurrentIndex(d->cb_toolbars->count() - 1); toolbarSelectionChanged(d->cb_toolbars->currentIndex()); d->le_toolbarName->setFocus(); } void OptionsTabToolbars::toolbarDelete() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; int n = d->cb_toolbars->currentIndex(); QString base = d->cb_toolbars->itemData(n).toString(); noDirty = true; toolbarSelectionChanged(-1); p->toolbars.remove(base); d->cb_toolbars->removeItem(d->cb_toolbars->findData(base)); noDirty = false; toolbarSelectionChanged(d->cb_toolbars->currentIndex()); } void OptionsTabToolbars::addToolbarAction(QListWidget *parent, QString name, int toolbarId) { ActionList actions = psi->actionList()->suitableActions((PsiActionList::ActionsType)toolbarId); const QAction *action = (QAction *)actions.action(name); if (!action) return; addToolbarAction(parent, action, name); } void OptionsTabToolbars::addToolbarAction(QListWidget *parent, const QAction *action, QString name) { QListWidgetItem *item = new QListWidgetItem(parent); QString n = actionName(action); if (!action->whatsThis().isEmpty()) n += " - " + action->whatsThis(); item->setText(n); item->setData(Qt::UserRole, name); item->setIcon(action->icon()); item->setHidden(!action->isVisible()); } void OptionsTabToolbars::toolbarSelectionChanged(int item) { if (noDirty) return; int n = item; // PsiToolBar *toolBar = 0; // if ( item != -1 ) // toolBar = psi->findToolBar( p->toolbars[n].group, p->toolbars[n].index ); bool customizeable = true; bool moveable = true; LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; bool enable = (item == -1) ? false : true; d->le_toolbarName->setEnabled(enable); // d->pb_toolbarPosition->setEnabled(enable && moveable); d->ck_toolbarOn->setEnabled(enable); d->ck_toolbarLocked->setEnabled(enable && moveable); // d->ck_toolbarStretch->setEnabled(enable && moveable); d->lw_selectedActions->setEnabled(enable && customizeable); d->tw_availActions->setEnabled(enable && customizeable); d->tb_up->setEnabled(enable && customizeable); d->tb_down->setEnabled(enable && customizeable); d->tb_left->setEnabled(enable && customizeable); d->tb_right->setEnabled(enable && customizeable); d->pb_deleteToolbar->setEnabled(enable); d->cb_toolbars->setEnabled(enable); d->tw_availActions->clear(); d->lw_selectedActions->clear(); if (!enable) { d->le_toolbarName->setText(""); return; } noDirty = true; QString base = d->cb_toolbars->itemData(n).toString(); ToolbarPrefs tb; tb = p->toolbars[base]; d->le_toolbarName->setText(tb.name); d->ck_toolbarOn->setChecked(tb.on); d->ck_toolbarLocked->setChecked(tb.locked || !moveable); // d->ck_toolbarStretch->setChecked(tb.stretchable); { // Fill the TreeWidget with toolbar-specific actions QTreeWidget *tw = d->tw_availActions; QTreeWidgetItem *lastRoot = 0; foreach(ActionList* actionList, psi->actionList()->actionLists(p->class2id())) { QTreeWidgetItem *root = new QTreeWidgetItem(tw, lastRoot); lastRoot = root; root->setText(0, actionList->name()); root->setData(0, Qt::UserRole, QString("")); root->setExpanded(true); QTreeWidgetItem *last = 0; QStringList actionNames = actionList->actions(); QStringList::Iterator it2 = actionNames.begin(); for (; it2 != actionNames.end(); ++it2) { IconAction *action = actionList->action(*it2); if (!action->isVisible()) continue; QTreeWidgetItem *item = new QTreeWidgetItem(root, last); last = item; QString n = actionName((QAction *)action); if (!action->whatsThis().isEmpty()) { n += " - " + action->whatsThis(); } item->setText(0, n); item->setIcon(0, action->icon()); item->setData(0, Qt::UserRole, action->objectName()); } } tw->resizeColumnToContents(0); } QStringList::Iterator it = tb.keys.begin(); for (; it != tb.keys.end(); ++it) { addToolbarAction(d->lw_selectedActions, *it, p->class2id()); } updateArrows(); noDirty = false; } void OptionsTabToolbars::rebuildToolbarKeys() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; if (!d->cb_toolbars->count()) return; int n = d->cb_toolbars->currentIndex(); QStringList keys; int count = d->lw_selectedActions->count(); for (int i = 0; i < count; i++) { keys << d->lw_selectedActions->item(i)->data(Qt::UserRole).toString(); } QString base = d->cb_toolbars->itemData(n).toString(); p->toolbars[base].keys = keys; emit dataChanged(); } void OptionsTabToolbars::updateArrows() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; bool up = false, down = false, left = false, right = false; if (d->tw_availActions->currentItem() && !d->tw_availActions->currentItem()->data(0, Qt::UserRole).toString().isEmpty()) right = true; QListWidgetItem *item = d->lw_selectedActions->currentItem(); if (item) { left = true; // get numeric index of item int n = d->lw_selectedActions->row(item); int i = n; while (--i >= 0) { if (!d->lw_selectedActions->item(i)->isHidden()) { up = true; break; } } i = n; while (++i < d->lw_selectedActions->count()) { if (!d->lw_selectedActions->item(i)->isHidden()) { down = true; break; } } } d->tb_up->setEnabled(up); d->tb_down->setEnabled(down); d->tb_left->setEnabled(left); d->tb_right->setEnabled(right); } void OptionsTabToolbars::toolbarNameChanged() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; if (!d->cb_toolbars->count()) return; QString name = d->le_toolbarName->text(); int n = d->cb_toolbars->currentIndex(); QString base = d->cb_toolbars->itemData(n).toString(); p->toolbars[base].name = name; d->cb_toolbars->setItemText(d->cb_toolbars->findData(base), name); emit dataChanged(); } void OptionsTabToolbars::toolbarActionUp() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; QListWidgetItem *item = d->lw_selectedActions->currentItem(); if (!item) return; int row = d->lw_selectedActions->row(item); if (row > 0) { d->lw_selectedActions->takeItem(row); --row; while (row > 0 && d->lw_selectedActions->item(row)->isHidden()) { --row; } d->lw_selectedActions->insertItem(row, item); d->lw_selectedActions->setCurrentItem(item); } rebuildToolbarKeys(); updateArrows(); } void OptionsTabToolbars::toolbarActionDown() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; QListWidgetItem *item = d->lw_selectedActions->currentItem(); if (!item) return; int row = d->lw_selectedActions->row(item); if (row < d->lw_selectedActions->count()) { d->lw_selectedActions->takeItem(row); ++row; while (row < d->lw_selectedActions->count() && d->lw_selectedActions->item(row)->isHidden()) { ++row; } d->lw_selectedActions->insertItem(row, item); d->lw_selectedActions->setCurrentItem(item); } rebuildToolbarKeys(); updateArrows(); } void OptionsTabToolbars::toolbarAddAction() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; QTreeWidgetItem *item = d->tw_availActions->currentItem(); if (!item || item->data(0, Qt::UserRole).toString().isEmpty()) return; addToolbarAction(d->lw_selectedActions, item->data(0, Qt::UserRole).toString(), p->class2id()); rebuildToolbarKeys(); updateArrows(); } void OptionsTabToolbars::toolbarRemoveAction() { LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; QListWidgetItem *item = d->lw_selectedActions->currentItem(); if (!item) return; delete item; rebuildToolbarKeys(); updateArrows(); } void OptionsTabToolbars::toolbarDataChanged() { if (noDirty) return; LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; if (!d->cb_toolbars->count()) return; int n = d->cb_toolbars->currentIndex(); QString base = d->cb_toolbars->itemData(n).toString(); ToolbarPrefs tb; tb = p->toolbars[base]; tb.dirty = true; tb.name = d->le_toolbarName->text(); tb.on = d->ck_toolbarOn->isChecked(); tb.locked = d->ck_toolbarLocked->isChecked(); // tb.stretchable = d->ck_toolbarStretch->isChecked(); p->toolbars[base] = tb; emit dataChanged(); } QString OptionsTabToolbars::actionName(const QAction *a) { QString n = a->text(), n2; for (int i = 0; i < (int)n.length(); i++) { if (n[i] == '&' && n[i+1] != '&') continue; else if (n[i] == '&' && n[i+1] == '&') n2 += '&'; else n2 += n[i]; } return n2; } void OptionsTabToolbars::toolbarPosition() { #if 0 LEGOPTFIXME LookFeelToolbarsUI *d = (LookFeelToolbarsUI *)w; if (!d->cb_toolbars->count()) return; int n = d->cb_toolbars->currentIndex(); PositionOptionsTabToolbars *posTbDlg = new PositionOptionsTabToolbars(w, &LEGOPTS.toolbars["mainWin"][n], n); connect(posTbDlg, SIGNAL(applyPressed()), SLOT(toolbarPositionApply())); posTbDlg->exec(); delete posTbDlg; #endif } void OptionsTabToolbars::toolbarPositionApply() { #if 0 LEGOPTFIXME emit dataChanged(); LEGOPTS.toolbars = LEGOPTS.toolbars; psi->buildToolbars(); #endif } void OptionsTabToolbars::selAct_selectionChanged(QListWidgetItem *) { updateArrows(); } void OptionsTabToolbars::avaAct_selectionChanged(QTreeWidgetItem *) { updateArrows(); } psi-0.14/src/options/opt_sound.h0000644000175000017500000000131211305557613015003 0ustar janjan#ifndef OPT_SOUND_H #define OPT_SOUND_H #include #include "optionstab.h" class QWidget; class QLineEdit; class QButtonGroup; class QAbstractButton; class OptionsTabSound : public OptionsTab { Q_OBJECT public: OptionsTabSound(QObject *parent); ~OptionsTabSound(); QWidget *widget(); void applyOptions(); void restoreOptions(); private slots: void chooseSoundEvent(QAbstractButton*); void previewSoundEvent(QAbstractButton*); void soundReset(); void setData(PsiCon *, QWidget *); private: QWidget *w, *parentWidget; QList sounds_; QMap modify_buttons_; QMap play_buttons_; QButtonGroup *bg_se, *bg_sePlay; }; #endif psi-0.14/src/options/opt_shortcuts.h0000644000175000017500000000327611305557613015724 0ustar janjan/* * * opt_shortcuts.h - an OptionsTab for setting the Keyboard Shortcuts of Psi * Copyright (C) 2006 Cestonaro Thilo * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef OPT_SHORTCUTS_H #define OPT_SHORTCUTS_H #include "optionstab.h" #include class QTreeWidgetItem; class QWidget; class PsiOptions; class OptionsTabShortcuts : public OptionsTab { Q_OBJECT public: OptionsTabShortcuts(QObject *parent); ~OptionsTabShortcuts(); QWidget *widget(); void applyOptions(); void restoreOptions(); enum Kind { TopLevelItem = 1, ShortcutItem, KeyItem }; bool stretchable() const {return true;}; private slots: void onAdd(); void onRemove(); void onEdit(); void onRestoreDefaults(); void onItemDoubleClicked(QTreeWidgetItem *item, int column); void onItemSelectionChanged(); void onNewShortcutKey(const QKeySequence& key); private: void addTo(QTreeWidgetItem *shortcutItem); void grep(); QString translateShortcut(QString comment); void readShortcuts(const PsiOptions *options); QWidget *w; }; #endif psi-0.14/src/options/opt_appearance.cpp0000644000175000017500000003460511305557613016320 0ustar janjan#include "opt_appearance.h" #include "opt_iconset.h" #include "common.h" #include "iconwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_opt_appearance.h" #include "ui_opt_appearance_misc.h" #include "psioptions.h" class OptAppearanceUI : public QWidget, public Ui::OptAppearance { public: OptAppearanceUI() : QWidget() { setupUi(this); } }; class OptAppearanceMiscUI : public QWidget, public Ui::OptAppearanceMisc { public: OptAppearanceMiscUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // FontLabel //---------------------------------------------------------------------------- FontLabel::FontLabel(QWidget *parent, const char *name) : QLineEdit(parent) { setObjectName(name); setReadOnly(true); QPalette palette = this->palette(); palette.setColor(backgroundRole(), parent->palette().color(parent->backgroundRole())); setPalette(palette); m_defaultHeight = QLineEdit::sizeHint().height(); } void FontLabel::setFont(QString fontName) { QFont f; f.fromString(fontName); m_font = fontName; setText( tr("%1 %2").arg( f.family() ).arg( f.pointSize() ) ); QLineEdit::setFont(f); } QString FontLabel::fontName() const { return m_font; } QSize FontLabel::sizeHint() const { return QSize(QLineEdit::sizeHint().width(), m_defaultHeight); } //---------------------------------------------------------------------------- // OptionsTabAppearance //---------------------------------------------------------------------------- OptionsTabAppearance::OptionsTabAppearance(QObject *parent) : MetaOptionsTab(parent, "appearance", "", tr("Appearance"), tr("Psi's appearance"), "psi/appearance") { addTab( new OptionsTabAppearanceGeneral(this) ); addTab( new OptionsTabIconsetEmoticons(this) ); addTab( new OptionsTabIconsetRoster(this) ); addTab( new OptionsTabIconsetSystem(this) ); addTab( new OptionsTabAppearanceMisc(this) ); } //---------------------------------------------------------------------------- // OptionsTabAppearanceMisc //---------------------------------------------------------------------------- OptionsTabAppearanceMisc::OptionsTabAppearanceMisc(QObject *parent) : OptionsTab(parent, "appearance_misc", "", tr("Misc."), tr("Miscellaneous Settings")) { w = 0; } OptionsTabAppearanceMisc::~OptionsTabAppearanceMisc() { } QWidget *OptionsTabAppearanceMisc::widget() { if ( w ) return 0; w = new OptAppearanceMiscUI(); return w; } void OptionsTabAppearanceMisc::applyOptions() { if ( !w ) return; OptAppearanceMiscUI *d = (OptAppearanceMiscUI *)w; PsiOptions::instance()->setOption("options.ui.look.contactlist.use-slim-group-headings", d->ck_newHeadings->isChecked()); PsiOptions::instance()->setOption("options.ui.look.contactlist.use-outlined-group-headings", d->ck_outlineHeadings->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.opacity", d->sl_rosterop->value()); PsiOptions::instance()->setOption("options.ui.chat.opacity", d->sl_chatdlgop->value()); } void OptionsTabAppearanceMisc::restoreOptions() { if ( !w ) return; OptAppearanceMiscUI *d = (OptAppearanceMiscUI *)w; d->ck_newHeadings->setChecked(PsiOptions::instance()->getOption("options.ui.look.contactlist.use-slim-group-headings").toBool()); d->ck_outlineHeadings->setChecked(PsiOptions::instance()->getOption("options.ui.look.contactlist.use-outlined-group-headings").toBool()); d->sl_rosterop->setValue(PsiOptions::instance()->getOption("options.ui.contactlist.opacity").toInt()); d->sl_chatdlgop->setValue(PsiOptions::instance()->getOption("options.ui.chat.opacity").toInt()); } void OptionsTabAppearanceMisc::setData(PsiCon *, QWidget *parentDialog) { parentWidget = parentDialog; } //---------------------------------------------------------------------------- // OptionsTabAppearanceGeneral: Fonts & Colours //---------------------------------------------------------------------------- OptionsTabAppearanceGeneral::OptionsTabAppearanceGeneral(QObject *parent) : OptionsTab(parent, "appearance_general", "", tr("Fonts && Colors"), tr("Fonts && Color Settings")) { w = 0; bg_font = 0; bg_color = 0; } OptionsTabAppearanceGeneral::~OptionsTabAppearanceGeneral() { if ( bg_font ) delete bg_font; if ( bg_color ) delete bg_color; } static QPixmap color2pixmap(QColor c) // taken from opt_general.cpp { QPixmap pix(16, 16); QPainter p(&pix); p.fillRect(0, 0, pix.width(), pix.height(), QBrush(c)); p.setPen( QColor(0, 0, 0) ); p.drawRect(0, 0, pix.width(), pix.height()); p.end(); return pix; } QWidget *OptionsTabAppearanceGeneral::widget() { if ( w ) return 0; w = new OptAppearanceUI(); OptAppearanceUI *d = (OptAppearanceUI *)w; le_font[0] = d->le_fRoster; le_font[1] = d->le_fMessage; le_font[2] = d->le_fChat; le_font[3] = d->le_fPopup; bg_font = new QButtonGroup; bg_font->addButton(d->pb_fRoster); bg_font->addButton(d->pb_fMessage); bg_font->addButton(d->pb_fChat); bg_font->addButton(d->pb_fPopup); connect(bg_font, SIGNAL(buttonClicked(QAbstractButton*)), SLOT(chooseFont(QAbstractButton*))); le_font[0]->setWhatsThis( tr("Specifies the font style for the main window.")); le_font[1]->setWhatsThis( tr("Specifies the font style for message windows.")); le_font[2]->setWhatsThis( tr("Specifies the font style for chat windows.")); le_font[3]->setWhatsThis( tr("Specifies the font style for popup windows.")); d->pb_fRoster->setWhatsThis( tr("Selects a font for the roster window using the font selection dialog.")); d->pb_fMessage->setWhatsThis( tr("Selects a font for message windows using the font selection dialog.")); d->pb_fChat->setWhatsThis( tr("Selects a font for chat windows using the font selection dialog.")); bg_color = new QButtonGroup; bg_color->addButton(d->pb_cOnline); bg_color->addButton(d->pb_cOffline); bg_color->addButton(d->pb_cAway); bg_color->addButton(d->pb_cDND); bg_color->addButton(d->pb_cProfileFore); bg_color->addButton(d->pb_cProfileBack); bg_color->addButton(d->pb_cGroupFore); bg_color->addButton(d->pb_cGroupBack); bg_color->addButton(d->pb_cListBack); bg_color->addButton(d->pb_cAnimFront); bg_color->addButton(d->pb_cAnimBack); bg_color->addButton(d->pb_cStatus); bg_color->addButton(d->pb_cMessageSent); bg_color->addButton(d->pb_cMessageReceived); bg_color->addButton(d->pb_cSysMsg); connect(bg_color, SIGNAL(buttonClicked(QAbstractButton*)), SLOT(chooseColor(QAbstractButton*))); QString s = tr("Specifies the text color for a contact name in the main window when that user is \"%1\"."); d->pb_cOnline->setWhatsThis( s.arg(tr("online"))); d->pb_cOffline->setWhatsThis( s.arg(tr("offline"))); d->pb_cAway->setWhatsThis( s.arg(tr("away"))); d->pb_cDND->setWhatsThis( s.arg(tr("do not disturb"))); d->pb_cStatus->setWhatsThis( s.arg(tr("Status message"))); d->pb_cProfileBack->setWhatsThis( tr("Specifies the background color for an account name in the main window.")); d->pb_cGroupBack->setWhatsThis( tr("Specifies the background color for a group name in the main window.")); d->pb_cListBack->setWhatsThis( tr("Specifies the background color for the main window.")); d->pb_cAnimFront->setWhatsThis( tr("Specifies the foreground animation color for nicks.")); d->pb_cAnimBack->setWhatsThis( tr("Specifies the background animation color for nicks.")); d->pb_cMessageSent->setWhatsThis( tr("Specifies the color for sent messages in chat and history windows.")); d->pb_cMessageReceived->setWhatsThis( tr("Specifies the color for received messages in chat and history windows.")); d->pb_cSysMsg->setWhatsThis( tr("Specifies the color for informational messages in chat windows, like status changes and offline messages.")); // Avatars //QWhatsThis::add(d->ck_avatarsChatdlg, // tr("Toggles displaying of avatars in the chat dialog")); if (PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool()) { d->tl_cStatus->hide(); d->pb_cStatus->hide(); } return w; } static QColor getColor(QAbstractButton *button) { return button->property("psi_color").value(); } void OptionsTabAppearanceGeneral::applyOptions() { if ( !w ) return; OptAppearanceUI *d = (OptAppearanceUI *)w; //LEGOPTS.avatarsChatdlgEnabled = d->ck_avatarsChatdlg->isChecked(); // Avatars PsiOptions::instance()->setOption("options.ui.look.font.contactlist", d->le_fRoster->fontName()); PsiOptions::instance()->setOption("options.ui.look.font.message", d->le_fMessage->fontName()); PsiOptions::instance()->setOption("options.ui.look.font.chat", d->le_fChat->fontName()); PsiOptions::instance()->setOption("options.ui.look.font.passive-popup", d->le_fPopup->fontName()); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.status.online", getColor(d->pb_cOnline)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.status.offline", getColor(d->pb_cOffline)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.status.away", getColor(d->pb_cAway)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.status.do-not-disturb", getColor(d->pb_cDND)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.profile.header-foreground", getColor(d->pb_cProfileFore)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.profile.header-background", getColor(d->pb_cProfileBack)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.grouping.header-foreground", getColor(d->pb_cGroupFore)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.grouping.header-background", getColor(d->pb_cGroupBack)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.background", getColor(d->pb_cListBack)); PsiOptions::instance()->setOption("options.ui.look.contactlist.status-change-animation.color1", getColor(d->pb_cAnimFront)); PsiOptions::instance()->setOption("options.ui.look.contactlist.status-change-animation.color2", getColor(d->pb_cAnimBack)); PsiOptions::instance()->setOption("options.ui.look.colors.contactlist.status-messages", getColor(d->pb_cStatus)); PsiOptions::instance()->setOption("options.ui.look.colors.messages.received", getColor(d->pb_cMessageReceived)); PsiOptions::instance()->setOption("options.ui.look.colors.messages.sent", getColor(d->pb_cMessageSent)); PsiOptions::instance()->setOption("options.ui.look.colors.messages.informational", getColor(d->pb_cSysMsg)); } static void restoreColor(QToolButton *button, QColor c) { button->setProperty("psi_color", c); button->setIcon(color2pixmap(c)); } void OptionsTabAppearanceGeneral::restoreOptions() { if ( !w ) return; OptAppearanceUI *d = (OptAppearanceUI *)w; //d->ck_avatarsChatdlg->setChecked( LEGOPTS.avatarsChatdlgEnabled ); // Avatars d->le_fRoster->setFont(PsiOptions::instance()->getOption("options.ui.look.font.contactlist").toString()); d->le_fMessage->setFont(PsiOptions::instance()->getOption("options.ui.look.font.message").toString()); d->le_fChat->setFont(PsiOptions::instance()->getOption("options.ui.look.font.chat").toString()); d->le_fPopup->setFont(PsiOptions::instance()->getOption("options.ui.look.font.passive-popup").toString()); restoreColor(d->pb_cOnline, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.online").value()); restoreColor(d->pb_cOffline, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.offline").value()); restoreColor(d->pb_cAway, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.away").value()); restoreColor(d->pb_cDND, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.do-not-disturb").value()); restoreColor(d->pb_cProfileFore, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.profile.header-foreground").value()); restoreColor(d->pb_cProfileBack, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.profile.header-background").value()); restoreColor(d->pb_cGroupFore, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-foreground").value()); restoreColor(d->pb_cGroupBack, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value()); restoreColor(d->pb_cListBack, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.background").value()); restoreColor(d->pb_cAnimFront, PsiOptions::instance()->getOption("options.ui.look.contactlist.status-change-animation.color1").value()); restoreColor(d->pb_cAnimBack, PsiOptions::instance()->getOption("options.ui.look.contactlist.status-change-animation.color2").value()); restoreColor(d->pb_cStatus, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status-messages").value()); restoreColor(d->pb_cMessageReceived, PsiOptions::instance()->getOption("options.ui.look.colors.messages.received").value()); restoreColor(d->pb_cMessageSent, PsiOptions::instance()->getOption("options.ui.look.colors.messages.sent").value()); restoreColor(d->pb_cSysMsg, PsiOptions::instance()->getOption("options.ui.look.colors.messages.informational").value()); } void OptionsTabAppearanceGeneral::setData(PsiCon *, QWidget *parentDialog) { parentWidget = parentDialog; } void OptionsTabAppearanceGeneral::chooseFont(QAbstractButton* button) { bool ok; QFont font; int x = (bg_font->buttons()).indexOf(button); font.fromString( le_font[x]->fontName() ); // ensure we don't use the new native font dialog on mac with Qt 4.5, // since it was broken last we checked (qt task #252000) #if QT_VERSION >= 0x040500 QString fnt = QFontDialog::getFont(&ok, font, parentWidget, QString(), QFontDialog::DontUseNativeDialog).toString(); #else QString fnt = QFontDialog::getFont(&ok, font, parentWidget).toString(); #endif le_font[x]->setFont(fnt); if(ok) emit dataChanged(); } void OptionsTabAppearanceGeneral::chooseColor(QAbstractButton* button) { QColor c; //int x = (bg_color->buttons()).indexOf(button); c = getColor(button); c = QColorDialog::getColor(c, parentWidget); if(c.isValid()) { button->setProperty("psi_color", c); //((QPushButton*) bg_color->buttons()[x])->setIcon(name2color(o->color[x].name())); button->setIcon(color2pixmap(c)); emit dataChanged(); } } psi-0.14/src/options/optionsdlg.h0000644000175000017500000000234511305557613015162 0ustar janjan/* * optionsdlg.cpp * Copyright (C) 2003-2009 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef OPTIONSDLG_H #define OPTIONSDLG_H #include "ui_ui_options.h" #include class PsiCon; class OptionsDlg : public QDialog, public Ui::OptionsUI { Q_OBJECT public: OptionsDlg(PsiCon *, QWidget *parent = 0); ~OptionsDlg(); void openTab(const QString& id); signals: void applyOptions(); private slots: void doOk(); void doApply(); public: class Private; private: Private *d; friend class Private; QPushButton* pb_apply; }; #endif psi-0.14/src/options/opt_lookfeel_toolbars.ui0000644000175000017500000002323511305557613017556 0ustar janjan LookFeelToolbars 0 0 315 256 LookFeelToolbarsUI 9 6 0 6 Toolbar: 3 0 0 0 Qt::Horizontal QSizePolicy::Maximum 30 20 &Add Alt+A &Delete Alt+D QFrame::HLine QFrame::Sunken Qt::Horizontal 0 6 Name: 0 6 Specifies, whether toolbar is enabled and visible. Enabled Locked Qt::Horizontal QSizePolicy::Expanding 40 20 QFrame::HLine QFrame::Sunken Qt::Horizontal 0 6 Qt::Vertical QSizePolicy::Expanding 25 101 0 0 0 0 ... psi/arrowUp QAbstractItemView::NoEditTriggers false 0 0 0 0 ... psi/arrowDown 0 0 0 0 ... psi/arrowRight Qt::Vertical QSizePolicy::Expanding 25 91 A&vailable actions: tw_availActions 0 0 0 0 ... psi/arrowLeft QAbstractItemView::NoEditTriggers false false 1 Curr&ent actions: lw_selectedActions qPixmapFromMimeSource IconToolButton QToolButton
icontoolbutton.h
IconButton QPushButton
iconbutton.h
cb_toolbars pb_addToolbar pb_deleteToolbar le_toolbarName ck_toolbarOn ck_toolbarLocked
psi-0.14/src/options/opt_tree.cpp0000644000175000017500000000154411305557613015154 0ustar janjan#include #include #include "opt_tree.h" #include "psioptionseditor.h" OptionsTabTree::OptionsTabTree(QObject *parent) : OptionsTab(parent, "tree", "", tr("Advanced"), tr("Options for advanced users"), "psi/advanced") { w = 0; } OptionsTabTree::~OptionsTabTree() { } QWidget *OptionsTabTree::widget() { if (w) { return 0; } w = new QWidget(); //w->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); QVBoxLayout* layout = new QVBoxLayout(w); //layout->setSpacing(0); layout->setMargin(0); QLabel *lb = new QLabel(tr("Please note: This editor will change the options " "directly. Pressing Cancel will not revert these changes."), w); lb->setWordWrap(true); layout->addWidget(lb); PsiOptionsEditor *poe = new PsiOptionsEditor(w); layout->addWidget(poe); poe->show(); return w; } psi-0.14/src/options/opt_chat.cpp0000644000175000017500000001672311305557613015141 0ustar janjan#include "opt_chat.h" #include "common.h" #include "iconwidget.h" #include #include #include #include #include #include "ui_opt_chat.h" #include "shortcutmanager.h" #include "psioptions.h" class OptChatUI : public QWidget, public Ui::OptChat { public: OptChatUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabChat //---------------------------------------------------------------------------- OptionsTabChat::OptionsTabChat(QObject *parent) : OptionsTab(parent, "chat", "", tr("Chat"), tr("Configure the chat dialog"), "psi/start-chat") { w = 0; bg_delChats = bg_defAct = 0; } OptionsTabChat::~OptionsTabChat() { if ( bg_defAct ) delete bg_defAct; if ( bg_delChats ) delete bg_delChats; } QWidget *OptionsTabChat::widget() { if ( w ) return 0; w = new OptChatUI(); OptChatUI *d = (OptChatUI *)w; bg_defAct = new QButtonGroup; bg_defAct->setExclusive( true ); bg_defAct->addButton( d->rb_defActMsg); bg_defAct->addButton( d->rb_defActChat); bg_delChats = new QButtonGroup; bg_delChats->setExclusive( true ); bg_delChats->addButton( d->rb_delChatsClose); bg_delChats->addButton( d->rb_delChatsHour); bg_delChats->addButton( d->rb_delChatsDay); bg_delChats->addButton( d->rb_delChatsNever); connect(d->ck_tabChats, SIGNAL(toggled(bool)), d->cb_tabGrouping, SLOT(setEnabled(bool))); d->rb_defActMsg->setWhatsThis( tr("Make the default action open a normal message window.")); d->rb_defActChat->setWhatsThis( tr("Make the default action open a chat window.")); d->ck_chatSoftReturn->setWhatsThis( tr("

When checked, pressing Enter in a chat window will send your message." " You must use Shift+Enter in order to create a newline in the chat message." " If unchecked, messages are sent by pressing Alt-S or Control-Enter, just as they are with regular messages.

")); d->ck_alertOpenChats->setWhatsThis( tr("Normally, Psi will not alert you when a new chat message" " is received in a chat window that is already open." " Check this option if you want to receive these alerts anyway.")); d->ck_raiseChatWindow->setWhatsThis( tr("Makes Psi bring an open chat window to the front of your screen when you receive a new message." " It does not take the keyboard focus, so it will not interfere with your work.")); d->ck_smallChats->setWhatsThis( tr("Makes Psi open chat windows in compact mode.")); d->ck_tabChats->setWhatsThis( tr("Makes Psi open chats in a tabbed window.")); QString s = tr("

Controls how long the chat log will be kept in memory after the" " chat window is closed.

"); d->rb_delChatsClose->setWhatsThis(s + tr("

This option does not keep the chat log in memory.

")); d->rb_delChatsHour->setWhatsThis(s + tr("

This option keeps the chat log for 1 hour before deleting it.

")); d->rb_delChatsDay->setWhatsThis(s + tr("

This option keeps the chat log for 1 day before deleting it.

")); d->rb_delChatsNever->setWhatsThis(s + tr("

This options keeps the chat log forever.

")); return w; } void OptionsTabChat::applyOptions() { if ( !w ) return; OptChatUI *d = (OptChatUI *)w; PsiOptions::instance()->setOption("options.messages.default-outgoing-message-type", bg_defAct->buttons().indexOf(bg_defAct->checkedButton()) == 0 ? "message" : "chat"); PsiOptions::instance()->setOption("options.ui.chat.alert-for-already-open-chats", d->ck_alertOpenChats->isChecked()); PsiOptions::instance()->setOption("options.ui.chat.raise-chat-windows-on-new-messages", d->ck_raiseChatWindow->isChecked()); PsiOptions::instance()->setOption("options.ui.chat.use-small-chats", d->ck_smallChats->isChecked()); QString delafter; switch (bg_delChats->buttons().indexOf( bg_delChats->checkedButton() )) { case 0: delafter = "instant"; break; case 1: delafter = "hour"; break; case 2: delafter = "day"; break; case 3: delafter = "never"; break; } PsiOptions::instance()->setOption("options.ui.chat.delete-contents-after", delafter); PsiOptions::instance()->setOption("options.ui.tabs.use-tabs", d->ck_tabChats->isChecked()); QString tabGrouping; int idx = d->cb_tabGrouping->currentIndex(); switch (idx) { case 0: tabGrouping = "C"; break; case 1: tabGrouping = "M"; break; case 2: tabGrouping = "C:M"; break; case 3: tabGrouping = "CM"; break; } if (!tabGrouping.isEmpty()) { PsiOptions::instance()->setOption("options.ui.tabs.grouping", tabGrouping); } else { if (d->cb_tabGrouping->count() == 5) { d->cb_tabGrouping->removeItem(4); } } PsiOptions::instance()->setOption("options.ui.chat.use-expanding-line-edit", d->ck_autoResize->isChecked()); // Soft return. // Only update this if the value actually changed, or else custom presets // might go lost. bool soft = ShortcutManager::instance()->shortcuts("chat.send").contains(QKeySequence(Qt::Key_Return)); if (soft != d->ck_chatSoftReturn->isChecked()) { QVariantList vl; if (d->ck_chatSoftReturn->isChecked()) { vl << qVariantFromValue(QKeySequence(Qt::Key_Enter)) << qVariantFromValue(QKeySequence(Qt::Key_Return)); } else { vl << qVariantFromValue(QKeySequence(Qt::Key_Enter+Qt::CTRL)) << qVariantFromValue(QKeySequence(Qt::CTRL+Qt::Key_Return)); } PsiOptions::instance()->setOption("options.shortcuts.chat.send",vl); } } void OptionsTabChat::restoreOptions() { if ( !w ) return; OptChatUI *d = (OptChatUI *)w; bg_defAct->buttons()[PsiOptions::instance()->getOption("options.messages.default-outgoing-message-type").toString() == "message" ? 0 : 1]->setChecked(true); d->ck_alertOpenChats->setChecked( PsiOptions::instance()->getOption("options.ui.chat.alert-for-already-open-chats").toBool() ); d->ck_raiseChatWindow->setChecked( PsiOptions::instance()->getOption("options.ui.chat.raise-chat-windows-on-new-messages").toBool() ); d->ck_smallChats->setChecked( PsiOptions::instance()->getOption("options.ui.chat.use-small-chats").toBool() ); d->ck_tabChats->setChecked( PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool() ); d->cb_tabGrouping->setEnabled(PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool()); QString tabGrouping = PsiOptions::instance()->getOption("options.ui.tabs.grouping").toString(); bool custom = false; if (tabGrouping == "C") { d->cb_tabGrouping->setCurrentIndex(0); } else if (tabGrouping == "M") { d->cb_tabGrouping->setCurrentIndex(1); } else if (tabGrouping == "C:M") { d->cb_tabGrouping->setCurrentIndex(2); } else if (tabGrouping == "CM") { d->cb_tabGrouping->setCurrentIndex(3); } else { if (d->cb_tabGrouping->count() == 5) { d->cb_tabGrouping->setCurrentIndex(4); } else { d->cb_tabGrouping->setCurrentIndex(-1); } custom = true; } if (!custom && d->cb_tabGrouping->count() == 5) { d->cb_tabGrouping->removeItem(4); } d->ck_autoResize->setChecked( PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool() ); QString delafter = PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString(); if (delafter == "instant") { d->rb_delChatsClose->setChecked(true); } else if (delafter == "hour") { d->rb_delChatsHour->setChecked(true); } else if (delafter == "day") { d->rb_delChatsDay->setChecked(true); } else if (delafter == "never") { d->rb_delChatsNever->setChecked(true); } d->ck_chatSoftReturn->setChecked(ShortcutManager::instance()->shortcuts("chat.send").contains(QKeySequence(Qt::Key_Return))); } psi-0.14/src/options/opt_appearance.ui0000644000175000017500000004140311305557613016145 0ustar janjan OptAppearance 0 0 402 333 OptAppearanceUI 9 6 Colors 9 6 Online contacts: Away contacts: DND contacts: Offline contacts: Qt::Horizontal 111 20 Contact list background: Status messages: 0 0 0 0 20 20 0 0 0 0 20 20 Account heading background: Group heading background: 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 Nick animation foreground: Nick animation background: Sent message foreground: Received message foreground: Informational messages in chats: Account heading foreground: Group heading foreground: 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 0 0 0 0 20 20 Fonts 8 6 true Chat: Message: Choose... true Choose... true Choose... Choose... Roster: Popup: FontLabel
opt_appearance.h
0
pb_cProfileFore pb_cProfileBack pb_cGroupFore pb_cGroupBack pb_cAnimFront pb_cAnimBack pb_cMessageSent pb_cMessageReceived pb_cSysMsg pb_cOnline pb_cAway pb_cDND pb_cOffline pb_cListBack pb_cStatus le_fRoster pb_fRoster le_fMessage pb_fMessage le_fChat pb_fChat le_fPopup pb_fPopup
psi-0.14/src/options/opt_iconset.cpp0000644000175000017500000007035411305557613015666 0ustar janjan#include "opt_iconset.h" #include "common.h" #include "iconwidget.h" #include "applicationinfo.h" #include "psiiconset.h" #include "psicon.h" #include "psioptions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_opt_iconset_emo.h" #include "ui_opt_iconset_system.h" #include "ui_opt_iconset_roster.h" #include "ui_ui_isdetails.h" class IconsetEmoUI : public QWidget, public Ui::IconsetEmo { public: IconsetEmoUI() : QWidget() { setupUi(this); } }; class IconsetSystemUI : public QWidget, public Ui::IconsetSystem { public: IconsetSystemUI() : QWidget() { setupUi(this); } }; class IconsetRosterUI : public QWidget, public Ui::IconsetRoster { public: IconsetRosterUI() : QWidget() { setupUi(this); } }; class IconsetDetailsDlg : public QDialog, public Ui::IconsetDetailsDlg { public: IconsetDetailsDlg(PsiCon *psicon, QWidget* parent, const char* name, bool modal) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setupUi(this); psi = psicon; psi->dialogRegister(this); QStringList bold_labels; bold_labels << "lb_name2"; bold_labels << "lb_version2"; bold_labels << "lb_date2"; bold_labels << "lb_home2"; bold_labels << "lb_desc2"; bold_labels << "lb_authors"; QList labels = findChildren(); foreach (QLabel *l, labels) { if (bold_labels.contains(l->objectName())) { QFont font = l->font(); font.setBold(true); l->setFont(font); } } setObjectName(name); setModal(modal); } ~IconsetDetailsDlg() { psi->dialogUnregister(this); } void setIconset( const Iconset &is ) { setWindowTitle(windowTitle().arg(is.name())); lb_name->setText(is.name()); lb_version->setText(is.version()); if ( is.description().isEmpty() ) { lb_desc->hide(); lb_desc2->hide(); } else lb_desc->setText(is.description()); if ( !is.homeUrl().isEmpty() ) { lb_home->setTitle(is.homeUrl()); lb_home->setUrl(is.homeUrl()); } else { lb_home->hide(); lb_home2->hide(); } if ( is.creation().isEmpty() ) { lb_date->hide(); lb_date2->hide(); } else { QDate date = QDate::fromString(is.creation(), Qt::ISODate); lb_date->setText(date.toString(Qt::LocalDate)); } if ( is.authors().count() == 0 ) { ptv_authors->hide(); lb_authors->hide(); } else { QString authors; QStringList::ConstIterator it = is.authors().begin(); for ( ; it != is.authors().end(); ++it) { if ( !authors.isEmpty() ) authors += "

"; authors += *it; } ptv_authors->setText( "" + authors + "" ); } isd_iconset->setIconset(is); resize(sizeHint()); } private: PsiCon *psi; }; static void isDetails(const Iconset &is, QWidget *parent, PsiCon *psi) { IconsetDetailsDlg *isd = new IconsetDetailsDlg(psi, parent, "IconsetDetailsDlg", false); isd->setIconset(is); isd->show(); } static QStringList dirs; static int countIconsets(QString addDir, QStringList excludeList) { int count = 0; QStringList::Iterator it = dirs.begin(); for ( ; it != dirs.end(); ++it) { QString fileName = *it + "/iconsets" + addDir; QDir dir (fileName); QStringList list = dir.entryList(QStringList() << "*"); QStringList::Iterator it2 = list.begin(); for ( ; it2 != list.end(); ++it2) { if ( *it2 == "." || *it2 == ".." ) continue; bool found = false; QStringList::Iterator it3 = excludeList.begin(); for ( ; it3 != excludeList.end(); ++it3) { if ( *it2 == *it3 ) { found = true; break; } } if ( found ) continue; count++; excludeList << *it2; } } return count; } //---------------------------------------------------------------------------- // IconsetLoadEvent //---------------------------------------------------------------------------- class IconsetLoadEvent : public QEvent { public: IconsetLoadEvent(IconsetLoadThread *par, Iconset *i) : QEvent(QEvent::User) { p = par; is = i; } IconsetLoadThread *thread() const { return p; } // if iconset() is '0' then it means that iconset wasn't loaded successfully Iconset *iconset() const { return is; } private: IconsetLoadThread *p; Iconset *is; }; //---------------------------------------------------------------------------- // IconsetFinishEvent //---------------------------------------------------------------------------- class IconsetFinishEvent : public QEvent { public: IconsetFinishEvent() : QEvent( (QEvent::Type)(QEvent::User + 1) ) { } }; //---------------------------------------------------------------------------- // IconsetLoadThreadDestroyEvent //---------------------------------------------------------------------------- class IconsetLoadThreadDestroyEvent : public QEvent { public: IconsetLoadThreadDestroyEvent(QThread *t) : QEvent( (QEvent::Type)(QEvent::User + 2) ) { thread = t; } ~IconsetLoadThreadDestroyEvent() { thread->wait(); delete thread; } private: QThread *thread; }; //---------------------------------------------------------------------------- // IconsetLoadThread //---------------------------------------------------------------------------- class IconsetLoadThread : public QThread { public: IconsetLoadThread(QObject *parent, QString addPath); void excludeIconsets(QStringList); bool cancelled; protected: void run(); void postEvent(QEvent *); private: QObject *parent; QString addPath; QStringList excludeList; }; IconsetLoadThread::IconsetLoadThread(QObject *p, QString path) { cancelled = false; parent = p; addPath = path; } void IconsetLoadThread::excludeIconsets(QStringList l) { excludeList += l; } static QMutex threadCancelled, threadMutex; void IconsetLoadThread::postEvent(QEvent *e) { threadCancelled.lock(); bool cancel = cancelled; threadCancelled.unlock(); if ( cancel ) { delete e; return; } QApplication::postEvent(parent, e); } void IconsetLoadThread::run() { threadMutex.lock(); QStringList dirs = ::dirs; threadMutex.unlock(); QStringList::Iterator it = dirs.begin(); for ( ; it != dirs.end(); ++it) { QString fileName = *it + "/iconsets" + addPath; QDir dir (fileName); QStringList list = dir.entryList(QStringList() << "*"); QStringList::Iterator it2 = list.begin(); for ( ; it2 != list.end(); ++it2) { if ( *it2 == "." || *it2 == ".." ) continue; threadCancelled.lock(); bool cancel = cancelled; threadCancelled.unlock(); if ( cancel ) goto getout; bool found = false; QStringList::Iterator it3 = excludeList.begin(); for ( ; it3 != excludeList.end(); ++it3) { if ( *it2 == *it3 ) { found = true; break; } } if ( found ) continue; IconsetLoadEvent *event = 0; Iconset *is = new Iconset; if ( is->load (fileName + "/" + *it2) ) { excludeList << *it2; // don't forget to delete iconset in ::event()! event = new IconsetLoadEvent(this, is); } else { delete is; event = new IconsetLoadEvent(this, 0); // without excluding corrupted iconset, // counter will go nuts! read more comments // about that... excludeList << *it2; // TODO: there is possibility, // that there's a bunch of same-named // iconsets, and some of them are corrupted. // It is possible to write a hack that // loads iconset even in that case. // logic: // tried to load iconset --> unable to load // checking if there's same-named iconsets in // other directories // emit IconsetLoadEvent() only on success // or when last corrupted iconset was unable // to load } postEvent(event); } } getout: postEvent(new IconsetFinishEvent()); QApplication::postEvent(qApp, new IconsetLoadThreadDestroyEvent(this)); // self destruct } //---------------------------------------------------------------------------- // OptionsTabIconsetSystem //---------------------------------------------------------------------------- OptionsTabIconsetSystem::OptionsTabIconsetSystem(QObject *parent) : OptionsTab(parent, "iconset_system", "", tr("System Icons"), tr("Select the system iconset")) { w = 0; thread = 0; if ( dirs.isEmpty() ) { dirs << ":"; dirs << "."; dirs << ApplicationInfo::homeDir(); dirs << ApplicationInfo::resourcesDir(); } } OptionsTabIconsetSystem::~OptionsTabIconsetSystem() { cancelThread(); } QWidget *OptionsTabIconsetSystem::widget() { if ( w ) return 0; w = new IconsetSystemUI; IconsetSystemUI *d = (IconsetSystemUI *)w; connect(d->pb_sysDetails, SIGNAL(clicked()), SLOT(previewIconset())); // TODO: add QWhatsThis return w; } void OptionsTabIconsetSystem::applyOptions() { if ( !w || thread ) return; IconsetSystemUI *d = (IconsetSystemUI *)w; const Iconset *is = d->iss_system->iconset(); if ( is ) { QFileInfo fi( is->fileName() ); PsiOptions::instance()->setOption("options.iconsets.system", fi.fileName()); } } void OptionsTabIconsetSystem::restoreOptions() { if ( !w || thread ) return; IconsetSystemUI *d = (IconsetSystemUI *)w; d->iss_system->clear(); QStringList loaded; d->setCursor(Qt::WaitCursor); d->iss_system->setEnabled(false); d->pb_sysDetails->setEnabled(false); d->progress->show(); d->progress->setValue( 0 ); numIconsets = countIconsets("/system", loaded); iconsetsLoaded = 0; cancelThread(); thread = new IconsetLoadThread(this, "/system"); thread->start(); } bool OptionsTabIconsetSystem::event(QEvent *e) { IconsetSystemUI *d = (IconsetSystemUI *)w; if ( e->type() == QEvent::User ) { // iconset load event IconsetLoadEvent *le = (IconsetLoadEvent *)e; if ( thread != le->thread() ) return false; if ( !numIconsets ) numIconsets = 1; d->progress->setValue( (int)((float)100 * ++iconsetsLoaded / numIconsets) ); Iconset *i = le->iconset(); if ( i ) { PsiIconset::instance()->stripFirstAnimFrame(i); d->iss_system->insert(*i); QFileInfo fi( i->fileName() ); if ( fi.fileName() == PsiOptions::instance()->getOption("options.iconsets.system").toString() ) d->iss_system->setItemSelected(d->iss_system->lastItem(), true); delete i; } return true; } else if ( e->type() == QEvent::User + 1 ) { // finish event d->iss_system->setEnabled(true); d->pb_sysDetails->setEnabled(true); connect(d->iss_system, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL(dataChanged())); d->progress->hide(); d->unsetCursor(); thread = 0; return true; } return false; } void OptionsTabIconsetSystem::previewIconset() { IconsetSystemUI *d = (IconsetSystemUI *)w; const Iconset *is = d->iss_system->iconset(); if (is) { isDetails(*is, parentWidget->parentWidget(), psi); } } void OptionsTabIconsetSystem::setData(PsiCon *psicon, QWidget *p) { psi = psicon; parentWidget = p; } void OptionsTabIconsetSystem::cancelThread() { if ( thread ) { threadCancelled.lock(); thread->cancelled = true; threadCancelled.unlock(); thread = 0; } } //---------------------------------------------------------------------------- // OptionsTabIconsetEmoticons //---------------------------------------------------------------------------- OptionsTabIconsetEmoticons::OptionsTabIconsetEmoticons(QObject *parent) : OptionsTab(parent, "iconset_emoticons", "", tr("Emoticons"), tr("Select your emoticon iconsets")) { w = 0; thread = 0; } OptionsTabIconsetEmoticons::~OptionsTabIconsetEmoticons() { cancelThread(); } QWidget *OptionsTabIconsetEmoticons::widget() { if ( w ) return 0; w = new IconsetEmoUI; IconsetEmoUI *d = (IconsetEmoUI *)w; connect(d->pb_emoUp, SIGNAL(clicked()), d->iss_emoticons, SLOT(moveItemUp())); connect(d->pb_emoUp, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->pb_emoDown, SIGNAL(clicked()), d->iss_emoticons, SLOT(moveItemDown())); connect(d->pb_emoDown, SIGNAL(clicked()), SIGNAL(dataChanged())); connect(d->pb_emoDetails, SIGNAL(clicked()), SLOT(previewIconset())); d->ck_useEmoticons->setWhatsThis( tr("

Emoticons are short sequences of characters that are used to convey an emotion or idea.

" "

Enable this option if you want Psi to replace common emoticons with a graphical image.

" "

For example, :-) would be replaced by

")); // TODO: add QWhatsThis return w; } void OptionsTabIconsetEmoticons::applyOptions() { if ( !w || thread ) return; IconsetEmoUI *d = (IconsetEmoUI *)w; PsiOptions::instance()->setOption("options.ui.emoticons.use-emoticons", d->ck_useEmoticons->isChecked()); QStringList list; for (int row = 0; row < d->iss_emoticons->count(); row++) { IconWidgetItem *item = (IconWidgetItem *)d->iss_emoticons->item(row); if ( d->iss_emoticons->isItemSelected(item) ) { const Iconset *is = item->iconset(); if ( is ) { QFileInfo fi( is->fileName() ); list << fi.fileName(); } } } PsiOptions::instance()->setOption("options.iconsets.emoticons", list); } void OptionsTabIconsetEmoticons::restoreOptions() { if ( !w || thread ) return; IconsetEmoUI *d = (IconsetEmoUI *)w; d->ck_useEmoticons->setChecked( PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool() ); // fill in the iconset view d->iss_emoticons->clear(); { foreach(Iconset* is, PsiIconset::instance()->emoticons) { d->iss_emoticons->insert(*is); d->iss_emoticons->setItemSelected(d->iss_emoticons->lastItem(), true); } } { QStringList loaded; { foreach(Iconset* tmp, PsiIconset::instance()->emoticons) { QFileInfo fi ( tmp->fileName() ); loaded << fi.fileName(); } } d->setCursor(Qt::WaitCursor); d->ck_useEmoticons->setEnabled(false); d->groupBox9->setEnabled(false); d->progress->show(); d->progress->setValue( 0 ); numIconsets = countIconsets("/emoticons", loaded); iconsetsLoaded = 0; cancelThread(); thread = new IconsetLoadThread(this, "/emoticons"); thread->excludeIconsets(loaded); thread->start(); } } bool OptionsTabIconsetEmoticons::event(QEvent *e) { IconsetEmoUI *d = (IconsetEmoUI *)w; if ( e->type() == QEvent::User ) { // iconset load event IconsetLoadEvent *le = (IconsetLoadEvent *)e; if ( thread != le->thread() ) return false; if ( !numIconsets ) numIconsets = 1; d->progress->setValue( (int)((float)100 * ++iconsetsLoaded / numIconsets) ); Iconset *is = le->iconset(); if ( is ) { PsiIconset::removeAnimation(is); d->iss_emoticons->insert(*is); delete is; } return true; } else if ( e->type() == QEvent::User + 1 ) { // finish event d->ck_useEmoticons->setEnabled(true); d->groupBox9->setEnabled(true); connect(d->iss_emoticons, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL(dataChanged())); bool checked = d->ck_useEmoticons->isChecked(); d->ck_useEmoticons->setChecked( true ); d->ck_useEmoticons->setChecked( checked ); d->progress->hide(); d->unsetCursor(); thread = 0; return true; } return false; } void OptionsTabIconsetEmoticons::previewIconset() { IconsetEmoUI *d = (IconsetEmoUI *)w; const Iconset *is = d->iss_emoticons->iconset(); if (is) { isDetails(*is, parentWidget->parentWidget(), psi); } } void OptionsTabIconsetEmoticons::setData(PsiCon *psicon, QWidget *p) { psi = psicon; parentWidget = p; } void OptionsTabIconsetEmoticons::cancelThread() { if ( thread ) { threadCancelled.lock(); thread->cancelled = true; threadCancelled.unlock(); thread = 0; } } //---------------------------------------------------------------------------- // OptionsTabIconsetRoster //---------------------------------------------------------------------------- OptionsTabIconsetRoster::OptionsTabIconsetRoster(QObject *parent) : OptionsTab(parent, "iconset_roster", "", tr("Roster Icons"), tr("Select iconsets for your roster")) { w = 0; thread = 0; } OptionsTabIconsetRoster::~OptionsTabIconsetRoster() { cancelThread(); } void OptionsTabIconsetRoster::addService(const QString& id, const QString& name) { IconsetRosterUI*d = (IconsetRosterUI*)w; QTreeWidgetItem* item = new QTreeWidgetItem(d->tw_isServices, QStringList(QString(name))); item->setData(0, ServiceRole, QVariant(QString(id))); d->tw_isServices->addTopLevelItem(item); } QWidget *OptionsTabIconsetRoster::widget() { if ( w ) return 0; w = new IconsetRosterUI; IconsetRosterUI *d = (IconsetRosterUI *)w; // Initialize transport iconsets addService("aim", "AIM"); addService("gadugadu", "Gadu-Gadu"); addService("icq", "ICQ"); addService("msn", "MSN"); addService("sms", "SMS"); addService("yahoo", "Yahoo!"); addService("transport", tr("Transport")); d->tw_isServices->resizeColumnToContents(0); connect(d->pb_defRosterDetails, SIGNAL(clicked()), SLOT(defaultDetails())); connect(d->iss_servicesRoster, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), SLOT(isServices_iconsetSelected(QListWidgetItem *, QListWidgetItem *))); connect(d->tw_isServices, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(isServices_selectionChanged(QTreeWidgetItem *))); connect(d->pb_servicesDetails, SIGNAL(clicked()), SLOT(servicesDetails())); isServices_selectionChanged(0); connect(d->iss_customRoster, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), SLOT(isCustom_iconsetSelected(QListWidgetItem *, QListWidgetItem *))); connect(d->tw_customRoster, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(isCustom_selectionChanged(QTreeWidgetItem *))); connect(d->tw_customRoster, SIGNAL(itemClicked(QTreeWidgetItem *, int )), SLOT(isCustom_selectionChanged(QTreeWidgetItem *))); connect(d->pb_customRosterDetails, SIGNAL(clicked()), SLOT(customDetails())); connect(d->le_customRoster, SIGNAL(textChanged(const QString &)), SLOT(isCustom_textChanged())); connect(d->pb_customRosterAdd, SIGNAL(clicked()), SLOT(isCustom_add())); connect(d->pb_customRosterDelete, SIGNAL(clicked()), SLOT(isCustom_delete())); isCustom_selectionChanged(0); d->ck_useTransportIconsForContacts->setWhatsThis( tr("Toggles use of transport icons to the contacts, that use that transports.")); // TODO: add QWhatsThis return w; } void OptionsTabIconsetRoster::applyOptions() { if (!w || thread) return; IconsetRosterUI *d = (IconsetRosterUI *)w; PsiOptions::instance()->setOption("options.ui.contactlist.use-transport-icons", d->ck_useTransportIconsForContacts->isChecked()); // roster - default { const Iconset *is = d->iss_defRoster->iconset(); if (is) { QFileInfo fi(is->fileName()); PsiOptions::instance()->setOption("options.iconsets.status", fi.fileName()); } } // roster - services { QString baseServicesPath = "options.iconsets.service-status"; PsiOptions::instance()->removeOption(baseServicesPath, true); QTreeWidgetItemIterator it(d->tw_isServices); while (*it) { QString path = PsiOptions::instance()->mapPut(baseServicesPath, (*it)->data(0, ServiceRole).toString()); PsiOptions::instance()->setOption(path + ".iconset", (*it)->data(0, IconsetRole).toString()); ++it; } } // roster - custom { QString baseCustomStatusPath = "options.iconsets.custom-status"; PsiOptions::instance()->removeOption(baseCustomStatusPath, true); int index = 0; QTreeWidgetItemIterator it(d->tw_customRoster); while (*it) { QString path = baseCustomStatusPath + ".a" + QString::number(index++); PsiOptions::instance()->setOption(path + ".regexp", (*it)->data(0, RegexpRole).toString()); PsiOptions::instance()->setOption(path + ".iconset", (*it)->data(0, IconsetRole).toString()); ++it; } } } void OptionsTabIconsetRoster::restoreOptions() { if ( !w || thread ) return; IconsetRosterUI *d = (IconsetRosterUI *)w; d->ck_useTransportIconsForContacts->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.use-transport-icons").toBool() ); d->iss_defRoster->clear(); d->iss_servicesRoster->clear(); d->iss_customRoster->clear(); QStringList loaded; d->setCursor(Qt::WaitCursor); QPalette customPal = d->palette(); // customPal.setDisabled(customPal.inactive()); d->tabWidget3->setEnabled(false); d->tabWidget3->setPalette(customPal); d->progress->show(); d->progress->setValue( 0 ); numIconsets = countIconsets("/roster", loaded); iconsetsLoaded = 0; cancelThread(); thread = new IconsetLoadThread(this, "/roster"); thread->start(); } bool OptionsTabIconsetRoster::event(QEvent *e) { IconsetRosterUI *d = (IconsetRosterUI *)w; if ( e->type() == QEvent::User ) { // iconset load event IconsetLoadEvent *le = (IconsetLoadEvent *)e; if ( thread != le->thread() ) return false; if ( !numIconsets ) numIconsets = 1; d->progress->setValue( (int)((float)100 * ++iconsetsLoaded / numIconsets) ); Iconset *i = le->iconset(); if ( i ) { PsiIconset::instance()->stripFirstAnimFrame(i); QFileInfo fi( i->fileName() ); // roster - default d->iss_defRoster->insert(*i); if ( fi.fileName() == PsiOptions::instance()->getOption("options.iconsets.status")) d->iss_defRoster->setItemSelected(d->iss_defRoster->lastItem(), true); // roster - service d->iss_servicesRoster->insert(*i); // roster - custom d->iss_customRoster->insert(*i); delete i; } return true; } else if ( e->type() == QEvent::User + 1 ) { // finish event // roster - service { // fill the QTreeWidget QTreeWidgetItemIterator it(d->tw_isServices); while (*it) { QTreeWidgetItem *i = *it; if (!i->data(0, ServiceRole).toString().isEmpty()) { Iconset *iss = PsiIconset::instance()->roster[ PsiOptions::instance()->getOption( PsiOptions::instance()->mapLookup( "options.iconsets.service-status", i->data(0, ServiceRole).toString())+".iconset").toString()]; if (iss) { i->setText(1, iss->name()); QFileInfo fi(iss->fileName()); i->setData(0, IconsetRole, fi.fileName()); } } ++it; } } // roster - custom { // Then, fill the QListView QTreeWidgetItem *last = 0; QStringList customicons = PsiOptions::instance()->getChildOptionNames("options.iconsets.custom-status", true, true); foreach(QString base, customicons) { QString regexp = PsiOptions::instance()->getOption(base + ".regexp").toString(); QString icoset = PsiOptions::instance()->getOption(base + ".iconset").toString(); QTreeWidgetItem *item = new QTreeWidgetItem(d->tw_customRoster, last); last = item; item->setText(0, clipCustomText(regexp)); item->setData(0, RegexpRole, regexp); Iconset *iss = PsiIconset::instance()->roster[icoset]; if ( iss ) { item->setText(1, iss->name()); QFileInfo fi ( iss->fileName() ); item->setData(0, IconsetRole, fi.fileName()); } } d->tw_customRoster->resizeColumnToContents(0); } d->tabWidget3->setEnabled(true); // d->tabWidget3->unsetPalette(); connect(d->iss_defRoster, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL(dataChanged())); connect(d->iss_servicesRoster, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL(dataChanged())); connect(d->iss_customRoster, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL(dataChanged())); d->progress->hide(); d->unsetCursor(); thread = 0; return true; } return false; } void OptionsTabIconsetRoster::setData(PsiCon *psicon, QWidget *p) { psi = psicon; parentWidget = p; } void OptionsTabIconsetRoster::defaultDetails() { IconsetRosterUI *d = (IconsetRosterUI *)w; const Iconset *is = d->iss_defRoster->iconset(); if (is) { isDetails(*is, parentWidget->parentWidget(), psi); } } void OptionsTabIconsetRoster::servicesDetails() { IconsetRosterUI *d = (IconsetRosterUI *)w; const Iconset *is = d->iss_servicesRoster->iconset(); if (is) { isDetails(*is, parentWidget->parentWidget(), psi); } } void OptionsTabIconsetRoster::customDetails() { IconsetRosterUI *d = (IconsetRosterUI *)w; const Iconset *is = d->iss_customRoster->iconset(); if (is) { isDetails(*is, parentWidget->parentWidget(), psi); } } //------------------------------------------------------------ void OptionsTabIconsetRoster::isServices_iconsetSelected(QListWidgetItem *item, QListWidgetItem *) { if ( !item ) return; IconsetRosterUI *d = (IconsetRosterUI *)w; QTreeWidgetItem *it = d->tw_isServices->currentItem(); if ( !it ) return; const Iconset *is = ((IconWidgetItem *)item)->iconset(); if ( !is ) return; it->setText(1, is->name()); QFileInfo fi ( is->fileName() ); it->setData(0, IconsetRole, fi.fileName()); } void OptionsTabIconsetRoster::isServices_selectionChanged(QTreeWidgetItem *it) { IconsetRosterUI *d = (IconsetRosterUI *)w; d->iss_servicesRoster->setEnabled( it != 0 ); d->pb_servicesDetails->setEnabled( it != 0 ); d->iss_servicesRoster->clearSelection(); if ( !it ) return; QString name = it->data(0, IconsetRole).toString(); if (name.isEmpty()) return; emit noDirty(true); for (int row = 0; row < d->iss_servicesRoster->count(); row++) { IconWidgetItem *item = (IconWidgetItem *)d->iss_servicesRoster->item(row); const Iconset *is = item->iconset(); if ( is ) { QFileInfo fi ( is->fileName() ); if ( fi.fileName() == name ) { emit noDirty(true); d->iss_servicesRoster->setItemSelected(item, true); d->iss_servicesRoster->scrollToItem(item); emit noDirty(false); break; } } } qApp->processEvents(); emit noDirty(false); } //------------------------------------------------------------ void OptionsTabIconsetRoster::isCustom_iconsetSelected(QListWidgetItem *item, QListWidgetItem *) { if ( !item ) return; IconsetRosterUI *d = (IconsetRosterUI *)w; QTreeWidgetItem *it = d->tw_customRoster->currentItem(); if ( !it ) return; const Iconset *is = ((IconWidgetItem *)item)->iconset(); if ( !is ) return; it->setText(1, is->name()); QFileInfo fi ( is->fileName() ); it->setData(0, IconsetRole, fi.fileName()); } void OptionsTabIconsetRoster::isCustom_selectionChanged(QTreeWidgetItem *it) { IconsetRosterUI *d = (IconsetRosterUI *)w; d->iss_customRoster->setEnabled( it != 0 ); d->pb_customRosterDetails->setEnabled( it != 0 ); //d->pb_customRosterAdd->setEnabled( it != 0 ); d->pb_customRosterDelete->setEnabled( it != 0 ); d->le_customRoster->setEnabled( it != 0 ); d->iss_customRoster->clearSelection(); if ( !it ) return; QString name = it->data(0, IconsetRole).toString(); if (name.isEmpty()) return; emit noDirty(true); d->le_customRoster->setText(it->data(0, RegexpRole).toString()); for (int row = 0; row < d->iss_customRoster->count(); row++) { IconWidgetItem *item = (IconWidgetItem *)d->iss_customRoster->item(row); const Iconset *is = item->iconset(); if ( is ) { QFileInfo fi ( is->fileName() ); if ( fi.fileName() == name ) { d->iss_customRoster->setItemSelected(item, true); d->iss_customRoster->scrollToItem(item); break; } } } qApp->processEvents(); emit noDirty(false); } void OptionsTabIconsetRoster::isCustom_textChanged() { IconsetRosterUI *d = (IconsetRosterUI *)w; QTreeWidgetItem *item = d->tw_customRoster->currentItem(); if ( !item ) return; item->setText(0, clipCustomText(d->le_customRoster->text())); item->setData(0, RegexpRole, d->le_customRoster->text()); } void OptionsTabIconsetRoster::isCustom_add() { IconsetRosterUI *d = (IconsetRosterUI *)w; QString def; const Iconset *iconset = d->iss_defRoster->iconset(); if ( iconset ) { QFileInfo fi( iconset->fileName() ); def = fi.fileName(); } else qWarning("OptionsTabIconsetRoster::isCustom_add(): 'def' is null!"); QTreeWidgetItem *item = new QTreeWidgetItem(d->tw_customRoster); const Iconset *i = PsiIconset::instance()->roster[def]; if ( i ) { item->setText(1, i->name()); QFileInfo fi(i->fileName()); item->setData(0, IconsetRole, fi.fileName()); } d->tw_customRoster->setCurrentItem(item); emit dataChanged(); d->le_customRoster->setFocus(); } void OptionsTabIconsetRoster::isCustom_delete() { IconsetRosterUI *d = (IconsetRosterUI *)w; QTreeWidgetItem *item = d->tw_customRoster->currentItem(); if ( !item ) return; delete item; isCustom_selectionChanged(0); d->tw_customRoster->clearSelection(); emit dataChanged(); } QString OptionsTabIconsetRoster::clipCustomText(QString s) { if ( s.length() > 10 ) { s = s.left(9); s += "..."; } return s; } void OptionsTabIconsetRoster::cancelThread() { if ( thread ) { threadCancelled.lock(); thread->cancelled = true; threadCancelled.unlock(); thread = 0; } } psi-0.14/src/options/optionstab.h0000644000175000017500000000424111305557613015157 0ustar janjan#ifndef OPTIONSTAB_H #define OPTIONSTAB_H #include #include #include class PsiIcon; class QWidget; class PsiCon; class OptionsTab : public QObject { Q_OBJECT public: OptionsTab(QObject *parent, const char *name = 0); OptionsTab(QObject *parent, QByteArray id, QByteArray parentId, QString name, QString desc, QString tabIconName = QString::null, QString iconName = QString::null); ~OptionsTab(); virtual QByteArray id() const; // Unique identifier, i.e. "plugins_misha's_cool-plugin" virtual QByteArray parentId() const; // Identifier of parent tab, i.e. "general" virtual QString tabName() const; // "General" virtual PsiIcon *tabIcon() const; // default implementation returns 0 virtual QString name() const; // "Roster" virtual QString desc() const; // "You can configure your roster here" virtual PsiIcon *psiIcon() const; // default implementation returns 0 virtual QWidget *widget() = 0; // Actual widget that contains checkboxes, pushbuttons, etc. // the widget is reparented after this call virtual bool stretchable() const; // return 'true' if widget() is stretchable and wants a lot of space signals: void dataChanged(); //void addWidgetChangedSignal(QString widgetName, QCString signal); void noDirty(bool); void connectDataChanged(QWidget *); public slots: virtual void setData(PsiCon *, QWidget *parentDialog); virtual void applyOptions(); virtual void restoreOptions(); virtual void tabAdded(OptionsTab *tab); // called when tab 'tab' specifies this tab as parent private: QByteArray v_id, v_parentId; QString v_name, v_desc, v_tabIconName, v_iconName; }; class MetaOptionsTab : public OptionsTab { Q_OBJECT public: MetaOptionsTab(QObject *parent, const char *name = 0); MetaOptionsTab(QObject *parent, QByteArray id, QByteArray parentId, QString name, QString desc, QString tabIconName = QString::null, QString iconName = QString::null); ~MetaOptionsTab(); QWidget *widget(); void applyOptions(); void restoreOptions(); void setData(PsiCon *, QWidget *); bool stretchable() const { return true; } void addTab(OptionsTab *); private: void init(); QWidget *w; QList tabs; }; #endif psi-0.14/src/options/optionstab.cpp0000644000175000017500000001320411305557613015511 0ustar janjan#include "optionstab.h" #include "iconset.h" #include #include #include #include //---------------------------------------------------------------------------- // OptionsTab //---------------------------------------------------------------------------- OptionsTab::OptionsTab(QObject *parent, const char *name) : QObject(parent) { setObjectName(name); } OptionsTab::OptionsTab(QObject *parent, QByteArray _id, QByteArray _parentId, QString _name, QString _desc, QString _tabIconName, QString _iconName) : QObject(parent) { setObjectName(_name); v_id = _id; v_parentId = _parentId; v_name = _name; v_desc = _desc; v_tabIconName = _tabIconName; v_iconName = _iconName; } OptionsTab::~OptionsTab() { } QByteArray OptionsTab::id() const { return v_id; } QByteArray OptionsTab::parentId() const { return v_parentId; } QString OptionsTab::tabName() const { return v_name; } PsiIcon *OptionsTab::tabIcon() const { if ( v_tabIconName.isEmpty() ) return 0; return (PsiIcon *)IconsetFactory::iconPtr( v_tabIconName ); } QString OptionsTab::name() const { return v_name; } QString OptionsTab::desc() const { return v_desc; } PsiIcon *OptionsTab::psiIcon() const { if ( v_iconName.isEmpty() ) { //if ( tabIcon() ) // return tabIcon(); return (PsiIcon *)IconsetFactory::iconPtr("psi/logo_32"); } return (PsiIcon *)IconsetFactory::iconPtr( v_iconName ); } void OptionsTab::applyOptions() { } void OptionsTab::restoreOptions() { } void OptionsTab::tabAdded(OptionsTab *) { } bool OptionsTab::stretchable() const { return false; } void OptionsTab::setData(PsiCon *, QWidget *) { } //---------------------------------------------------------------------------- // OptionsTabWidget //---------------------------------------------------------------------------- class OptionsTabWidget : public QTabWidget { Q_OBJECT public: OptionsTabWidget(QWidget *parent); void addTab(OptionsTab *); void restoreOptions(); signals: void connectDataChanged(QWidget *); void noDirty(bool); private slots: void updateCurrent(QWidget *); private: struct TabData { TabData() { tab = 0; initialized = false; } TabData(OptionsTab *t) { tab = t; initialized = false; } OptionsTab *tab; bool initialized; }; QMap w2tab; }; OptionsTabWidget::OptionsTabWidget(QWidget *parent) : QTabWidget(parent) { connect(this, SIGNAL(currentChanged(QWidget *)), SLOT(updateCurrent(QWidget *))); } void OptionsTabWidget::addTab(OptionsTab *tab) { if ( tab->tabName().isEmpty() ) return; // skip the dummy tabs // the widget will have no parent; it will be reparented // when inserting it with "addTab" QWidget *w = new QWidget(0); w->setObjectName(tab->name()); if ( !tab->desc().isEmpty() ) setTabToolTip(indexOf(w), tab->desc()); w2tab[w] = TabData(tab); if ( tab->tabIcon() ) QTabWidget::addTab(w, tab->tabIcon()->icon(), tab->tabName()); else QTabWidget::addTab(w, tab->tabName()); //FIXME: this is safe for our current use of addTab, but may //be inconvenient in the future (Qt circa 4.2 had a bug which stopped //setCurrentIndex(0); from working) setCurrentIndex(1); setCurrentIndex(0); } void OptionsTabWidget::updateCurrent(QWidget *w) { if ( !w2tab[w].initialized ) { QVBoxLayout *vbox = new QVBoxLayout(w); vbox->setMargin(5); OptionsTab *opttab = w2tab[w].tab; QWidget *tab = opttab->widget(); if ( !tab ) return; tab->setParent(w); vbox->addWidget(tab); if ( !opttab->stretchable() ) vbox->addStretch(); emit noDirty(true); opttab->restoreOptions(); emit noDirty(false); emit connectDataChanged(tab); tab->show(); w2tab[w].initialized = true; } } void OptionsTabWidget::restoreOptions() { emit noDirty(true); w2tab[currentWidget()].tab->restoreOptions(); emit noDirty(false); } //---------------------------------------------------------------------------- // MetaOptionsTab //---------------------------------------------------------------------------- MetaOptionsTab::MetaOptionsTab(QObject *parent, const char *name) : OptionsTab(parent, name) { init(); } MetaOptionsTab::MetaOptionsTab(QObject *parent, QByteArray id, QByteArray parentId, QString name, QString desc, QString tabIconName, QString iconName) : OptionsTab(parent, id, parentId, name, desc, tabIconName, iconName) { init(); } MetaOptionsTab::~MetaOptionsTab() { qDeleteAll(tabs); if ( w ) delete w; } void MetaOptionsTab::init() { w = 0; } void MetaOptionsTab::addTab(OptionsTab *tab) { connect(tab, SIGNAL(dataChanged()), SIGNAL(dataChanged())); //connect(tab, SIGNAL(addWidgetChangedSignal(QString, QCString)), SIGNAL(addWidgetChangedSignal(QString, QCString))); connect(tab, SIGNAL(noDirty(bool)), SIGNAL(noDirty(bool))); connect(tab, SIGNAL(connectDataChanged(QWidget *)), SIGNAL(connectDataChanged(QWidget *))); tabs.append(tab); } QWidget *MetaOptionsTab::widget() { if ( w ) return w; OptionsTabWidget *t = new OptionsTabWidget(0); w = t; connect(w, SIGNAL(connectDataChanged(QWidget *)), SIGNAL(connectDataChanged(QWidget *))); connect(w, SIGNAL(noDirty(bool)), SIGNAL(noDirty(bool))); foreach(OptionsTab* tab, tabs) { t->addTab(tab); } // set the current widget to 0, otherwise qt4 will show no widget t->setCurrentIndex(0); return w; } void MetaOptionsTab::applyOptions() { foreach(OptionsTab* tab, tabs) { tab->applyOptions(); } } void MetaOptionsTab::restoreOptions() { if ( w ) { OptionsTabWidget *d = (OptionsTabWidget *)w; d->restoreOptions(); } foreach(OptionsTab* tab, tabs) { tab->restoreOptions(); } } void MetaOptionsTab::setData(PsiCon *psi, QWidget *w) { foreach(OptionsTab* tab, tabs) { tab->setData(psi, w); } } #include "optionstab.moc" psi-0.14/src/options/opt_events.h0000644000175000017500000000053111305557613015161 0ustar janjan#ifndef OPT_EVENTS_H #define OPT_EVENTS_H #include "optionstab.h" #include "qradiobutton.h" class QWidget; class OptionsTabEvents : public OptionsTab { Q_OBJECT public: OptionsTabEvents(QObject *parent); QWidget *widget(); void applyOptions(); void restoreOptions(); private: QWidget *w; QList list_alerts; }; #endif psi-0.14/src/options/opt_groupchat.h0000644000175000017500000000122111305557613015646 0ustar janjan#ifndef OPT_GROUPCHAT_H #define OPT_GROUPCHAT_H #include "optionstab.h" class QWidget; class QListWidgetItem; class OptionsTabGroupchat : public OptionsTab { Q_OBJECT public: OptionsTabGroupchat(QObject *parent); QWidget *widget(); void applyOptions(); void restoreOptions(); void setData(PsiCon *, QWidget *); bool stretchable() const { return true; } private slots: void addNickColor(QString); void addGCHighlight(); void removeGCHighlight(); void addGCNickColor(); void removeGCNickColor(); void chooseGCNickColor(); void displayGCNickColor(); void selectedGCNickColor(QListWidgetItem *item); private: QWidget *w, *dlg; }; #endif psi-0.14/src/options/opt_iconset_roster.ui0000644000175000017500000002611311305557613017111 0ustar janjan IconsetRoster 0 0 375 341 IconsetRosterUI 9 6 0 Default 8 6 Default roster iconset: &Show details Qt::Horizontal QSizePolicy::Expanding 151 20 Services 9 6 Use transport specific icons for contacts 0 6 4 7 0 0 QAbstractItemView::NoEditTriggers false true 2 Service Iconset 0 6 1 7 0 0 0 6 Qt::Horizontal QSizePolicy::Expanding 41 20 &Show details Service iconsets: Custom 8 6 0 6 Qt::Horizontal QSizePolicy::Expanding 91 20 Iconset: Regular expression: &Show details 0 6 &Add &Delete QAbstractItemView::NoEditTriggers false true RegExp Iconset Custom iconsets: 195 250 189 31 Qt::Horizontal 0 0 100 30 0 0 100 30 Qt::Horizontal qPixmapFromMimeSource IconsetSelect QListWidget
iconsetselect.h
IconButton QPushButton
iconbutton.h
psi-0.14/src/options/opt_status.ui0000644000175000017500000002202611305557613015371 0ustar janjan OptStatus 0 0 411 563 OptStatusUI 9 6 Prompt for status message when choosing 9 0 Online Offline 0 6 false false Minutes false Minutes false false Minutes Auto offline after: Auto XA after: Auto away after: false Auto status message: 32767 50 Presets 9 6 0 6 Preset: Qt::Horizontal 40 20 New Delete 0 6 Status: Qt::Horizontal 97 20 Priority: 50 16777215 Content: 7 7 0 0 32767 90 qPixmapFromMimeSource StatusComboBox QComboBox
statuscombobox.h
ck_asAway sb_asAway ck_asXa sb_asXa ck_asOffline sb_asOffline te_asMessage pb_spNew pb_spDelete te_sp ck_asOffline toggled(bool) sb_asOffline setEnabled(bool) 65 109 171 112 ck_asXa toggled(bool) sb_asXa setEnabled(bool) 95 77 172 78 ck_asAway toggled(bool) sb_asAway setEnabled(bool) 61 46 180 42
psi-0.14/src/options/opt_tree.h0000644000175000017500000000044611305557613014621 0ustar janjan#ifndef OPT_TREE_H #define OPT_TREE_H #include "optionstab.h" class QWidget; class OptionsTabTree : public OptionsTab { Q_OBJECT public: OptionsTabTree(QObject *parent); ~OptionsTabTree(); QWidget *widget(); bool stretchable() const {return true;}; private: QWidget *w; }; #endif psi-0.14/src/options/opt_general_groupchat.ui0000644000175000017500000002260111305557613017536 0ustar janjan GeneralGroupchat 0 0 420 186 GeneralGroupchatUI 9 6 0 6 Enable word highlighting Highlight lines and alert the user if this text is included in chat Word highlighting 11 6 Words which will cause a notification in group chat. This is the list of words which when said in group chat will cause the user to be notified. Type a new word here and press "Add Word" for it to be added to the highlight list Type a new word here and press "Add Word" for it to be added to the highlight list 0 6 Qt::Horizontal QSizePolicy::Expanding 40 20 Adds the new word to the list Adds the new word to the list Add Removes the selected word from the highlight list Removes the selected word from the highlight list Remove Qt::Horizontal QSizePolicy::Expanding 40 20 0 6 Enable nick coloring Nick coloring 11 6 Colors used for nicks in groupchat This is the list of colours with which nicks will be drawn in group chat. 0 6 Type a colourcode here, or press the pallette to the right Type a colourcode here, or press the pallette to the right 4 4 0 0 0 6 Qt::Horizontal QSizePolicy::Expanding 40 20 Adds the color to the list Adds the new color to the list Add Removes the selected color from the list Removes the selected color from the list Remove Qt::Horizontal QSizePolicy::Expanding 40 20 qPixmapFromMimeSource ck_gcHighlights le_newHighlightWord pb_removeHighlightWord pb_addHighlightWord ck_gcNickColoring le_newNickColor pb_nickColor pb_removeNickColor pb_addNickColor psi-0.14/src/options/opt_chat.ui0000644000175000017500000001215411305557613014766 0ustar janjan OptChat 0 0 346 421 OptChatUI 9 6 Enter key sends chat messages Alert chat messages even if chat window is open Raise chat window on receiving new messages Open chats in compact mode 0 6 0 0 0 0 Use tabbed mode: for chats only for mucs only for chats and mucs separately for mucs and chats in one window [customized] Qt::Horizontal 0 0 Auto-resize text input field Default action 9 6 Message Chat Delete chat window contents 10 6 When chat window is closed One hour after chat window was closed One day after chat window was closed Never qPixmapFromMimeSource psi-0.14/src/options/opt_plugins.ui0000644000175000017500000000573011305557613015532 0ustar janjan OptPlugins 0 0 362 400 OptPluginsUI 9 6 Plugin Name: false Plugin Location: false No plugin selected 0 6 false Load this plugin Qt::Horizontal 40 20 Qt::Vertical 20 40 0 6 Qt::Vertical 20 40 qPixmapFromMimeSource psi-0.14/src/options/opt_iconset.h0000644000175000017500000000444711305557613015333 0ustar janjan#ifndef OPT_ICONSET_H #define OPT_ICONSET_H #include "optionstab.h" //Added by qt3to4: #include class QWidget; class QListWidgetItem; class IconsetLoadThread; class QTreeWidgetItem; class OptionsTabIconsetSystem : public OptionsTab { Q_OBJECT public: OptionsTabIconsetSystem(QObject *parent); ~OptionsTabIconsetSystem(); QWidget *widget(); void applyOptions(); void restoreOptions(); bool stretchable() const { return true; } private slots: void setData(PsiCon *, QWidget *); void previewIconset(); protected: bool event(QEvent *); void cancelThread(); private: QWidget *w, *parentWidget; PsiCon *psi; int numIconsets, iconsetsLoaded; IconsetLoadThread *thread; }; class OptionsTabIconsetEmoticons : public OptionsTab { Q_OBJECT public: OptionsTabIconsetEmoticons(QObject *parent); ~OptionsTabIconsetEmoticons(); QWidget *widget(); void applyOptions(); void restoreOptions(); bool stretchable() const { return true; } private slots: void setData(PsiCon *, QWidget *); void previewIconset(); protected: bool event(QEvent *); void cancelThread(); private: QWidget *w, *parentWidget; PsiCon *psi; int numIconsets, iconsetsLoaded; IconsetLoadThread *thread; }; class OptionsTabIconsetRoster : public OptionsTab { Q_OBJECT public: OptionsTabIconsetRoster(QObject *parent); ~OptionsTabIconsetRoster(); QWidget *widget(); void applyOptions(); void restoreOptions(); bool stretchable() const { return true; } private slots: void setData(PsiCon *, QWidget *); void defaultDetails(); void servicesDetails(); void customDetails(); void isServices_iconsetSelected(QListWidgetItem *current, QListWidgetItem *previous); void isServices_selectionChanged(QTreeWidgetItem *); void isCustom_iconsetSelected(QListWidgetItem *current, QListWidgetItem *previous); void isCustom_selectionChanged(QTreeWidgetItem *); void isCustom_textChanged(); void isCustom_add(); void isCustom_delete(); QString clipCustomText(QString); protected: bool event(QEvent *); void cancelThread(); private: QWidget* w; QWidget* parentWidget; PsiCon *psi; int numIconsets, iconsetsLoaded; IconsetLoadThread *thread; enum { IconsetRole = Qt::UserRole + 0, ServiceRole = Qt::UserRole + 1, RegexpRole = Qt::UserRole + 2 }; void addService(const QString& id, const QString& name); }; #endif psi-0.14/src/options/opt_events.cpp0000644000175000017500000002002311305557613015512 0ustar janjan#include "opt_events.h" #include "common.h" #include "iconwidget.h" #include #include #include #include #include #include #include "psioptions.h" #include "ui_opt_events.h" class OptEventsUI : public QWidget, public Ui::OptEvents { public: OptEventsUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabEvents //---------------------------------------------------------------------------- OptionsTabEvents::OptionsTabEvents(QObject *parent) : OptionsTab(parent, "events", "", tr("Events"), tr("The events behaviour"), "psi/events") { w = 0; } QWidget *OptionsTabEvents::widget() { if ( w ) return 0; w = new OptEventsUI(); OptEventsUI *d = (OptEventsUI *)w; d->ck_popupMsgs->setWhatsThis( tr("Makes new incoming message windows pop up automatically when received.")); d->ck_popupHeadlines->setWhatsThis( tr("Makes new incoming headlines pop up automatically when received.")); d->ck_popupFiles->setWhatsThis( tr("Makes new incoming file requests pop up automatically when received.")); d->ck_allowAwayPopup->setWhatsThis( tr("Normally, Psi will not autopopup events when you are away. " "Set this option if you want them to popup anyway.")); d->ck_allowUnlistedPopup->setWhatsThis( tr("Normally, Psi will not autopopup events from users not in your roster. " "Set this option if you want them to popup anyway.")); d->ck_raise->setWhatsThis( tr("Makes new incoming events bring the main window to the foreground.")); d->ck_ignoreNonRoster->setWhatsThis( tr("Makes Psi ignore all incoming events from contacts" " not already in your list of contacts.")); d->cb_animation->setWhatsThis( tr("What kind of animation should psi use for incoming event icons on the main window?")); d->cb_animation->setItemData ( 0, "no"); d->cb_animation->setItemData ( 1, "blink"); d->cb_animation->setItemData ( 2, "animate"); /* d->rb_aSolid->setWhatsThis( tr("Does not animate or blink incoming event icons on the main window as they are received.")); d->rb_aBlink->setWhatsThis( tr("Makes all incoming event icons blink on the main window as events are received.")); d->rb_aAnimate->setWhatsThis( tr("Animates incoming event icons on the main window as events are recieved."));*/ d->ck_autoAuth->setWhatsThis( tr("Makes Psi automatically accept all authorization requests from anyone.")); d->ck_notifyAuth->setWhatsThis( tr("Makes Psi notify you when your authorization request was approved.")); d->cb_bounce->setItemData(0, "never"); d->cb_bounce->setItemData(1, "once"); d->cb_bounce->setItemData(2, "forever"); #ifndef Q_WS_MAC d->cb_bounce->hide(); d->lb_bounce->hide(); #endif /* list_alerts.insert(0,d->rb_aSolid); list_alerts.insert(1,d->rb_aBlink); list_alerts.insert(2,d->rb_aAnimate); */ return w; } void OptionsTabEvents::applyOptions() { if ( !w ) return; OptEventsUI *d = (OptEventsUI *)w; PsiOptions::instance()->setOption("options.ui.message.auto-popup", d->ck_popupMsgs->isChecked()); PsiOptions::instance()->setOption("options.ui.chat.auto-popup", d->ck_popupMsgs->isChecked()); PsiOptions::instance()->setOption("options.ui.message.auto-popup-headlines", d->ck_popupHeadlines->isChecked()); PsiOptions::instance()->setOption("options.ui.file-transfer.auto-popup", d->ck_popupFiles->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.popup-dialogs.suppress-while-away", !d->ck_allowAwayPopup->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.popup-dialogs.suppress-when-not-on-roster", !d->ck_allowUnlistedPopup->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.raise-on-new-event", d->ck_raise->isChecked()); PsiOptions::instance()->setOption("options.messages.ignore-non-roster-contacts", d->ck_ignoreNonRoster->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.alert-style", d->cb_animation->itemData(d->cb_animation->currentIndex())); PsiOptions::instance()->setOption("options.subscriptions.automatically-allow-authorization", d->ck_autoAuth->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.successful-subscription", d->ck_notifyAuth->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.bounce-dock", d->cb_bounce->itemData( d->cb_bounce->currentIndex())); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.enabled", d->ck_popupOn->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.incoming-message", d->ck_popupOnMessage->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.incoming-chat", d->ck_popupOnMessage->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.incoming-headline", d->ck_popupOnHeadline->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.incoming-file-transfer", d->ck_popupOnFile->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.status.online", d->ck_popupOnOnline->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.status.offline", d->ck_popupOnOffline->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.passive-popups.status.other-changes", d->ck_popupOnStatus->isChecked()); } void OptionsTabEvents::restoreOptions() { if ( !w ) return; OptEventsUI *d = (OptEventsUI *)w; d->ck_popupMsgs->setChecked( PsiOptions::instance()->getOption("options.ui.message.auto-popup").toBool() || PsiOptions::instance()->getOption("options.ui.chat.auto-popup").toBool() ); d->ck_popupHeadlines->setChecked( PsiOptions::instance()->getOption("options.ui.message.auto-popup-headlines").toBool() ); d->ck_popupFiles->setChecked( PsiOptions::instance()->getOption("options.ui.file-transfer.auto-popup").toBool() ); d->ck_allowAwayPopup->setChecked( !PsiOptions::instance()->getOption("options.ui.notifications.popup-dialogs.suppress-while-away").toBool() ); d->ck_allowUnlistedPopup->setChecked( !PsiOptions::instance()->getOption("options.ui.notifications.popup-dialogs.suppress-when-not-on-roster").toBool() ); d->ck_raise->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.raise-on-new-event").toBool() ); d->ck_ignoreNonRoster->setChecked( PsiOptions::instance()->getOption("options.messages.ignore-non-roster-contacts").toBool() ); d->cb_animation->setCurrentIndex(d->cb_animation->findData(PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString())); d->ck_autoAuth->setChecked( PsiOptions::instance()->getOption("options.subscriptions.automatically-allow-authorization").toBool() ); d->ck_notifyAuth->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.successful-subscription").toBool() ); d->cb_bounce->setCurrentIndex( d->cb_bounce->findData(PsiOptions::instance()->getOption("options.ui.notifications.bounce-dock").toString()) ); d->ck_popupOn->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.enabled").toBool() ); d->ck_popupOnMessage->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-message").toBool() || PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-chat").toBool() ); d->ck_popupOnHeadline->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-headline").toBool() ); d->ck_popupOnFile->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-file-transfer").toBool() ); d->ck_popupOnOnline->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.online").toBool() ); d->ck_popupOnOffline->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.offline").toBool() ); d->ck_popupOnStatus->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.other-changes").toBool() ); } psi-0.14/src/options/opt_sound.ui0000644000175000017500000003006511305557613015200 0ustar janjan OptSound 0 0 355 437 OptSoundUI 9 6 0 6 Player: Play sounds when away/XA Play sounds for all messages in groupchat QFrame::HLine QFrame::Sunken Qt::Horizontal 0 6 Enter a filename or !beep for a system beep Headline: Enter a filename or !beep for a system beep Receive online status: Enter a filename or !beep for a system beep Enter a filename or !beep for a system beep Receive message: Enter a filename or !beep for a system beep Send message: Enter a filename or !beep for a system beep System message: Enter a filename or !beep for a system beep Incoming file transfer: File transfer complete: Enter a filename or !beep for a system beep Enter a filename or !beep for a system beep Enter a filename or !beep for a system beep Receive next chat: Receive first chat: Receive offline status: 0 6 Qt::Horizontal QSizePolicy::Expanding 276 16 Reset to defaults qPixmapFromMimeSource le_player ck_awaySound ck_gcSound le_oeMessage tb_seMessage tb_seMessagePlay le_oeChat1 tb_seChat1 tb_seChat1Play le_oeChat2 tb_seChat2 tb_seChat2Play le_oeHeadline tb_seHeadline tb_seHeadlinePlay le_oeSystem tb_seSystem tb_seSystemPlay le_oeOnline tb_seOnline tb_seOnlinePlay le_oeOffline tb_seOffline tb_seOfflinePlay le_oeSend tb_seSend tb_seSendPlay le_oeIncomingFT tb_seIncomingFT tb_seIncomingFTPlay le_oeFTComplete tb_seFTComplete tb_seFTCompletePlay pb_soundReset psi-0.14/src/options/ui_options.ui0000644000175000017500000000521011305557613015350 0ustar janjan OptionsUI 0 0 408 293 Options 0 0 50 0 Qt::ScrollBarAlwaysOff 3 0 0 QFrame::HLine QFrame::Sunken Qt::Horizontal QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok qPixmapFromMimeSource FancyLabel QWidget
fancylabel.h
psi-0.14/src/options/opt_application.cpp0000644000175000017500000001355511305557613016525 0ustar janjan#include "opt_application.h" #include "common.h" #include "iconwidget.h" #include "psioptions.h" #include #include #include #include #include "ui_opt_application.h" class OptApplicationUI : public QWidget, public Ui::OptApplication { public: OptApplicationUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabApplication //---------------------------------------------------------------------------- OptionsTabApplication::OptionsTabApplication(QObject *parent) : OptionsTab(parent, "application", "", tr("Application"), tr("General application options"), "psi/logo_16") { w = 0; } OptionsTabApplication::~OptionsTabApplication() { } QWidget *OptionsTabApplication::widget() { if ( w ) return 0; w = new OptApplicationUI(); OptApplicationUI *d = (OptApplicationUI *)w; d->ck_alwaysOnTop->setWhatsThis( tr("Makes the main Psi window always be in front of other windows.")); d->ck_autoRosterSize->setWhatsThis( tr("Makes the main Psi window resize automatically to fit all contacts.")); d->ck_keepSizes->setWhatsThis( tr("Makes Psi remember window size and positions for chats and messages." " If disabled, the windows will always appear in their default positions and sizes.")); d->ck_useleft->setWhatsThis( tr("Normally, right-clicking with the mouse on a contact will activate the context-menu." " Check this option if you'd rather use a left-click.")); d->ck_showMenubar->setWhatsThis( tr("Shows the menubar in the application window.")); // docklet d->ck_docklet->setWhatsThis( tr("Makes Psi use a docklet icon, also known as system tray icon.")); d->ck_dockDCstyle->setWhatsThis( tr("Normally, single-clicking on the Psi docklet icon brings the main window to" " the foreground. Check this option if you would rather use a double-click.")); d->ck_dockHideMW->setWhatsThis( tr("Starts Psi with only the docklet icon visible.")); d->ck_dockToolMW->setWhatsThis( tr("Prevents Psi from taking up a slot on the taskbar and makes the main " "window use a small titlebar.")); #ifdef Q_WS_MAC d->ck_alwaysOnTop->hide(); d->ck_showMenubar->hide(); d->gb_docklet->hide(); #endif if (!haveAutoUpdater_) { d->ck_autoUpdate->hide(); } connect(d->le_dtPort, SIGNAL(textChanged(QString)), this, SLOT(updatePortLabel())); return w; } void OptionsTabApplication::setHaveAutoUpdater(bool b) { haveAutoUpdater_ = b; } void OptionsTabApplication::applyOptions() { if ( !w ) return; OptApplicationUI *d = (OptApplicationUI *)w; PsiOptions::instance()->setOption("options.ui.contactlist.always-on-top", d->ck_alwaysOnTop->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.automatically-resize-roster", d->ck_autoRosterSize->isChecked()); PsiOptions::instance()->setOption("options.ui.remember-window-sizes",d->ck_keepSizes->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.use-left-click", d->ck_useleft->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.show-menubar", d->ck_showMenubar->isChecked()); // Auto-update PsiOptions::instance()->setOption("options.auto-update.check-on-startup", d->ck_autoUpdate->isChecked()); // docklet PsiOptions::instance()->setOption("options.ui.systemtray.enable", d->ck_docklet->isChecked()); PsiOptions::instance()->setOption("options.ui.systemtray.use-double-click", d->ck_dockDCstyle->isChecked()); PsiOptions::instance()->setOption("options.contactlist.hide-on-start", d->ck_dockHideMW->isChecked()); PsiOptions::instance()->setOption("options.contactlist.use-toolwindow", d->ck_dockToolMW->isChecked()); // data transfer PsiOptions::instance()->setOption("options.p2p.bytestreams.listen-port", d->le_dtPort->text().toInt()); PsiOptions::instance()->setOption("options.p2p.bytestreams.external-address", d->le_dtExternal->text().trimmed()); } void OptionsTabApplication::restoreOptions() { if ( !w ) return; OptApplicationUI *d = (OptApplicationUI *)w; d->ck_alwaysOnTop->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.always-on-top").toBool() ); d->ck_autoRosterSize->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.automatically-resize-roster").toBool() ); d->ck_keepSizes->setChecked( PsiOptions::instance()->getOption("options.ui.remember-window-sizes").toBool() ); d->ck_showMenubar->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.show-menubar").toBool() ); d->ck_useleft->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.use-left-click").toBool() ); d->ck_autoUpdate->setChecked(PsiOptions::instance()->getOption("options.auto-update.check-on-startup").toBool()); // docklet d->ck_docklet->setChecked( PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() ); d->ck_dockDCstyle->setChecked( PsiOptions::instance()->getOption("options.ui.systemtray.use-double-click").toBool() ); d->ck_dockHideMW->setChecked( PsiOptions::instance()->getOption("options.contactlist.hide-on-start").toBool() ); d->ck_dockToolMW->setChecked( PsiOptions::instance()->getOption("options.contactlist.use-toolwindow").toBool() ); // data transfer d->le_dtPort->setText( QString::number(PsiOptions::instance()->getOption("options.p2p.bytestreams.listen-port").toInt()) ); d->le_dtExternal->setText( PsiOptions::instance()->getOption("options.p2p.bytestreams.external-address").toString() ); } void OptionsTabApplication::updatePortLabel() { if ( !w ) return; OptApplicationUI *d = (OptApplicationUI *)w; if ( d->le_dtPort->text().isEmpty() ) { d->label->clear(); return; } int port = d->le_dtPort->text().toInt(); if ( port < 0 || port > 65532 ) { d->label->clear(); return; } if ( port == 0 ) { d->label->setText(tr("(TCP: Disabled, UDP: Auto)")); } else { d->label->setText(tr("(TCP: %1, UDP: %1-%2)").arg( port ).arg( port + 3 )); } } psi-0.14/src/options/opt_advanced.cpp0000644000175000017500000001761611305557613015771 0ustar janjan#include "opt_advanced.h" #include "common.h" #include "iconwidget.h" #include #include #include #include #include #include "ui_opt_advanced.h" #include "psioptions.h" #include "spellchecker.h" class OptAdvancedUI : public QWidget, public Ui::OptAdvanced { public: OptAdvancedUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabAdvanced //---------------------------------------------------------------------------- OptionsTabAdvanced::OptionsTabAdvanced(QObject *parent) : OptionsTab(parent, "misc", "", tr("Misc."), tr("Extra uncategorized options"), "psi/advanced") { w = 0; } OptionsTabAdvanced::~OptionsTabAdvanced() { } QWidget *OptionsTabAdvanced::widget() { if ( w ) return 0; w = new OptAdvancedUI(); OptAdvancedUI *d = (OptAdvancedUI *)w; #ifdef Q_WS_X11 // auto-copy is a built-in feature on linux, we don't want user to use our own one d->ck_autocopy->hide(); #endif d->ck_spell->setEnabled(SpellChecker::instance()->available()); d->ck_messageevents->setWhatsThis( tr("Enables the sending and requesting of message events such as " "'Contact is Typing', ...")); d->ck_inactiveevents->setWhatsThis( tr("Enables the sending of events when you end or suspend a " "conversation")); d->ck_rc->setWhatsThis( tr("Enables remote controlling your client from other locations")); d->ck_spell->setWhatsThis( tr("Check this option if you want your spelling to be checked")); d->ck_contactsMessageFormatting->setWhatsThis( tr("If enabled, Psi will display incoming messages formatted in the style specified by the contact")); d->ck_autocopy->setWhatsThis( tr("Check this option if you want the selected text in incoming messages and chat log to be automatically copied to clipboard")); d->ck_singleclick->setWhatsThis( tr("Normally, a double-click on a contact will invoke the default action." " Check this option if you'd rather invoke with a single-click.")); d->ck_jidComplete->setWhatsThis( tr("Enables as-you-type JID autocompletion in message dialog.")); d->ck_grabUrls->setWhatsThis( tr("Automatically attaches URLs from clipboard to the messages when enabled")); d->cb_incomingAs->setWhatsThis( tr("

Specifies how to treat incoming events:

" "

Normal - messages come as messages, chats come as chats.

" "

Messages - All messages/chats come as messages, no matter what their original form was.

" "

Chats - All messages/chats come as chats, no matter what their original form was.

")); d->cb_incomingAs->setItemData(0, "no"); d->cb_incomingAs->setItemData(1, "message"); d->cb_incomingAs->setItemData(2, "chat"); d->cb_incomingAs->setItemData(3, "current-open"); d->ck_showSubjects->setWhatsThis( tr("Makes Psi show separate subject line in messages. Uncheck this if you want to save some screen space.")); d->ck_showCounter->setWhatsThis( tr("Makes Psi show message length counter. Check this if you want to know how long is your message. Can be useful when you're using SMS transport.")); d->ck_autoVCardOnLogin->setWhatsThis( tr("By default, Psi always checks your vCard on login. If you want to save some traffic, you can uncheck this option.")); d->ck_rosterAnim->setWhatsThis( tr("Makes Psi animate contact names in the main window when they come online.")); d->ck_scrollTo->setWhatsThis( tr("Makes Psi scroll the main window automatically so you can see new incoming events.")); d->ck_ignoreHeadline->setWhatsThis( tr("Makes Psi ignore all incoming \"headline\" events," " like system-wide news on MSN, announcements, etc.")); connect(d->ck_messageevents,SIGNAL(toggled(bool)),d->ck_inactiveevents,SLOT(setEnabled(bool))); d->ck_inactiveevents->setEnabled(d->ck_messageevents->isChecked()); return w; } void OptionsTabAdvanced::applyOptions() { if ( !w ) return; OptAdvancedUI *d = (OptAdvancedUI *)w; PsiOptions::instance()->setOption("options.messages.send-composing-events", d->ck_messageevents->isChecked()); PsiOptions::instance()->setOption("options.messages.send-inactivity-events", d->ck_inactiveevents->isChecked()); PsiOptions::instance()->setOption("options.external-control.adhoc-remote-control.enable", d->ck_rc->isChecked()); if ( SpellChecker::instance()->available() ) PsiOptions::instance()->setOption("options.ui.spell-check.enabled",d->ck_spell->isChecked()); PsiOptions::instance()->setOption("options.html.chat.render", d->ck_contactsMessageFormatting->isChecked()); PsiOptions::instance()->setOption("options.ui.automatically-copy-selected-text", d->ck_autocopy->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.use-single-click", d->ck_singleclick->isChecked()); PsiOptions::instance()->setOption("options.ui.message.use-jid-auto-completion", d->ck_jidComplete->isChecked()); PsiOptions::instance()->setOption("options.ui.message.auto-grab-urls-from-clipboard", d->ck_grabUrls->isChecked()); PsiOptions::instance()->setOption("options.messages.force-incoming-message-type", d->cb_incomingAs->itemData(d->cb_incomingAs->currentIndex())); PsiOptions::instance()->setOption("options.ui.message.show-subjects", d->ck_showSubjects->isChecked()); PsiOptions::instance()->setOption("options.ui.message.show-character-count", d->ck_showCounter->isChecked()); PsiOptions::instance()->setOption("options.vcard.query-own-vcard-on-login", d->ck_autoVCardOnLogin->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.use-status-change-animation", d->ck_rosterAnim->isChecked()); PsiOptions::instance()->setOption("options.ui.contactlist.ensure-contact-visible-on-event", d->ck_scrollTo->isChecked()); PsiOptions::instance()->setOption("options.messages.ignore-headlines", d->ck_ignoreHeadline->isChecked()); } void OptionsTabAdvanced::restoreOptions() { if ( !w ) return; OptAdvancedUI *d = (OptAdvancedUI *)w; d->ck_messageevents->setChecked( PsiOptions::instance()->getOption("options.messages.send-composing-events").toBool() ); d->ck_inactiveevents->setChecked( PsiOptions::instance()->getOption("options.messages.send-inactivity-events").toBool() ); d->ck_rc->setChecked( PsiOptions::instance()->getOption("options.external-control.adhoc-remote-control.enable").toBool() ); if ( !SpellChecker::instance()->available() ) d->ck_spell->setChecked(false); else d->ck_spell->setChecked(PsiOptions::instance()->getOption("options.ui.spell-check.enabled").toBool()); d->ck_contactsMessageFormatting->setChecked(PsiOptions::instance()->getOption("options.html.chat.render").toBool()); d->ck_autocopy->setChecked( PsiOptions::instance()->getOption("options.ui.automatically-copy-selected-text").toBool() ); d->ck_singleclick->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.use-single-click").toBool() ); d->ck_jidComplete->setChecked( PsiOptions::instance()->getOption("options.ui.message.use-jid-auto-completion").toBool() ); d->ck_grabUrls->setChecked( PsiOptions::instance()->getOption("options.ui.message.auto-grab-urls-from-clipboard").toBool() ); d->cb_incomingAs->setCurrentIndex(d->cb_incomingAs->findData( PsiOptions::instance()->getOption("options.messages.force-incoming-message-type").toString())); d->ck_showSubjects->setChecked( PsiOptions::instance()->getOption("options.ui.message.show-subjects").toBool() ); d->ck_showCounter->setChecked( PsiOptions::instance()->getOption("options.ui.message.show-character-count").toBool() ); d->ck_autoVCardOnLogin->setChecked( PsiOptions::instance()->getOption("options.vcard.query-own-vcard-on-login").toBool() ); d->ck_rosterAnim->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.use-status-change-animation").toBool() ); d->ck_scrollTo->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.ensure-contact-visible-on-event").toBool() ); d->ck_ignoreHeadline->setChecked( PsiOptions::instance()->getOption("options.messages.ignore-headlines").toBool() ); } psi-0.14/src/options/opt_avcall.ui0000644000175000017500000000375211305557613015315 0ustar janjan OptAvCall 0 0 400 108 Form Audio output: 0 0 Audio input: 0 0 Video input: 0 0 cb_audioOutDevice cb_audioInDevice cb_videoInDevice psi-0.14/src/options/opt_iconset_emo.ui0000644000175000017500000000673011305557613016356 0ustar janjan IconsetEmo 0 0 256 195 IconsetEmoUI 9 6 Enable emoticons true Emoticon iconsets 8 6 psi/arrowDown false psi/arrowUp false Qt::Horizontal QSizePolicy::Expanding 204 20 &Show details QAbstractItemView::MultiSelection Qt::Horizontal qPixmapFromMimeSource IconButton
iconbutton.h
0
IconsetSelect
iconsetselect.h
0
psi-0.14/src/options/opt_application.ui0000644000175000017500000001355311305557613016356 0ustar janjan OptApplication 0 0 304 402 OptApplicationUI Roster window always on top Auto-resize contact list Remember window sizes true Use left-click for menu Show menubar Enable docklet true Docklet 6 10 10 10 10 Use "double-click" style (like ICQ) Start minimized Make roster window a "tool window" Check for updates on startup true Data transfer base port: 56 0 99999; 5 56 32767 (1 TCP, 4 UDP) Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 0 0 0 Data transfer external address: Qt::Vertical 20 40 qPixmapFromMimeSource ck_alwaysOnTop ck_autoRosterSize ck_keepSizes ck_useleft ck_showMenubar ck_docklet ck_dockDCstyle ck_dockHideMW ck_dockToolMW le_dtPort le_dtExternal psi-0.14/src/options/ui_isdetails.ui0000644000175000017500000002001611305557613015637 0ustar janjan IconsetDetailsDlg 0 0 552 376 550 0 550 0 Iconset Details: %1 0 0 <a href="http://psi-im.org">psi-im.org</a> 0 0 Description: 0 0 0 0 Authors: 0 0 Creation date: 0 0 Version: 0 0 Home URL: 0 0 XXX Qt::AlignVCenter true 0 0 XXX Qt::AlignVCenter true 0 0 XXX Qt::AlignVCenter true 0 0 Name: 0 0 XXX Qt::AlignVCenter true 0 0 QDialogButtonBox::Close qPixmapFromMimeSource URLLabel
urllabel.h
PsiTextView
psitextview.h
IconsetDisplay
iconsetdisplay.h
iconset.h buttonBox rejected() IconsetDetailsDlg reject() 517 304 547 268
psi-0.14/src/options/opt_sound.cpp0000644000175000017500000002137011305557613015344 0ustar janjan#include "opt_sound.h" #include #include #include #include #include #include #include #include #include "common.h" #include "iconwidget.h" #include "iconset.h" #include "applicationinfo.h" #include "psioptions.h" #include "fileutil.h" #include "ui_opt_sound.h" class OptSoundUI : public QWidget, public Ui::OptSound { public: OptSoundUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabSound //---------------------------------------------------------------------------- OptionsTabSound::OptionsTabSound(QObject *parent) : OptionsTab(parent, "sound", "", tr("Sound"), tr("Configure how Psi sounds"), "psi/playSounds") { w = 0; bg_se = bg_sePlay = 0; } OptionsTabSound::~OptionsTabSound() { if ( bg_se ) delete bg_se; if ( bg_sePlay ) delete bg_sePlay; } QWidget *OptionsTabSound::widget() { if ( w ) return 0; w = new OptSoundUI(); OptSoundUI *d = (OptSoundUI *)w; sounds_ << d->le_oeMessage << d->le_oeChat1 << d->le_oeChat2 << d->le_oeHeadline << d->le_oeSystem << d->le_oeOnline << d->le_oeOffline << d->le_oeSend << d->le_oeIncomingFT << d->le_oeFTComplete; bg_se = new QButtonGroup; bg_se->addButton(d->tb_seMessage); modify_buttons_[d->tb_seMessage] = d->le_oeMessage; bg_se->addButton(d->tb_seChat1); modify_buttons_[d->tb_seChat1] = d->le_oeChat1; bg_se->addButton(d->tb_seChat2); modify_buttons_[d->tb_seChat2] = d->le_oeChat2; bg_se->addButton(d->tb_seHeadline); modify_buttons_[d->tb_seHeadline] = d->le_oeHeadline; bg_se->addButton(d->tb_seSystem); modify_buttons_[d->tb_seSystem] = d->le_oeSystem; bg_se->addButton(d->tb_seOnline); modify_buttons_[d->tb_seOnline] = d->le_oeOnline; bg_se->addButton(d->tb_seOffline); modify_buttons_[d->tb_seOffline] = d->le_oeOffline; bg_se->addButton(d->tb_seSend); modify_buttons_[d->tb_seSend] = d->le_oeSend; bg_se->addButton(d->tb_seIncomingFT); modify_buttons_[d->tb_seIncomingFT] = d->le_oeIncomingFT; bg_se->addButton(d->tb_seFTComplete); modify_buttons_[d->tb_seFTComplete] = d->le_oeFTComplete; connect(bg_se, SIGNAL(buttonClicked(QAbstractButton*)), SLOT(chooseSoundEvent(QAbstractButton*))); bg_sePlay = new QButtonGroup; bg_sePlay->addButton(d->tb_seMessagePlay); play_buttons_[d->tb_seMessagePlay] = d->le_oeMessage; bg_sePlay->addButton(d->tb_seChat1Play); play_buttons_[d->tb_seChat1Play] = d->le_oeChat1; bg_sePlay->addButton(d->tb_seChat2Play); play_buttons_[d->tb_seChat2Play] = d->le_oeChat2; bg_sePlay->addButton(d->tb_seHeadlinePlay); play_buttons_[d->tb_seHeadlinePlay] = d->le_oeHeadline; bg_sePlay->addButton(d->tb_seSystemPlay); play_buttons_[d->tb_seSystemPlay] = d->le_oeSystem; bg_sePlay->addButton(d->tb_seOnlinePlay); play_buttons_[d->tb_seOnlinePlay] = d->le_oeOnline; bg_sePlay->addButton(d->tb_seOfflinePlay); play_buttons_[d->tb_seOfflinePlay] = d->le_oeOffline; bg_sePlay->addButton(d->tb_seSendPlay); play_buttons_[d->tb_seSendPlay] = d->le_oeSend; bg_sePlay->addButton(d->tb_seIncomingFTPlay); play_buttons_[d->tb_seIncomingFTPlay] = d->le_oeIncomingFT; bg_sePlay->addButton(d->tb_seFTCompletePlay); play_buttons_[d->tb_seFTCompletePlay] = d->le_oeFTComplete; connect(bg_sePlay, SIGNAL(buttonClicked(QAbstractButton*)), SLOT(previewSoundEvent(QAbstractButton*))); connect(d->pb_soundReset, SIGNAL(clicked()), SLOT(soundReset())); // set up proper tool button icons int n; for (n = 0; n < 10; n++) { IconToolButton *tb = (IconToolButton *)bg_se->buttons()[n]; tb->setPsiIcon( IconsetFactory::iconPtr("psi/browse") ); tb = (IconToolButton *)bg_sePlay->buttons()[n]; tb->setPsiIcon( IconsetFactory::iconPtr("psi/play") ); } // TODO: add QWhatsThis for all widgets d->le_player->setWhatsThis( tr("If your system supports multiple sound players, you may" " choose your preferred sound player application here.")); d->ck_awaySound->setWhatsThis( tr("Enable this option if you wish to hear sound alerts when your status is \"away\" or \"extended away\".")); d->ck_gcSound->setWhatsThis( tr("Play sounds for all events in groupchat, not only for mentioning of your nick.")); #if defined(Q_WS_WIN) d->lb_player->hide(); d->le_player->hide(); #elif defined(Q_WS_MAC) d->lb_player->hide(); d->le_player->hide(); #endif return w; } void OptionsTabSound::applyOptions() { if ( !w ) return; OptSoundUI *d = (OptSoundUI *)w; PsiOptions::instance()->setOption("options.ui.notifications.sounds.unix-sound-player", d->le_player->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.silent-while-away", !d->ck_awaySound->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.notify-every-muc-message", d->ck_gcSound->isChecked()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.incoming-message", d->le_oeMessage->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.new-chat", d->le_oeChat1->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.chat-message", d->le_oeChat2->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.system-message", d->le_oeSystem->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.incoming-headline", d->le_oeHeadline->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.contact-online", d->le_oeOnline->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.contact-offline", d->le_oeOffline->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.outgoing-chat", d->le_oeSend->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.incoming-file-transfer", d->le_oeIncomingFT->text()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.completed-file-transfer", d->le_oeFTComplete->text()); } void OptionsTabSound::restoreOptions() { if ( !w ) return; OptSoundUI *d = (OptSoundUI *)w; #if defined(Q_WS_WIN) d->le_player->setText(tr("Windows Sound")); #elif defined(Q_WS_MAC) d->le_player->setText(tr("Mac OS Sound")); #else d->le_player->setText( PsiOptions::instance()->getOption("options.ui.notifications.sounds.unix-sound-player").toString() ); #endif d->ck_awaySound->setChecked( !PsiOptions::instance()->getOption("options.ui.notifications.sounds.silent-while-away").toBool() ); d->ck_gcSound->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.sounds.notify-every-muc-message").toBool() ); d->le_oeMessage->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-message").toString()); d->le_oeChat1->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.new-chat").toString()); d->le_oeChat2->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.chat-message").toString()); d->le_oeSystem->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.system-message").toString()); d->le_oeHeadline->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-headline").toString()); d->le_oeOnline->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.contact-online").toString()); d->le_oeOffline->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.contact-offline").toString()); d->le_oeSend->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.outgoing-chat").toString()); d->le_oeIncomingFT->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-file-transfer").toString()); d->le_oeFTComplete->setText(PsiOptions::instance()->getOption("options.ui.notifications.sounds.completed-file-transfer").toString()); } void OptionsTabSound::setData(PsiCon *, QWidget *p) { parentWidget = p; } void OptionsTabSound::chooseSoundEvent(QAbstractButton* b) { QString str = FileUtil::getOpenFileName(parentWidget, tr("Choose a sound file"), tr("Sound (*.wav)")); if (!str.isEmpty()) { modify_buttons_[b]->setText(str); emit dataChanged(); } } void OptionsTabSound::previewSoundEvent(QAbstractButton* b) { soundPlay(play_buttons_[b]->text()); } void OptionsTabSound::soundReset() { OptSoundUI *d = (OptSoundUI *)w; d->le_oeMessage->setText("sound/chat2.wav"); d->le_oeChat1->setText("sound/chat1.wav"); d->le_oeChat2->setText("sound/chat2.wav"); d->le_oeSystem->setText("sound/chat2.wav"); d->le_oeHeadline->setText("sound/chat2.wav"); d->le_oeOnline->setText("sound/online.wav"); d->le_oeOffline->setText("sound/offline.wav"); d->le_oeSend->setText("sound/send.wav"); d->le_oeIncomingFT->setText("sound/ft_incoming.wav"); d->le_oeFTComplete->setText("sound/ft_complete.wav"); emit dataChanged(); } psi-0.14/src/options/opt_events.ui0000644000175000017500000001742111305557613015355 0ustar janjan OptEvents 0 0 347 588 OptEventsUI 9 6 Auto-open new messages Auto-open new headlines Auto-open new files Allow auto-open even when Away/XA Allow auto-open even from unlisted users Raise roster window on new event Ignore events from contacts not already in your roster Auto-authorize contacts Notify when authorization was received 0 6 Bounce dock: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter cb_bounce Never Once Forever Qt::Horizontal 174 20 0 6 Animation: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter cb_animation No animation Blink Animate Qt::Horizontal 139 20 Enable popup notifications true Popup notifications 10 6 On incoming message event On incoming headline event On incoming file event When a contact becomes available When a contact becomes unavailable When a contact changes status qPixmapFromMimeSource ck_popupMsgs ck_popupHeadlines ck_popupFiles ck_allowAwayPopup ck_allowUnlistedPopup ck_raise ck_ignoreNonRoster ck_autoAuth ck_notifyAuth cb_bounce cb_animation ck_popupOn ck_popupOnMessage ck_popupOnHeadline ck_popupOnFile ck_popupOnOnline ck_popupOnOffline ck_popupOnStatus ck_popupOn toggled(bool) groupBox1 setEnabled(bool) 158 384 158 425 psi-0.14/src/options/opt_application.h0000644000175000017500000000070111305557613016157 0ustar janjan#ifndef OPT_APPLICATION_H #define OPT_APPLICATION_H #include "optionstab.h" class QWidget; class QButtonGroup; class OptionsTabApplication : public OptionsTab { Q_OBJECT public: OptionsTabApplication(QObject *parent); ~OptionsTabApplication(); void setHaveAutoUpdater(bool); QWidget *widget(); void applyOptions(); void restoreOptions(); private slots: void updatePortLabel(); private: QWidget *w; bool haveAutoUpdater_; }; #endif psi-0.14/src/options/opt_advanced.ui0000644000175000017500000001071411305557613015614 0ustar janjan OptAdvanced 0 0 509 429 OptAdvancedUI 9 6 Enable "Contact is typing ..." events Enable "Inactivity" events (end/suspend conversation) Enable remote controlling from other locations Check spelling Use contacts' message formatting Single-click triggers default action Automatically copy selected text to clipboard Grab URLs from clipboard Jabber ID completion Show subject line in events Show character counter Automatically get vCard when becoming online Animate the roster when a contact comes online Scroll roster to contact on event Ignore "Headline" events (e.g. MSN alerts) 0 6 Treat incoming messages and chats as: Determined by sender Messages Chats Messages (Chats if Chatting) qPixmapFromMimeSource psi-0.14/src/options/opt_shortcuts.cpp0000644000175000017500000003400011305557613016244 0ustar janjan/* * opt_shortcuts.cpp - an OptionsTab for setting the Keyboard Shortcuts of Psi * Copyright (C) 2006 Cestonaro Thilo * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "opt_shortcuts.h" #include #include "common.h" #include "psioptions.h" #include "shortcutmanager.h" #include "grepshortcutkeydialog.h" #include "ui_opt_shortcuts.h" #define ITEMKIND Qt::UserRole #define OPTIONSTREEPATH Qt::UserRole + 1 /** * \class the Ui for the Options Tab Shortcuts */ class OptShortcutsUI : public QWidget, public Ui::OptShortcuts { public: OptShortcutsUI() : QWidget() { setupUi(this); } }; //---------------------------------------------------------------------------- // OptionsTabShortcuts //---------------------------------------------------------------------------- /** * \brief Constructor of the Options Tab Shortcuts Class */ OptionsTabShortcuts::OptionsTabShortcuts(QObject *parent) : OptionsTab(parent, "shortcuts", "", tr("Shortcuts"), tr("Options for Psi Shortcuts"), "psi/shortcuts") { w = 0; } /** * \brief Destructor of the Options Tab Shortcuts Class */ OptionsTabShortcuts::~OptionsTabShortcuts() { } /** * \brief widget, creates the Options Tab Shortcuts Widget * \return QWidget*, points to the previously created widget */ QWidget *OptionsTabShortcuts::widget() { if ( w ) return 0; w = new OptShortcutsUI(); OptShortcutsUI *d = (OptShortcutsUI *)w; d->treeShortcuts->setColumnWidth(0, 320); d->add->setEnabled(false); d->remove->setEnabled(false); d->edit->setEnabled(false); connect(d->treeShortcuts, SIGNAL(itemSelectionChanged()), this, SLOT(onItemSelectionChanged())); connect(d->treeShortcuts, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem *, int))); connect(d->add, SIGNAL(clicked()), this, SLOT(onAdd())); connect(d->remove, SIGNAL(clicked()), this, SLOT(onRemove())); connect(d->edit, SIGNAL(clicked()), this, SLOT(onEdit())); connect(d->restoreDefaults, SIGNAL(clicked()), this, SLOT(onRestoreDefaults())); return w; } /** * \brief applyOptions, if options have changed, they will be applied by calling this function * \param opt, unused, totally ignored */ void OptionsTabShortcuts::applyOptions() { if ( !w ) return; OptShortcutsUI *d = (OptShortcutsUI *)w; PsiOptions *options = PsiOptions::instance(); int toplevelItemsCount = d->treeShortcuts->topLevelItemCount(); int shortcutItemsCount; int keyItemsCount; QTreeWidgetItem *topLevelItem; QTreeWidgetItem *shortcutItem; QTreeWidgetItem *keyItem; QString optionsPath; QString comment; QList children; QList keys; /* step through the Toplevel Items */ for(int topLevelIndex = 0 ; topLevelIndex < toplevelItemsCount; topLevelIndex++) { topLevelItem = d->treeShortcuts->topLevelItem(topLevelIndex); shortcutItemsCount = topLevelItem->childCount(); /* step through the Shortcut Items */ for(int shortcutItemIndex = 0; shortcutItemIndex < shortcutItemsCount; shortcutItemIndex++) { shortcutItem = topLevelItem->child(shortcutItemIndex); keyItemsCount = shortcutItem->childCount(); /* get the Options Path of the Shortcut Item */ optionsPath = shortcutItem->data(0, OPTIONSTREEPATH).toString(); /* just one Key Sequence */ if(keyItemsCount == 1) { /* so set the option to this keysequence directly */ keyItem = shortcutItem->child(0); options->setOption(optionsPath, QVariant(keyItem->text(1))); } else if(keyItemsCount > 1){ /* more than one, then collect them in a list */ QList keySequences; for(int keyItemIndex = 0; keyItemIndex < keyItemsCount; keyItemIndex++) { keyItem = shortcutItem->child(keyItemIndex); keySequences.append(QVariant(keyItem->text(1))); } options->setOption(optionsPath, QVariant(keySequences)); } else { /* zero key sequences, so set an empty string, so it will be written empty to the options.xml */ options->setOption(optionsPath, ""); } } } } /** * \brief restoreOptions, reads in the currently set options */ void OptionsTabShortcuts::restoreOptions() { if ( !w ) return; readShortcuts(PsiOptions::instance()); } /** * \brief readShortcuts, reads shortcuts from given PsiOptions instance */ void OptionsTabShortcuts::readShortcuts(const PsiOptions *options) { OptShortcutsUI *d = (OptShortcutsUI *)w; QTreeWidgetItem *topLevelItem; QList shortcutGroups = options->getChildOptionNames("options.shortcuts", true, true); /* step through the shortcut groups e.g. chatdlg */ foreach(QString shortcutGroup, shortcutGroups) { topLevelItem = new QTreeWidgetItem(d->treeShortcuts); QString comment = options->getComment(shortcutGroup); if (comment.isNull()) { comment = tr("Unnamed group"); } else { comment = translateShortcut(comment); } topLevelItem->setText(0, comment); topLevelItem->setData(0, OPTIONSTREEPATH, QVariant(shortcutGroup)); topLevelItem->setData(0, ITEMKIND, QVariant((int)OptionsTabShortcuts::TopLevelItem)); topLevelItem->setExpanded(true); d->treeShortcuts->addTopLevelItem(topLevelItem); } int toplevelItemsCount = d->treeShortcuts->topLevelItemCount(); QTreeWidgetItem *shortcutItem; QTreeWidgetItem *keyItem; QString optionsPath; QString comment; QList shortcuts; QList keys; int keyItemsCount; /* step through the toplevel items */ for(int toplevelItemIndex = 0 ; toplevelItemIndex < toplevelItemsCount; toplevelItemIndex++) { topLevelItem = d->treeShortcuts->topLevelItem(toplevelItemIndex); optionsPath = topLevelItem->data(0, OPTIONSTREEPATH).toString(); /* if a optionsPath was saved in the toplevel item, we can get the shortcuts and the keys for the shortcuts */ if(!optionsPath.isEmpty()) { shortcuts = options->getChildOptionNames(optionsPath, true, true); /* step through the shortcuts */ foreach(QString shortcut, shortcuts) { keys = ShortcutManager::readShortcutsFromOptions(shortcut.mid(QString("options.shortcuts").length() + 1), options); comment = options->getComment(shortcut); if (comment.isNull()) { comment = tr("Unnamed group"); } else { comment = translateShortcut(comment); } /* create the TreeWidgetItem and set the Data the Kind and it's Optionspath and append it */ shortcutItem = new QTreeWidgetItem(topLevelItem); shortcutItem->setText(0, comment); shortcutItem->setData(0, ITEMKIND, QVariant((int)OptionsTabShortcuts::ShortcutItem)); shortcutItem->setData(0, OPTIONSTREEPATH, QVariant(shortcut)); topLevelItem->addChild(shortcutItem); /* step through this shortcut's keys and create 'Key XXXX' entries for them */ keyItemsCount = 1; foreach(QKeySequence key, keys) { keyItem = new QTreeWidgetItem(shortcutItem); keyItem->setText(0, QString(tr("Key %1")).arg(keyItemsCount++)); keyItem->setData(0, ITEMKIND, QVariant((int)OptionsTabShortcuts::KeyItem)); keyItem->setText(1, key.toString(QKeySequence::NativeText)); shortcutItem->addChild(keyItem); } } } } } /** * \brief Button Add pressed, creates a new Key entry */ void OptionsTabShortcuts::onAdd() { OptShortcutsUI *d = (OptShortcutsUI *)w; QTreeWidgetItem *shortcutItem; QList selectedItems = d->treeShortcuts->selectedItems(); QString optionsPath; Kind itemKind; if(selectedItems.count() == 0) return; shortcutItem = selectedItems[0]; itemKind = (Kind)shortcutItem->data(0, ITEMKIND).toInt(); switch(itemKind) { case OptionsTabShortcuts::KeyItem: /* it was a keyItem, so get it's parent */ shortcutItem = shortcutItem->parent(); break; case OptionsTabShortcuts::ShortcutItem: break; default: return; } addTo(shortcutItem); } /** * \brief Adds a new key to given shortcut item * \param shortcutItem, new key parent, must be a ShortcutItem */ void OptionsTabShortcuts::addTo(QTreeWidgetItem *shortcutItem) { OptShortcutsUI *d = (OptShortcutsUI *)w; QList selectedItems = d->treeShortcuts->selectedItems(); QTreeWidgetItem *newKeyItem = new QTreeWidgetItem(shortcutItem); newKeyItem->setText(0, QString(tr("Key %1")).arg(shortcutItem->childCount())); newKeyItem->setData(0, ITEMKIND, QVariant(OptionsTabShortcuts::KeyItem)); shortcutItem->addChild(newKeyItem); if (selectedItems.count()) selectedItems[0]->setSelected(false); newKeyItem->setExpanded(true); newKeyItem->setSelected(true); grep(); } /** * \brief Button Remove pressed, removes the currently selected item, if it is a Keyitem */ void OptionsTabShortcuts::onRemove() { OptShortcutsUI *d = (OptShortcutsUI *)w; QList selectedItems = d->treeShortcuts->selectedItems(); if(selectedItems.count() == 0) return; QTreeWidgetItem *shortcutItem; QTreeWidgetItem *keyItem; int keyItemsCount; keyItem = selectedItems[0]; /* we need a Item with the Kind "KeyItem", else we could / should not remove it */ if((Kind)keyItem->data(0, ITEMKIND).toInt() == OptionsTabShortcuts::KeyItem) { shortcutItem = keyItem->parent(); /* remove the key item from the shortcut item's children */ shortcutItem->takeChild(shortcutItem->indexOfChild(keyItem)); /* rename the children which are left over */ keyItemsCount = shortcutItem->childCount(); for( int keyItemIndex = 0; keyItemIndex < keyItemsCount; keyItemIndex++) shortcutItem->child(keyItemIndex)->setText(0, QString(tr("Key %1")).arg(keyItemIndex + 1)); /* notify the options dlg that data was changed */ emit dataChanged(); } } /** * \brief Button Edit pressed, edits the currently selected item if it is a key */ void OptionsTabShortcuts::onEdit() { OptShortcutsUI *d = (OptShortcutsUI *)w; QList selectedItems = d->treeShortcuts->selectedItems(); if(selectedItems.count() == 0) return; QTreeWidgetItem *keyItem = selectedItems[0]; if((Kind)keyItem->data(0, ITEMKIND).toInt() == OptionsTabShortcuts::KeyItem) grep(); } /** * \brief Button Restore Defaults pressed */ void OptionsTabShortcuts::onRestoreDefaults() { if (QMessageBox::information(w, CAP(tr("Restore default shortcuts")), tr("Are you sure you would like to restore the default shortcuts?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { OptShortcutsUI *d = (OptShortcutsUI *)w; d->treeShortcuts->clear(); readShortcuts(PsiOptions::defaults()); emit dataChanged(); } } /** * \brief Opens grep dialog. */ void OptionsTabShortcuts::grep() { GrepShortcutKeyDialog* grep = new GrepShortcutKeyDialog(); connect(grep, SIGNAL(newShortcutKey(const QKeySequence&)), this, SLOT(onNewShortcutKey(const QKeySequence&))); grep->show(); } /** * \brief in the treeview, the selected item has changed, the add and remove buttons are * enabled or disabled, depening on the selected item type */ void OptionsTabShortcuts::onItemSelectionChanged() { OptShortcutsUI *d = (OptShortcutsUI *)w; QList selectedItems = d->treeShortcuts->selectedItems(); Kind itemKind; /* zero selected Item(s), so we can't add or remove anything, disable the buttons */ if(selectedItems.count() == 0) { d->add->setEnabled(false); d->remove->setEnabled(false); d->edit->setEnabled(false); return; } itemKind = (Kind)selectedItems[0]->data(0, ITEMKIND).toInt(); switch(itemKind) { case OptionsTabShortcuts::TopLevelItem: /* for a topLevel Item, we can't do anything neither add a key, nor remove one */ d->add->setEnabled(false); d->remove->setEnabled(false); d->edit->setEnabled(false); break; case OptionsTabShortcuts::ShortcutItem: /* at a shortcut Item, we can add a key, but not remove it */ d->add->setEnabled(true); d->remove->setEnabled(false); d->edit->setEnabled(false); break; case OptionsTabShortcuts::KeyItem: /* at a key item, we can add a key to it's parent shortcut item, or remove it */ d->add->setEnabled(true); d->remove->setEnabled(true); d->edit->setEnabled(true); break; } } /** * \brief an item of the treeview is double clicked, if it is a Keyitem, the GrepShortcutKeyDialog is shown */ void OptionsTabShortcuts::onItemDoubleClicked(QTreeWidgetItem *item, int column) { Q_UNUSED(column); if (!item) return; Kind itemKind = (Kind)item->data(0, ITEMKIND).toInt(); if (itemKind == KeyItem) grep(); else if (itemKind == ShortcutItem && item->childCount() == 0) addTo(item); } /** * \brief slot onNewShortcutKey is called when the grepShortcutKeyDialog has captured a KeySequence, * so the new KeySequence can be set to the KeyItem * \param the new KeySequence for the keyitem */ void OptionsTabShortcuts::onNewShortcutKey(const QKeySequence& key) { OptShortcutsUI *d = (OptShortcutsUI *)w; QTreeWidgetItem *keyItem; QList selectedItems = d->treeShortcuts->selectedItems(); QString optionsPath; Kind itemKind; if(selectedItems.count() == 0) return; keyItem = selectedItems[0]; itemKind = (OptionsTabShortcuts::Kind)keyItem->data(0, ITEMKIND).toInt(); /* if we got a key item, set the new key sequence and notify the options dialog that data has changed */ if(itemKind == OptionsTabShortcuts::KeyItem) { keyItem->setText(1, key.toString(QKeySequence::NativeText)); emit dataChanged(); } } /** * \brief Translate the \param comment in the "Shortcuts" translation Context * \param comment the text to be translated */ QString OptionsTabShortcuts::translateShortcut(QString comment) { return QCoreApplication::translate("Shortcuts", comment.toLatin1()); } psi-0.14/src/options/optionsdlg.cpp0000644000175000017500000003734211305557613015522 0ustar janjan/* * optionsdlg.cpp * Copyright (C) 2003-2009 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "optionsdlg.h" #include "optionstab.h" #include "common.h" #include "psicon.h" #include "fancylabel.h" #include "iconset.h" #include "iconwidget.h" #include #include #include #include #include #include #include #include #include // tabs #include "opt_toolbars.h" #include "opt_application.h" #include "opt_appearance.h" #include "opt_chat.h" #include "opt_events.h" #include "opt_status.h" #include "opt_iconset.h" #include "opt_groupchat.h" #include "opt_sound.h" #include "opt_avcall.h" #include "opt_advanced.h" #include "opt_shortcuts.h" #include "opt_tree.h" #ifdef PSI_PLUGINS #include "opt_plugins.h" #endif #include "../avcall/avcall.h" //---------------------------------------------------------------------------- // OptionsTabsDelegate //---------------------------------------------------------------------------- class OptionsTabsDelegate : public QItemDelegate { public: OptionsTabsDelegate(QObject* parent) : QItemDelegate(parent) {} // reimplemented virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { QStyleOptionViewItemV4 opt(option); opt.showDecorationSelected = true; opt.rect.adjust(0, 0, 0, -1); painter->save(); QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); QIcon icon = index.data(Qt::DecorationRole).value(); QSize iconSize; #if 0 if (icon.availableSizes().isEmpty()) iconSize = icon.availableSizes().first(); else #endif iconSize = QSize(16, 16); QRect iconRect = opt.rect; iconRect.setLeft(4); iconRect.setWidth(iconSize.width()); icon.paint(painter, iconRect, Qt::AlignCenter, QIcon::Normal, QIcon::On); QRect textRect = opt.rect; textRect.setLeft(iconRect.right() + 8); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) cg = QPalette::Inactive; if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); } painter->drawText(textRect, index.data(Qt::DisplayRole).toString(), Qt::AlignLeft | Qt::AlignVCenter); drawFocus(painter, option, option.rect); // not opt, because drawFocus() expects normal rect painter->restore(); painter->save(); QPen pen(QColor(0xE0, 0xE0, 0xE0)); QVector dashes; dashes << 1.0 << 1.0; pen.setCapStyle(Qt::FlatCap); pen.setDashPattern(dashes); painter->setPen(pen); painter->drawLine(option.rect.left(), option.rect.bottom(), option.rect.right(), option.rect.bottom()); painter->restore(); } // reimplemented void drawFocus(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect) const { if (option.state & QStyle::State_HasFocus && rect.isValid()) { QStyleOptionFocusRect o; o.QStyleOption::operator=(option); o.rect = rect.adjusted(0, 0, 0, -1); QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Window); QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); } } // reimplemented virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { QIcon icon = index.data(Qt::DecorationRole).value(); QSize iconSize; #if 0 if (!icon.availableSizes().isEmpty()) iconSize = icon.availableSizes().first(); else #endif iconSize = QSize(16, 16); int width = iconSize.width(); width += 8; width += option.fontMetrics.width(index.data(Qt::DisplayRole).toString()); width += 8; int height = iconSize.height(); height = qMax(height, option.fontMetrics.height()); height += 8; return QSize(width, height); } }; //---------------------------------------------------------------------------- // OptionsDlg::Private //---------------------------------------------------------------------------- class OptionsDlg::Private : public QObject { Q_OBJECT public: Private(OptionsDlg *dlg, PsiCon *_psi); public slots: void doApply(); void openTab(QString id); private slots: void currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous); void dataChanged(); void noDirtySlot(bool); void createTabs(); void createChangedMap(); //void addWidgetChangedSignal(QString widgetName, QCString signal); void connectDataChanged(QWidget *); public: OptionsDlg *dlg; PsiCon *psi; bool dirty, noDirty; QHash id2widget; QList tabs; QMap changedMap; }; OptionsDlg::Private::Private(OptionsDlg *d, PsiCon *_psi) { dlg = d; psi = _psi; noDirty = false; dirty = false; dlg->lb_pageTitle->setScaledContents(32, 32); // FancyLabel stinks dlg->lb_pageTitle->hide(); QAbstractItemDelegate* previousDelegate = dlg->lv_tabs->itemDelegate(); delete previousDelegate; dlg->lv_tabs->setItemDelegate(new OptionsTabsDelegate(dlg->lv_tabs)); createTabs(); createChangedMap(); QStyleOptionViewItem option; option.fontMetrics = dlg->lv_tabs->fontMetrics(); int maxWidth = 0; foreach(OptionsTab* opttab, tabs) { //qWarning("Adding tab %s...", (const char *)opttab->id()); opttab->setData(psi, dlg); connect(opttab, SIGNAL(dataChanged()), SLOT(dataChanged())); //connect(opttab, SIGNAL(addWidgetChangedSignal(QString, QCString)), SLOT(addWidgetChangedSignal(QString, QCString))); connect(opttab, SIGNAL(noDirty(bool)), SLOT(noDirtySlot(bool))); connect(opttab, SIGNAL(connectDataChanged(QWidget *)), SLOT(connectDataChanged(QWidget *))); if ( opttab->id().isEmpty() ) continue; dlg->lv_tabs->addItem(opttab->tabName()); QListWidgetItem* item = dlg->lv_tabs->item(dlg->lv_tabs->count() - 1); dlg->lv_tabs->setCurrentItem(item); QModelIndex index = dlg->lv_tabs->currentIndex(); if (opttab->tabIcon()) item->setData(Qt::DecorationRole, opttab->tabIcon()->icon()); item->setData(Qt::UserRole, opttab->id()); int width = dlg->lv_tabs->itemDelegate()->sizeHint(option, index).width() + dlg->lv_tabs->verticalScrollBar()->sizeHint().width(); maxWidth = qMax(width, maxWidth); } dlg->lv_tabs->setFixedWidth(maxWidth); openTab( "application" ); connect(dlg->lv_tabs, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SLOT(currentItemChanged(QListWidgetItem*, QListWidgetItem*))); dirty = false; dlg->pb_apply->setEnabled(false); } void OptionsDlg::Private::createTabs() { // tabs - base /*tabs.append( new OptionsTabGeneral(this) ); //tabs.append( new OptionsTabBase(this, "general", "", "psi/logo_16", tr("General"), tr("General preferences list")) ); tabs.append( new OptionsTabEvents(this) ); //tabs.append( new OptionsTabBase(this, "events", "", "psi/system", tr("Events"), tr("Change the events behaviour")) ); tabs.append( new OptionsTabPresence(this) ); //tabs.append( new OptionsTabBase(this, "presence", "", "status/online", tr("Presence"), tr("Presence configuration")) ); tabs.append( new OptionsTabLookFeel(this) ); tabs.append( new OptionsTabIconset(this) ); //tabs.append( new OptionsTabBase(this, "lookfeel", "", "psi/smile", tr("Look and Feel"), tr("Change the Psi's Look and Feel")) ); tabs.append( new OptionsTabSound(this) ); //tabs.append( new OptionsTabBase(this, "sound", "", "psi/playSounds", tr("Sound"), tr("Configure how Psi sounds")) ); */ OptionsTabApplication* applicationTab = new OptionsTabApplication(this); applicationTab->setHaveAutoUpdater(psi->haveAutoUpdater()); tabs.append( new OptionsTabApplication(this) ); tabs.append( new OptionsTabChat(this) ); tabs.append( new OptionsTabEvents(this) ); tabs.append( new OptionsTabStatus(this) ); tabs.append( new OptionsTabAppearance(this) ); //tabs.append( new OptionsTabIconsetSystem(this) ); //tabs.append( new OptionsTabIconsetRoster(this) ); //tabs.append( new OptionsTabIconsetEmoticons(this) ); tabs.append( new OptionsTabGroupchat(this) ); tabs.append( new OptionsTabSound(this) ); if(AvCallManager::isSupported()) tabs.append( new OptionsTabAvCall(this) ); tabs.append( new OptionsTabToolbars(this) ); #ifdef PSI_PLUGINS tabs.append( new OptionsTabPlugins(this) ); #endif tabs.append( new OptionsTabShortcuts(this) ); tabs.append( new OptionsTabAdvanced(this) ); tabs.append( new OptionsTabTree(this) ); // tabs - general /*tabs.append( new OptionsTabGeneralRoster(this) ); tabs.append( new OptionsTabGeneralDocking(this) ); tabs.append( new OptionsTabGeneralNotifications(this) ); tabs.append( new OptionsTabGeneralGroupchat(this) ); tabs.append( new OptionsTabGeneralMisc(this) );*/ // tabs - events /*tabs.append( new OptionsTabEventsReceive(this) ); tabs.append( new OptionsTabEventsMisc(this) );*/ // tabs - presence /*tabs.append( new OptionsTabPresenceAuto(this) ); tabs.append( new OptionsTabPresencePresets(this) ); tabs.append( new OptionsTabPresenceMisc(this) );*/ // tabs - look and feel /*tabs.append( new OptionsTabLookFeelColors(this) ); tabs.append( new OptionsTabLookFeelFonts(this) ); tabs.append( new OptionsTabIconsetSystem(this) ); tabs.append( new OptionsTabIconsetEmoticons(this) ); tabs.append( new OptionsTabIconsetRoster(this) ); tabs.append( new OptionsTabLookFeelToolbars(this) ); tabs.append( new OptionsTabLookFeelMisc(this) );*/ // tabs - sound /*tabs.append( new OptionsTabSoundPrefs(this) ); tabs.append( new OptionsTabSoundEvents(this) );*/ } void OptionsDlg::Private::createChangedMap() { // NOTE about commented out signals: // Do NOT call addWidgetChangedSignal() for them. // Instead, connect the widget's signal to your tab own dataChaged() signal changedMap.insert("QButton", SIGNAL(stateChanged(int))); changedMap.insert("QCheckBox", SIGNAL(stateChanged(int))); //qt4 port: there are no stateChangedSignals anymore //changedMap.insert("QPushButton", SIGNAL(stateChanged(int))); //changedMap.insert("QRadioButton", SIGNAL(stateChanged(int))); changedMap.insert("QRadioButton",SIGNAL(toggled (bool))); changedMap.insert("QComboBox", SIGNAL(activated (int))); //changedMap.insert("QComboBox", SIGNAL(textChanged(const QString &))); changedMap.insert("QDateEdit", SIGNAL(valueChanged(const QDate &))); changedMap.insert("QDateTimeEdit", SIGNAL(valueChanged(const QDateTime &))); changedMap.insert("QDial", SIGNAL(valueChanged (int))); changedMap.insert("QLineEdit", SIGNAL(textChanged(const QString &))); changedMap.insert("QSlider", SIGNAL(valueChanged(int))); changedMap.insert("QSpinBox", SIGNAL(valueChanged(int))); changedMap.insert("QTimeEdit", SIGNAL(valueChanged(const QTime &))); changedMap.insert("QTextEdit", SIGNAL(textChanged())); changedMap.insert("QTextBrowser", SIGNAL(sourceChanged(const QString &))); changedMap.insert("QMultiLineEdit", SIGNAL(textChanged())); //changedMap.insert("QListBox", SIGNAL(selectionChanged())); //changedMap.insert("QTabWidget", SIGNAL(currentChanged(QWidget *))); } //void OptionsDlg::Private::addWidgetChangedSignal(QString widgetName, QCString signal) //{ // changedMap.insert(widgetName, signal); //} void OptionsDlg::Private::openTab(QString id) { if ( id.isEmpty() ) return; QWidget *tab = id2widget[id]; if ( !tab ) { bool found = false; foreach(OptionsTab* opttab, tabs) { if ( opttab->id() == id ) { tab = opttab->widget(); // create the widget if ( !tab ) continue; // TODO: how about QScrollView for large tabs? // idea: maybe do it only for those, whose sizeHint is bigger than ws_tabs' QWidget *w = new QWidget(dlg->ws_tabs); w->setObjectName("QWidgetStack/tab"); QVBoxLayout *vbox = new QVBoxLayout(w); vbox->setSpacing(0); vbox->setMargin(0); tab->setParent(w); vbox->addWidget(tab); if ( !opttab->stretchable() ) vbox->addStretch(); dlg->ws_tabs->addWidget(w); id2widget[id] = w; connectDataChanged( tab ); // no need to connect to dataChanged() slot by hands anymore bool d = dirty; opttab->restoreOptions(); // initialize widgets' values dirty = d; dlg->pb_apply->setEnabled( dirty ); tab = w; found = true; break; } } if ( !found ) { qWarning("OptionsDlg::Private::itemSelected(): could not create widget for id '%s'", qPrintable(id)); return; } } foreach(OptionsTab* opttab, tabs) { if ( opttab->id() == id ) { dlg->lb_pageTitle->setText( opttab->name() ); dlg->lb_pageTitle->setHelp( opttab->desc() ); dlg->lb_pageTitle->setPsiIcon( opttab->psiIcon() ); break; } } dlg->ws_tabs->setCurrentWidget( tab ); for (int i = 0; i < dlg->lv_tabs->count(); ++i) { QListWidgetItem* item = dlg->lv_tabs->item(i); if (item->data(Qt::UserRole).toString() == id) { dlg->lv_tabs->setCurrentItem(item); break; } } } void OptionsDlg::Private::connectDataChanged(QWidget *widget) { foreach(QWidget* w, widget->findChildren()) { QVariant isOption = w->property("isOption"); if (isOption.isValid() && !isOption.toBool()) { continue; } QMap::Iterator it2 = changedMap.find( w->metaObject()->className() ); if ( it2 != changedMap.end() ) { disconnect(w, changedMap[w->metaObject()->className()], this, SLOT(dataChanged())); connect(w, changedMap[w->metaObject()->className()], SLOT(dataChanged())); } } } void OptionsDlg::Private::currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous) { Q_UNUSED(previous); if (!current) return; openTab(current->data(Qt::UserRole).toString()); } void OptionsDlg::Private::dataChanged() { if ( dirty ) return; if ( !noDirty ) { dirty = true; dlg->pb_apply->setEnabled(true); } } void OptionsDlg::Private::noDirtySlot(bool d) { noDirty = d; } void OptionsDlg::Private::doApply() { if ( !dirty ) return; foreach(OptionsTab* opttab, tabs) { opttab->applyOptions(); } emit dlg->applyOptions(); dirty = false; dlg->pb_apply->setEnabled(false); } //---------------------------------------------------------------------------- // OptionsDlg //---------------------------------------------------------------------------- OptionsDlg::OptionsDlg(PsiCon *psi, QWidget *parent) : QDialog(parent) { setupUi(this); pb_apply = buttonBox->button(QDialogButtonBox::Apply); setAttribute(Qt::WA_DeleteOnClose); d = new Private(this, psi); setModal(false); d->psi->dialogRegister(this); setWindowTitle(CAP(windowTitle())); resize(640, 480); connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(doOk())); connect(pb_apply,SIGNAL(clicked()),SLOT(doApply())); connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), SLOT(reject())); } OptionsDlg::~OptionsDlg() { d->psi->dialogUnregister(this); delete d; } void OptionsDlg::openTab(const QString& id) { d->openTab(id); } void OptionsDlg::doOk() { doApply(); accept(); } void OptionsDlg::doApply() { d->doApply(); } #include "optionsdlg.moc" psi-0.14/src/options/opt_chat.h0000644000175000017500000000054411305557613014600 0ustar janjan#ifndef OPT_CHAT_H #define OPT_CHAT_H #include "optionstab.h" class QWidget; class QButtonGroup; class OptionsTabChat : public OptionsTab { Q_OBJECT public: OptionsTabChat(QObject *parent); ~OptionsTabChat(); QWidget *widget(); void applyOptions(); void restoreOptions(); private: QWidget *w; QButtonGroup *bg_defAct, *bg_delChats; }; #endif psi-0.14/src/jinglevoicecaller.cpp0000644000175000017500000002655511305557613015332 0ustar janjan/* * jinglevoicecaller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "talk/xmpp/constants.h" #include "talk/base/sigslot.h" #include "talk/xmpp/jid.h" #include "talk/xmllite/xmlelement.h" #include "talk/xmllite/xmlprinter.h" #include "talk/base/network.h" #include "talk/p2p/base/session.h" #include "talk/p2p/base/sessionmanager.h" #include "talk/p2p/base/helpers.h" #include "talk/p2p/client/basicportallocator.h" #include "talk/p2p/client/sessionclient.h" #include "talk/base/physicalsocketserver.h" #include "talk/base/thread.h" #include "talk/base/socketaddress.h" #include "talk/session/phone/call.h" #include "talk/session/phone/phonesessionclient.h" #include "talk/session/sessionsendtask.h" #include "im.h" #include "xmpp.h" #include "xmpp_xmlcommon.h" #include "jinglevoicecaller.h" #include "psiaccount.h" // Should change in the future #define JINGLE_NS "http://www.google.com/session" // ---------------------------------------------------------------------------- class JingleIQResponder : public XMPP::Task { public: JingleIQResponder(XMPP::Task *); ~JingleIQResponder(); bool take(const QDomElement &); }; /** * \class JingleIQResponder * \brief A task that responds to jingle candidate queries with an empty reply. */ JingleIQResponder::JingleIQResponder(Task *parent) :Task(parent) { } JingleIQResponder::~JingleIQResponder() { } bool JingleIQResponder::take(const QDomElement &e) { if(e.tagName() != "iq") return false; QDomElement first = e.firstChild().toElement(); if (!first.isNull() && first.attribute("xmlns") == JINGLE_NS) { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); send(iq); return true; } return false; } // ---------------------------------------------------------------------------- /** * \brief A class for handling signals from libjingle. */ class JingleClientSlots : public sigslot::has_slots<> { public: JingleClientSlots(JingleVoiceCaller *voiceCaller); void callCreated(cricket::Call *call); void callDestroyed(cricket::Call *call); void sendStanza(cricket::SessionClient*, const buzz::XmlElement *stanza, bool); void requestSignaling(); void stateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state); private: JingleVoiceCaller* voiceCaller_; }; JingleClientSlots::JingleClientSlots(JingleVoiceCaller *voiceCaller) : voiceCaller_(voiceCaller) { } void JingleClientSlots::callCreated(cricket::Call *call) { call->SignalSessionState.connect(this, &JingleClientSlots::stateChanged); } void JingleClientSlots::callDestroyed(cricket::Call *call) { qDebug() << "JingleClientSlots: Call destroyed"; Jid jid(call->sessions()[0]->remote_address().c_str()); if (voiceCaller_->calling(jid)) { qDebug() << "Removing unterminated call to " << jid.full(); voiceCaller_->removeCall(jid); emit voiceCaller_->terminated(jid); } } // The bool is true if this is // a response and false if it is an outgoing iq. void JingleClientSlots::sendStanza(cricket::SessionClient*, const buzz::XmlElement *stanza, bool response) { QString st(stanza->Str().c_str()); st.replace("cli:iq","iq"); st.replace(":cli=","="); //fprintf(stderr,"bling\n"); voiceCaller_->sendStanza(st); //fprintf(stderr,"blong\n"); //fprintf(stderr,"Sending stanza \n%s\n\n",st.latin1()); } void JingleClientSlots::requestSignaling() { voiceCaller_->session_manager_->OnSignalingReady(); } void JingleClientSlots::stateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state) { qDebug() << QString("jinglevoicecaller.cpp: State changed (%1)").arg(state); // Why is c_str() stuff needed to make it compile on OS X ? Jid jid(session->remote_address().c_str()); if (state == cricket::Session::STATE_INIT) { } else if (state == cricket::Session::STATE_SENTINITIATE) { voiceCaller_->registerCall(jid,call); } else if (state == cricket::Session::STATE_RECEIVEDINITIATE) { voiceCaller_->registerCall(jid,call); emit voiceCaller_->incoming(jid); } else if (state == cricket::Session::STATE_SENTACCEPT) { } else if (state == cricket::Session::STATE_RECEIVEDACCEPT) { emit voiceCaller_->accepted(jid); } else if (state == cricket::Session::STATE_SENTMODIFY) { } else if (state == cricket::Session::STATE_RECEIVEDMODIFY) { qWarning(QString("jinglevoicecaller.cpp: RECEIVEDMODIFY not implemented yet (was from %1)").arg(jid.full())); } else if (state == cricket::Session::STATE_SENTREJECT) { } else if (state == cricket::Session::STATE_RECEIVEDREJECT) { voiceCaller_->removeCall(jid); emit voiceCaller_->rejected(jid); } else if (state == cricket::Session::STATE_SENTREDIRECT) { } else if (state == cricket::Session::STATE_SENTTERMINATE) { voiceCaller_->removeCall(jid); emit voiceCaller_->terminated(jid); } else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) { voiceCaller_->removeCall(jid); emit voiceCaller_->terminated(jid); } else if (state == cricket::Session::STATE_INPROGRESS) { emit voiceCaller_->in_progress(jid); } } // ---------------------------------------------------------------------------- /** * \class JingleVoiceCaller * \brief A Voice Calling implementation using libjingle. */ JingleVoiceCaller::JingleVoiceCaller(PsiAccount* acc) : VoiceCaller(acc) { initialized_ = false; } void JingleVoiceCaller::initialize() { if (initialized_) return; QString jid = ((ClientStream&) account()->client()->stream()).jid().full(); qDebug() << QString("jinglevoicecaller.cpp: Creating new caller for %1").arg(jid); if (jid.isEmpty()) { qWarning("jinglevoicecaller.cpp: Empty JID"); return; } buzz::Jid j(jid.ascii()); cricket::InitRandom(j.Str().c_str(),j.Str().size()); // Global variables if (!socket_server_) { socket_server_ = new cricket::PhysicalSocketServer(); cricket::Thread *t = new cricket::Thread((cricket::PhysicalSocketServer*)(socket_server_)); cricket::ThreadManager::SetCurrent(t); t->Start(); thread_ = t; stun_addr_ = new cricket::SocketAddress("64.233.167.126",19302); network_manager_ = new cricket::NetworkManager(); port_allocator_ = new cricket::BasicPortAllocator((cricket::NetworkManager*)(network_manager_), (cricket::SocketAddress*)(stun_addr_), /* relay server */ NULL); } // Session manager session_manager_ = new cricket::SessionManager((cricket::PortAllocator*)(port_allocator_), thread_); slots_ = new JingleClientSlots(this); session_manager_->SignalRequestSignaling.connect(slots_, &JingleClientSlots::requestSignaling); session_manager_->OnSignalingReady(); // Phone Client phone_client_ = new cricket::PhoneSessionClient(j, (cricket::SessionManager*)(session_manager_)); phone_client_->SignalCallCreate.connect(slots_, &JingleClientSlots::callCreated); phone_client_->SignalCallDestroy.connect(slots_, &JingleClientSlots::callDestroyed); phone_client_->SignalSendStanza.connect(slots_, &JingleClientSlots::sendStanza); // IQ Responder new JingleIQResponder(account()->client()->rootTask()); // Listen to incoming packets connect(account()->client(),SIGNAL(xmlIncoming(const QString&)),SLOT(receiveStanza(const QString&))); initialized_ = true; } void JingleVoiceCaller::deinitialize() { if (!initialized_) return; // Stop listening to incoming packets disconnect(account()->client(),SIGNAL(xmlIncoming(const QString&)),this,SLOT(receiveStanza(const QString&))); // Disconnect signals (is this needed) //phone_client_->SignalCallCreate.disconnect(slots_); //phone_client_->SignalSendStanza.disconnect(slots_); // Delete objects delete phone_client_; delete session_manager_; delete slots_; initialized_ = false; } JingleVoiceCaller::~JingleVoiceCaller() { } bool JingleVoiceCaller::calling(const Jid& jid) { return calls_.contains(jid.full()); } void JingleVoiceCaller::call(const Jid& jid) { qDebug() << "jinglevoicecaller.cpp: Calling " << jid.full(); cricket::Call *c = ((cricket::PhoneSessionClient*)(phone_client_))->CreateCall(); c->InitiateSession(buzz::Jid(jid.full().ascii())); phone_client_->SetFocus(c); } void JingleVoiceCaller::accept(const Jid& j) { qDebug("jinglevoicecaller.cpp: Accepting call"); cricket::Call* call = calls_[j.full()]; if (call != NULL) { call->AcceptSession(call->sessions()[0]); phone_client_->SetFocus(call); } } void JingleVoiceCaller::reject(const Jid& j) { qDebug("jinglevoicecaller.cpp: Rejecting call"); cricket::Call* call = calls_[j.full()]; if (call != NULL) { call->RejectSession(call->sessions()[0]); calls_.remove(j.full()); } } void JingleVoiceCaller::terminate(const Jid& j) { qDebug() << "jinglevoicecaller.cpp: Terminating call to " << j.full(); cricket::Call* call = calls_[j.full()]; if (call != NULL) { call->Terminate(); calls_.remove(j.full()); } } void JingleVoiceCaller::sendStanza(const char* stanza) { account()->client()->send(QString(stanza)); } void JingleVoiceCaller::registerCall(const Jid& jid, cricket::Call* call) { qDebug("jinglevoicecaller.cpp: Registering call\n"); if (!calls_.contains(jid.full())) { calls_[jid.full()] = call; } else { qWarning("jinglevoicecaller.cpp: Auto-rejecting call because another call is currently open"); call->RejectSession(call->sessions()[0]); } } void JingleVoiceCaller::removeCall(const Jid& j) { qDebug() << "JingleVoiceCaller: Removing call to " << j.full(); calls_.remove(j.full()); } void JingleVoiceCaller::receiveStanza(const QString& stanza) { QDomDocument doc; doc.setContent(stanza); // Check if it is offline presence from an open chat if (doc.documentElement().tagName() == "presence") { Jid from = Jid(doc.documentElement().attribute("from")); QString type = doc.documentElement().attribute("type"); if (type == "unavailable" && calls_.contains(from.full())) { qDebug("JingleVoiceCaller: User went offline without closing a call."); removeCall(from); emit terminated(from); } return; } // Check if the packet is destined for libjingle. // We could use Session::IsClientStanza to check this, but this one crashes // for some reason. QDomNode n = doc.documentElement().firstChild(); bool ok = false; while (!n.isNull() && !ok) { QDomElement e = n.toElement(); if (!e.isNull() && e.attribute("xmlns") == JINGLE_NS) { ok = true; } n = n.nextSibling(); } // Spread the word if (ok) { //qDebug() << "jinglevoicecaller.cpp: Handing down " << stanza; buzz::XmlElement *e = buzz::XmlElement::ForStr(stanza.ascii()); phone_client_->OnIncomingStanza(e); } } cricket::SocketServer* JingleVoiceCaller::socket_server_ = NULL; cricket::Thread* JingleVoiceCaller::thread_ = NULL; cricket::NetworkManager* JingleVoiceCaller::network_manager_ = NULL; cricket::BasicPortAllocator* JingleVoiceCaller::port_allocator_ = NULL; cricket::SocketAddress* JingleVoiceCaller::stun_addr_ = NULL; psi-0.14/src/profiledlg.h0000644000175000017500000000351011305557613013427 0ustar janjan/* * profiledlg.h - dialogs for manipulating profiles * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PROFILEDLG_H #define PROFILEDLG_H #include #include "ui_profileopen.h" #include "ui_profilemanage.h" #include "ui_profilenew.h" #include "varlist.h" class QButtonGroup; class ProfileOpenDlg : public QDialog, public Ui::ProfileOpen { Q_OBJECT public: ProfileOpenDlg(const QString &, const VarList &, const QString &, QWidget *parent=0); ~ProfileOpenDlg(); QString newLang; private slots: void manageProfiles(); void langChange(int); private: void reload(const QString &); VarList langs; int langSel; }; class ProfileManageDlg : public QDialog, public Ui::ProfileManage { Q_OBJECT public: ProfileManageDlg(const QString &, QWidget *parent=0); private slots: void slotProfileNew(); void slotProfileRename(); void slotProfileDelete(); void updateSelection(); }; class ProfileNewDlg : public QDialog, public Ui::ProfileNew { Q_OBJECT public: ProfileNewDlg(QWidget *parent=0); QString name; private slots: void slotCreate(); void nameModified(); private: QButtonGroup* buttonGroup_; }; #endif psi-0.14/src/accountadd.ui0000644000175000017500000001253411305557613013601 0ustar janjan AccountAdd 0 0 465 252 Add Account 11 6 0 7 0 0 200 0 200 32767 <qt>Please choose a friendly <b>Name</b> that Psi can use to refer to this account.<br> <br> Click the <b>Register New Account</b> checkbox if you want Psi to try and create an account for you on a remote server. If you are adding an existing Jabber account then leave this box unchecked. true 0 0 6 Name: Register new account 20 130 Expanding Vertical QFrame::HLine QFrame::Sunken 0 118 20 Expanding Horizontal &Close &Add Alt+A true psi/addContact qPixmapFromMimeSource psi-0.14/src/accountmodifydlg.cpp0000644000175000017500000005002511305557613015171 0ustar janjan/* * accountmodifydlg.cpp * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "accountmodifydlg.h" #include "pgputil.h" #include "psiaccount.h" #include "iconset.h" #include "psioptions.h" #include "jidutil.h" #include "psicon.h" #include "proxy.h" #include "privacymanager.h" #include "privacydlg.h" #include "pgpkeydlg.h" #include "psicontactlist.h" AccountModifyDlg::AccountModifyDlg(PsiCon *_psi, QWidget *parent) :QDialog(parent) { acc.name = ""; setupUi(this); setModal(true); pa = NULL; psi = _psi; init(); } AccountModifyDlg::AccountModifyDlg(PsiAccount *_pa, QWidget *parent) :QDialog(parent) { setupUi(this); setModal(false); setAttribute(Qt::WA_DeleteOnClose); pa = _pa; psi = pa->psi(); acc = pa->userAccount(); init(); } void AccountModifyDlg::init() { //connect(pa->psi(), SIGNAL(pgpToggled(bool)), SLOT(pgpToggled(bool))); if (pa) pa->dialogRegister(this); setWindowTitle(CAP(windowTitle())); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/account").icon()); #endif le_pass->setEnabled(true); le_host->setEnabled(false); lb_host->setEnabled(false); le_port->setEnabled(false); lb_port->setEnabled(false); // FIXME: Temporarily removing security level settings ck_req_mutual->hide(); cb_security_level->hide(); lb_security_level->hide(); connect(ck_host, SIGNAL(toggled(bool)), SLOT(hostToggled(bool))); connect(pb_key, SIGNAL(clicked()), SLOT(chooseKey())); connect(pb_keyclear, SIGNAL(clicked()), SLOT(clearKey())); connect(buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), SLOT(save())); connect(ck_automatic_resource, SIGNAL(toggled(bool)), le_resource, SLOT(setDisabled(bool))); connect(ck_automatic_resource, SIGNAL(toggled(bool)), lb_resource, SLOT(setDisabled(bool))); gb_pgp->setEnabled(false); if (pa) { connect(pb_vcard, SIGNAL(clicked()), SLOT(detailsVCard())); connect(pb_changepw, SIGNAL(clicked()), SLOT(detailsChangePW())); } else { pb_vcard->setEnabled(false); pb_changepw->setEnabled(false); } // Hide the name if necessary le_name->setText(acc.name); le_jid->setText(JIDUtil::accountToString(acc.jid,false)); cb_ssl->addItem(tr("Always"),UserAccount::SSL_Yes); cb_ssl->addItem(tr("When available"),UserAccount::SSL_Auto); cb_ssl->addItem(tr("Never"), UserAccount::SSL_No); cb_ssl->addItem(tr("Legacy SSL"), UserAccount::SSL_Legacy); cb_ssl->setCurrentIndex(cb_ssl->findData(acc.ssl)); connect(cb_ssl, SIGNAL(activated(int)), SLOT(sslActivated(int))); cb_plain->addItem(tr("Always"),ClientStream::AllowPlain); cb_plain->addItem(tr("Over encrypted connection"), ClientStream::AllowPlainOverTLS); cb_plain->addItem(tr("Never"), ClientStream::NoAllowPlain); cb_plain->setCurrentIndex(cb_plain->findData(acc.allow_plain)); if (acc.opt_pass) le_pass->setText(acc.pass); ck_host->setChecked(acc.opt_host); le_host->setText(acc.host); le_port->setText(QString::number(acc.port)); ck_req_mutual->setChecked(acc.req_mutual_auth); ck_legacy_ssl_probe->setChecked(acc.legacy_ssl_probe); ck_automatic_resource->setChecked(acc.opt_automatic_resource); le_resource->setText(acc.resource); le_priority->setText(QString::number(acc.priority)); connect(ck_custom_auth,SIGNAL(toggled(bool)), lb_authid, SLOT(setEnabled(bool))); connect(ck_custom_auth,SIGNAL(toggled(bool)), le_authid, SLOT(setEnabled(bool))); connect(ck_custom_auth,SIGNAL(toggled(bool)), lb_realm, SLOT(setEnabled(bool))); connect(ck_custom_auth,SIGNAL(toggled(bool)), le_realm, SLOT(setEnabled(bool))); ck_custom_auth->setChecked(acc.customAuth); le_authid->setText(acc.authid); le_realm->setText(acc.realm); ck_compress->setChecked(acc.opt_compress); ck_auto->setChecked(acc.opt_auto); ck_reconn->setChecked(acc.opt_reconn); ck_connectAfterSleep->setChecked(acc.opt_connectAfterSleep); ck_log->setChecked(acc.opt_log); ck_keepAlive->setChecked(acc.opt_keepAlive); le_dtProxy->setText(acc.dtProxy.full()); le_stunHost->setText(acc.stunHost); le_stunPort->setText(QString::number(acc.stunPort)); key = acc.pgpSecretKey; updateUserID(); PGPUtil::instance().clearPGPAvailableCache(); if(PGPUtil::instance().pgpAvailable()) { gb_pgp->setEnabled(true); } pc = psi->proxy()->createProxyChooser(tab_connection); replaceWidget(lb_proxychooser, pc); pc->setCurrentItem(acc.proxyID); // Security level cb_security_level->addItem(tr("None"),QCA::SL_None); cb_security_level->addItem(tr("Integrity"),QCA::SL_Integrity); cb_security_level->addItem(tr("Baseline"),QCA::SL_Baseline); cb_security_level->addItem(tr("High"),QCA::SL_High); cb_security_level->addItem(tr("Highest"),QCA::SL_Highest); cb_security_level->setCurrentIndex(cb_security_level->findData(acc.security_level)); // Name if(le_name->text().isEmpty()) le_name->setFocus(); else if(le_jid->text().isEmpty()) le_jid->setFocus(); else buttonBox->button(QDialogButtonBox::Save)->setFocus(); // Privacy privacyInitialized = false; lb_customPrivacy->hide(); privacyBlockedModel.setSourceModel(&privacyModel); lv_blocked->setModel(&privacyBlockedModel); if (pa) { connect(pa->privacyManager(),SIGNAL(defaultListAvailable(const PrivacyList&)),SLOT(updateBlockedContacts(const PrivacyList&))); connect(pa->privacyManager(),SIGNAL(defaultListError()),SLOT(getDefaultList_error())); connect(pa->privacyManager(),SIGNAL(changeList_error()),SLOT(changeList_error())); connect(pa,SIGNAL(updatedActivity()),SLOT(updatePrivacyTab())); } connect(tab_main,SIGNAL(currentChanged(int)),SLOT(tabChanged(int))); connect(pb_privacy, SIGNAL(clicked()), SLOT(privacyClicked())); connect(pb_removeBlock, SIGNAL(clicked()), SLOT(removeBlockClicked())); connect(pb_addBlock, SIGNAL(clicked()), SLOT(addBlockClicked())); // FIXME: Temporarily disabling blocking pb_removeBlock->hide(); pb_addBlock->hide(); // QWhatsThis helpers cb_plain->setWhatsThis( tr("Normally, Psi logs in using the digest authentication " "method. Check this box to force a plain text login " "to the Jabber server. Use this option only if you have " "problems connecting with the normal login procedure, as it " "makes your connection potentially vulnerable to " "attacks.")); ck_auto->setWhatsThis( tr("Automatically login to this account on Psi startup. Useful if " "you have Psi automatically launched when an Internet " "connection is detected.")); ck_connectAfterSleep->setWhatsThis( tr("Makes Psi try to connect when the computer resumes " "after a sleep.")); ck_reconn->setWhatsThis( tr("Makes Psi try to reconnect if the connection was broken. " "Useful, if you have an unstable connection and have to " "reconnect often.")); ck_log->setWhatsThis( tr("Keep a log of message history. Disable this " "option if you want to conserve disk space or if you need " "maximum security.")); ck_keepAlive->setWhatsThis( tr("Sends so called \"Keep-alive\" packets periodically. " "It is useful if your connection is set to be " "automatically disconnected after a certain period of " "inactivity (for example, by your ISP) and you want to keep it " "up all the time.")); cb_ssl->setWhatsThis( tr("Check this option to use an encrypted SSL connection to " "the Jabber server. You may use this option if your " "server supports it and if you have the necessary QCA-OpenSSL " "plugin installed. For more information, check the " "Psi homepage.")); ck_compress->setWhatsThis( tr("Check this option to use a compressed connection to " "the Jabber server, if the server supports it.")); ck_host->setWhatsThis( tr("Use this option for manual configuration of your Jabber host " "if it is not the same as the host you are connecting to. This option is mostly useful " "if you have some sort of proxy route on your " "local machine (i.e. you connect to localhost), but your " "account is registered on an external server.")); le_resource->setWhatsThis( tr("You can have multiple clients connected to the Jabber server " "with your single account. Each login is distinguished by a \"resource\" " "name, which you can specify in this field.")); ck_custom_auth->setWhatsThis( tr("This option sets the user (and realm) you want to " "authenticate as. This overrides the Jabber ID you are logging in " "as.")); le_priority->setWhatsThis( tr("

You can have multiple clients connected to the Jabber " "server with your single account. In such a situation, " "the client with the highest priority (that is specified in " "this field) will be the one that will receive " "all incoming events.

" "

For example, if you have a permanent connection " "to the Internet at your work location, and have a dial-up at home, " "you can have your Jabber client permanently running at work " "with a low priority, and you can still use the same account " "from home, using a client with higher priority to " "temporary \"disable\" the lower priority client at work.

")); // Hiding of UI components if ((!pa && acc.name.isEmpty()) || PsiOptions::instance()->getOption("options.ui.account.single").toBool()) { le_name->hide(); lb_name->hide(); } if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) { lb_example->hide(); lb_jid->setText(tr("Username:")); } if (!PsiOptions::instance()->getOption("options.pgp.enable").toBool()) { gb_pgp->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.privacy.show").toBool()) tab_main->removeTab(tab_main->indexOf(tab_privacy)); if (!PsiOptions::instance()->getOption("options.ui.account.proxy.show").toBool()) { lb_proxy->hide(); pc->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.manual-host").toBool()) { ck_host->hide(); lb_host->hide(); le_host->hide(); lb_port->hide(); le_port->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.keepalive").toBool()) ck_keepAlive->hide(); if (!PsiOptions::instance()->getOption("options.ui.account.legacy-ssl-probe").toBool()) ck_legacy_ssl_probe->hide(); if (!PsiOptions::instance()->getOption("options.ui.account.security.show").toBool()) { lb_plain->hide(); cb_plain->hide(); ck_req_mutual->hide(); lb_security_level->hide(); cb_security_level->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.security.show").toBool() && !PsiOptions::instance()->getOption("options.ui.account.legacy-ssl-probe").toBool() && !PsiOptions::instance()->getOption("options.ui.account.keepalive").toBool() && !PsiOptions::instance()->getOption("options.ui.account.manual-host").toBool() && !PsiOptions::instance()->getOption("options.ui.account.proxy.show").toBool()) { tab_main->removeTab(tab_main->indexOf(tab_connection)); } if (!PsiOptions::instance()->getOption("options.ui.account.resource").toBool()) { ck_automatic_resource->hide(); lb_resource->hide(); le_resource->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.custom-authid").toBool()) { ck_custom_auth->hide(); lb_authid->hide(); le_authid->hide(); lb_realm->hide(); le_realm->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.priority").toBool()) { lb_priority->hide(); le_priority->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.data-proxy").toBool()) { lb_dtProxy->hide(); le_dtProxy->hide(); } if (!PsiOptions::instance()->getOption("options.ui.account.resource").toBool() && !PsiOptions::instance()->getOption("options.ui.account.priority").toBool() && !PsiOptions::instance()->getOption("options.ui.account.data-proxy").toBool()) { tab_main->removeTab(tab_main->indexOf(tab_misc)); } resize(minimumSizeHint()); } AccountModifyDlg::~AccountModifyDlg() { if (pa) pa->dialogUnregister(this); } void AccountModifyDlg::updateUserID() { if(key.isNull()) { setKeyID(false); } else { setKeyID(true, key.primaryUserId()); } } void AccountModifyDlg::setKeyID(bool b, const QString &s) { if(b) { lb_keyname->setText(s); lb_keyname->setMinimumWidth(100); lb_keyicon->setEnabled(true); lb_keyname->setEnabled(true); pb_keyclear->setEnabled(true); } else { lb_keyname->setText(tr("No Key Selected")); lb_keyicon->setEnabled(false); lb_keyname->setEnabled(false); pb_keyclear->setEnabled(false); } } //void AccountModifyDlg::pgpToggled(bool b) //{ // if(b) { // gb_pgp->setEnabled(true); // } // else { // gb_pgp->setEnabled(false); // } // updateUserID(); //} void AccountModifyDlg::setPassword(const QString &pw) { if (!le_pass->text().isEmpty()) le_pass->setText(pw); } void AccountModifyDlg::sslActivated(int i) { if ((cb_ssl->itemData(i) == UserAccount::SSL_Yes || cb_ssl->itemData(i) == UserAccount::SSL_Legacy) && !checkSSL()) { cb_ssl->setCurrentIndex(cb_ssl->findData(UserAccount::SSL_Auto)); } else if (cb_ssl->itemData(i) == UserAccount::SSL_Legacy && !ck_host->isChecked()) { QMessageBox::critical(this, tr("Error"), tr("Legacy SSL is only available in combination with manual host/port.")); cb_ssl->setCurrentIndex(cb_ssl->findData(UserAccount::SSL_Auto)); } } bool AccountModifyDlg::checkSSL() { if(!QCA::isSupported("tls")) { QMessageBox::critical(this, tr("SSL error"), tr("Cannot enable SSL/TLS. Plugin not found.")); return false; } return true; } void AccountModifyDlg::hostToggled(bool on) { le_host->setEnabled(on); lb_host->setEnabled(on); le_port->setEnabled(on); lb_port->setEnabled(on); ck_legacy_ssl_probe->setEnabled(!on); ck_legacy_ssl_probe->setChecked(on ? false : acc.legacy_ssl_probe); if (!on && cb_ssl->currentIndex() == cb_ssl->findData(UserAccount::SSL_Legacy)) { cb_ssl->setCurrentIndex(cb_ssl->findData(UserAccount::SSL_Auto)); } } void AccountModifyDlg::chooseKey() { // Show the key dialog QString id = (key.isNull() ? "" : key.keyId()); PGPKeyDlg *w = new PGPKeyDlg(PGPKeyDlg::Secret, id, this); w->setWindowTitle(tr("Secret Key")); int r = w->exec(); QCA::KeyStoreEntry entry; if(r == QDialog::Accepted) entry = w->keyStoreEntry(); delete w; if(!entry.isNull()) { key = entry.pgpSecretKey(); updateUserID(); } } void AccountModifyDlg::clearKey() { setKeyID(false); key = QCA::PGPKey(); } void AccountModifyDlg::detailsVCard() { if (pa) pa->changeVCard(); } void AccountModifyDlg::detailsChangePW() { if (pa) { pa->changePW(); } } void AccountModifyDlg::save() { /*if(pa && le_name->text().isEmpty()) { QMessageBox::information(this, tr("Error"), tr("You must specify a name for the account before you may save it.")); return; }*/ Jid newJid( JIDUtil::accountFromString(le_jid->text().trimmed()) ); if ( newJid.node().isEmpty() || newJid.domain().isEmpty() ) { if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) { QMessageBox::information(this, tr("Error"), tr("Username is invalid.")); } else { QMessageBox::information(this, tr("Error"), tr("Jabber ID must be specified in the format user@host.")); } return; } // do not allow duplicate account names if (!pa && le_name->text().isEmpty()) le_name->setText(newJid.domain()); QString def = le_name->text(); QString aname = def; int n = 0; { foreach(PsiAccount* pa, psi->contactList()->accounts()) if(aname == pa->name()) n++; } if ( aname == acc.name ) n--; if ( n ) aname = def + '_' + QString::number(++n); le_name->setText( aname ); acc.name = le_name->text(); acc.jid = JIDUtil::accountFromString(le_jid->text().trimmed()).bare(); acc.pass = le_pass->text(); acc.opt_pass = !acc.pass.isEmpty(); acc.opt_host = ck_host->isChecked(); acc.host = le_host->text(); acc.port = le_port->text().toInt(); acc.req_mutual_auth = ck_req_mutual->isChecked(); if (!ck_host->isChecked()) acc.legacy_ssl_probe = ck_legacy_ssl_probe->isChecked(); acc.security_level = cb_security_level->itemData(cb_security_level->currentIndex()).toInt(); acc.opt_automatic_resource = ck_automatic_resource->isChecked(); acc.resource = le_resource->text(); acc.priority = le_priority->text().toInt(); acc.customAuth = ck_custom_auth->isChecked(); acc.authid = le_authid->text(); acc.realm = le_realm->text(); acc.ssl = (UserAccount::SSLFlag) cb_ssl->itemData(cb_ssl->currentIndex()).toInt(); acc.allow_plain = (ClientStream::AllowPlainType) cb_plain->itemData(cb_plain->currentIndex()).toInt(); acc.opt_compress = ck_compress->isChecked(); acc.opt_auto = ck_auto->isChecked(); acc.opt_connectAfterSleep = ck_connectAfterSleep->isChecked(); acc.opt_reconn = ck_reconn->isChecked(); acc.opt_log = ck_log->isChecked(); acc.opt_keepAlive = ck_keepAlive->isChecked(); acc.dtProxy = le_dtProxy->text(); acc.stunHost = le_stunHost->text(); acc.stunPort = le_stunPort->text().toInt(); acc.pgpSecretKey = key; acc.proxyID = pc->currentItem(); if (pa) { pa->setUserAccount(acc); if (pa->isActive()) { QMessageBox messageBox(QMessageBox::Information, tr("Warning"), tr("This account is currently active, so certain changes may not take effect until the next login."), QMessageBox::NoButton, this); QPushButton* cancel = messageBox.addButton(tr("Reconnect &Later"), QMessageBox::RejectRole); QPushButton* reconnect = messageBox.addButton(tr("Reconnect &Now"), QMessageBox::AcceptRole); messageBox.setDefaultButton(reconnect); messageBox.exec(); Q_UNUSED(cancel); if (messageBox.clickedButton() == reconnect) { XMPP::Status status = pa->status(); pa->setStatus(XMPP::Status::Offline); pa->setStatus(status); } } } else { psi->contactList()->createAccount(acc); } accept(); } void AccountModifyDlg::tabChanged(int) { updatePrivacyTab(); } void AccountModifyDlg::addBlockClicked() { if (!pa) return; bool ok; QString input = QInputDialog::getText(NULL, tr("Block contact"), tr("Enter the Jabber ID of the contact to block:"), QLineEdit::Normal, "", &ok); Jid jid(input); if (ok && !jid.isEmpty()) { privacyModel.list().insertItem(0,PrivacyListItem::blockItem(jid.full())); privacyModel.reset(); pa->privacyManager()->changeList(privacyModel.list()); } } void AccountModifyDlg::removeBlockClicked() { if (!pa) return; if (lv_blocked->currentIndex().isValid()) { QModelIndex idx = privacyBlockedModel.mapToSource(lv_blocked->currentIndex()); privacyModel.removeRow(idx.row(),idx.parent()); pa->privacyManager()->changeList(privacyModel.list()); } } void AccountModifyDlg::privacyClicked() { PrivacyDlg *d = new PrivacyDlg(pa->name(), pa->privacyManager(), this); d->show(); } void AccountModifyDlg::updatePrivacyTab() { if (tab_main->currentWidget() == tab_privacy) { if (pa && pa->loggedIn()) { if (!privacyInitialized) { lb_privacyStatus->setText(tr("Retrieving blocked contact list ...")); setPrivacyTabEnabled(false); pa->privacyManager()->getDefaultList(); } //else { // setPrivacyTabEnabled(true); //} } else { lb_privacyStatus->setText(tr("You are not connected.")); privacyInitialized = false; setPrivacyTabEnabled(false); } } } void AccountModifyDlg::setPrivacyTabEnabled(bool b) { ws_privacy->setCurrentWidget(b ? pg_privacy : pg_privacyStatus); } void AccountModifyDlg::updateBlockedContacts(const PrivacyList& l) { privacyInitialized = true; privacyModel.setList(l); lb_customPrivacy->setVisible(!l.onlyBlockItems()); setPrivacyTabEnabled(true); } void AccountModifyDlg::changeList_error() { privacyInitialized = false; updatePrivacyTab(); } void AccountModifyDlg::getDefaultList_error() { privacyInitialized = true; lb_privacyStatus->setText(tr("Your server does not support blocking.")); setPrivacyTabEnabled(false); } psi-0.14/src/profiles.h0000644000175000017500000000552511305557613013133 0ustar janjan/* * profiles.h - deal with profiles * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PROFILES_H #define PROFILES_H #include #include #include #include #include #include "varlist.h" #include "proxy.h" #include "common.h" #include "xmpp_clientstream.h" #include "xmpp_roster.h" #include "xmpp_jid.h" class OptionsTree; class UserAccount { public: UserAccount(); ~UserAccount(); void reset(); void fromXml(const QDomElement &); void fromOptions(OptionsTree *o, QString base); void toOptions(OptionsTree *o, QString base=QString()); QString name; QString jid, pass, host, resource, authid, realm; bool customAuth; int port, priority; bool opt_enabled, opt_pass, opt_host, opt_auto, opt_keepAlive, opt_log, opt_connectAfterSleep, opt_reconn, opt_ignoreSSLWarnings, opt_compress; XMPP::ClientStream::AllowPlainType allow_plain; bool req_mutual_auth; bool legacy_ssl_probe; bool opt_automatic_resource; int security_level; enum SSLFlag { SSL_No = 0, SSL_Yes = 1, SSL_Auto = 2, SSL_Legacy = 3 } ssl; QString proxyID; XMPP::Roster roster; struct GroupData { bool open; int rank; }; QMap groupState; QCA::PGPKey pgpSecretKey; VarList keybind; XMPP::Jid dtProxy; QString optionsBase; QString stunHost; int stunPort; QByteArray tlsOverrideCert; QString tlsOverrideDomain; /* migration only */ int proxy_index; int proxy_type, proxy_port; QString proxy_host, proxy_user, proxy_pass; bool tog_offline, tog_away, tog_agents, tog_hidden, tog_self; }; typedef QList UserAccountList; class OptionsMigration { public: bool fromFile(const QString &); void lateMigration(); //QString progver; UserAccountList accMigration; ProxyItemList proxyMigration; private: lateMigrationOptions lateMigrationData; }; QString pathToProfile(const QString &); QString pathToProfileConfig(const QString &); QStringList getProfilesList(); bool profileExists(const QString &); bool profileNew(const QString &); bool profileRename(const QString &, const QString &); bool profileDelete(const QString &); extern QString activeProfile; #endif psi-0.14/src/voicecalldlg.h0000644000175000017500000000307611305557613013737 0ustar janjan/* * voicecalldlg.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef VOICECALLDLG #define VOICECALLDLG #include #include "ui_voicecall.h" #include "xmpp_jid.h" using namespace XMPP; class VoiceCaller; class VoiceCallDlg : public QDialog { Q_OBJECT public: enum CallStatus { Default, Calling, Accepting, Rejecting, Terminating, Accepted, Rejected, InProgress, Terminated, Incoming }; VoiceCallDlg(const Jid&, VoiceCaller*); public slots: void incoming(); void call(); void terminate_call(); void accept_call(); void reject_call(); void accepted(const Jid&); void rejected(const Jid&); void in_progress(const Jid&); void terminated(const Jid&); protected slots: void reject(); protected: void finalize(); void setStatus(CallStatus); private: Jid jid_; CallStatus status_; VoiceCaller* voiceCaller_; Ui::VoiceCall ui_; }; #endif psi-0.14/src/tip.ui0000644000175000017500000001636411305557613012275 0ustar janjan Tip 0 0 480 400 Useful Tips 11 6 QFrame::StyledPanel QFrame::Sunken 0 0 0 0 10 10 psi/logo_128 5 7 0 0 0 0 0 8 32767 8 QFrame::Sunken 0 0 0 8 32767 8 8 0 8 32767 QFrame::HLine QFrame::Sunken Qt::Horizontal 0 6 Show tips at startup Qt::Horizontal QSizePolicy::Expanding 40 20 &Previous Alt+P psi/arrowLeft &Next Alt+N psi/arrowRight &Close Alt+C true qPixmapFromMimeSource PsiTextView
psitextview.h
0
IconLabel
iconlabel.h
0
IconButton
iconbutton.h
0
psi-0.14/src/geolocation.h0000644000175000017500000000325711305557613013613 0ustar janjan/* * geolocation.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GEOLOCATION_H #define GEOLOCATION_H #include #include "maybe.h" class QDomElement; class QDomDocument; class GeoLocation { public: GeoLocation(); GeoLocation(const QDomElement&); const Maybe& alt() const; const Maybe& bearing() const; const Maybe& error() const; const Maybe& lat() const; const Maybe& lon() const; const QString& datum() const; const QString& description() const; bool isNull() const; void setAlt(float); void setBearing(float); void setError(float); void setLat(float); void setLon(float); void setDatum(const QString&); void setDescription(const QString&); QDomElement toXml(QDomDocument&); bool operator==(const GeoLocation&) const; bool operator!=(const GeoLocation&) const; protected: void fromXml(const QDomElement&); private: Maybe alt_, bearing_, error_, lat_, lon_; QString datum_, description_; }; #endif psi-0.14/src/urlbookmark.h0000644000175000017500000000236211305557613013634 0ustar janjan/* * urlbookmark.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef URLBOOKMARK_H #define URLBOOKMARK_H #include class QDomElement; class QDomDocument; class URLBookmark { public: URLBookmark(const QString& name, const QString& url); URLBookmark(const QDomElement&); const QString& name() const; const QString& url() const; bool isNull() const; void fromXml(const QDomElement&); QDomElement toXml(QDomDocument&) const; bool operator==(const URLBookmark& other) const; private: QString name_; QString url_; }; #endif psi-0.14/src/varlist.cpp0000644000175000017500000000653111305557613013325 0ustar janjan/**************************************************************************** ** varlist.cpp - class for handling a list of string vars ** Copyright (C) 2001, 2002 Justin Karneges ** ** 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 2 ** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA. ** ****************************************************************************/ #include #include #include #include #include "varlist.h" #include "optionstree.h" VarList::VarList() :QList() { } QStringList VarList::varsToStringList() { QStringList list; for(VarList::Iterator it = begin(); it != end(); ++it) list.append((*it).key()); return list; } void VarList::fromOptions(OptionsTree *o, QString base) { QStringList bases = o->getChildOptionNames( base, true, true); foreach(QString ibase, bases) { QString var = o->getOption(ibase + ".key").toString(); QString val = o->getOption(ibase + ".data").toString(); set(var, val); } } void VarList::toOptions(OptionsTree *o, QString base) { o->removeOption(base, true); foreach(VarListItem item, *this) { QString ibase = o->mapPut(base, item.key()); o->setOption(ibase + ".data", item.data()); } } QDomElement VarList::toXml(QDomDocument &doc, const QString &tagName) { QDomElement base = doc.createElement(tagName); for(VarList::Iterator it = begin(); it != end(); ++it) { QDomElement tag = doc.createElement("item"); tag.setAttribute("name", (*it).key()); QDomText text = doc.createTextNode((*it).data()); tag.appendChild(text); base.appendChild(tag); } return base; } void VarList::fromXml(const QDomElement &e) { clear(); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { QString var, val; var = i.attribute("name"); QDomText t = i.firstChild().toText(); if(!t.isNull()) val = t.data(); set(var, val); } } } void VarList::set(const QString &key, const QString &data) { VarList::Iterator it = findByKey(key); if(it == end()) { VarListItem v; v.setKey(key); v.setData(data); append(v); } else { (*it).setData(data); } } void VarList::unset(const QString &key) { VarList::Iterator it = findByKey(key); if(it == end()) return; erase(it); } const QString & VarList::get(const QString &key) { VarList::Iterator it = findByKey(key); return (*it).data(); } VarList::Iterator VarList::findByKey(const QString &key) { VarList::Iterator it; for(it = begin(); it != end(); ++it) { if((*it).key() == key) break; } return it; } VarList::Iterator VarList::findByNum(int x) { int n = 0; VarList::Iterator it; for(it = begin(); it != end(); ++it) { if(n >= x) break; ++n; } return it; } psi-0.14/src/whiteboarding/0000755000175000017500000000000011305557613013756 5ustar janjanpsi-0.14/src/whiteboarding/wbdlg.h0000644000175000017500000001260411305557613015231 0ustar janjan/* * wbdlg.h - dialog for whiteboarding * Copyright (C) 2006 Joonas Govenius * * Originally developed from: * wbdlg.h - dialog for handling chats * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBDLG_H #define WBDLG_H #include #include #include #include #include #include #include #include #include // #include #include "advwidget.h" #include "im.h" #include "common.h" #include "wbwidget.h" #include "iconlabel.h" #include "psiaccount.h" #include "psioptions.h" class AccountLabel; using namespace XMPP; /*! \brief The dialog for a whiteboard session. * * Contains the WbWidget and provides controls for setting the mode, stroke * width and color of new items. * * Also provides controls for setting general properties of the session and * a control for ending and saving the session. * * \sa WbManager * \sa WbWidget */ class WbDlg : public AdvancedWidget { Q_OBJECT public: /*! \brief Constructor. * Creates a new dialog for the specified jid and session. */ WbDlg(SxeSession* session, PsiAccount* pa); /*! \brief Destructor. * Emits sessionEnded() */ ~WbDlg(); /*! \brief Returns the session identifier.*/ SxeSession* session() const; /*! \brief Returns whether further edits to the session are allowed.*/ bool allowEdits() const; /*! \brief Sets whether further edits to the session are allowed.*/ void setAllowEdits(bool); public slots: /*! \brief Ends the session. * Asks for confirmation if invoked by user's action. */ void endSession(); /*! \brief Removes indicators of new edits.*/ void activated(); /*! \brief Notifies the user that \a peer left the session.*/ void peerLeftSession(const Jid &peer); signals: /*! \brief Signals that the session ended and the dialog is to be deleted.*/ void sessionEnded(WbDlg* dialog); protected: // reimplemented /*! \brief Catches keyboard shortcuts.*/ void keyPressEvent(QKeyEvent *); /*! \brief Sets the destruction times as specified by options.*/ void closeEvent(QCloseEvent *); /*! \brief Saves the size of the dialog as default if so specified in options.*/ void resizeEvent(QResizeEvent *); /*! \brief Removes the destruction timer.*/ void showEvent(QShowEvent *); /*! \brief Invokes activated() if activated.*/ void changeEvent(QEvent *e); private slots: /*! \brief Popsup a dialog for saving the contents of the whiteboard to an SVG file. */ void save(); /*! \brief Popsup a dialog asking for a new viewBox for the whiteboard.*/ void setGeometry(); /*! \brief Popsup a color dialog and sets the selected color as the default stroke color for new items.*/ void setStrokeColor(); /*! \brief Popsup a color dialog and sets the selected color as the default fill color for new items.*/ void setFillColor(); /*! \brief Sets the stroke width for new elements based on the invoker.*/ void setStrokeWidth(QAction *); /*! \brief Sets the WbWidget's mode based on the invoker.*/ void setMode(QAction *); /*! \brief Sets keep open false.*/ void setKeepOpenFalse(); /*! \brief Constructs the context menu.*/ void buildMenu(); private: /*! \brief Pops up the context menu.*/ void contextMenuEvent(QContextMenuEvent *); /*! \brief Set a timer for self destruction in the give n number of minutes.*/ void setSelfDestruct(int); /*! \brief Update the caption to indicate the number of unseen whiteboard messages.*/ void updateCaption(); /*! \brief The main widget.*/ WbWidget *wbWidget_; /*! \brief The label showing own identity.*/ AccountLabel *lb_ident_; /*! \brief The line edit showing target JID.*/ QLineEdit *le_jid_; /*! \brief The context menu.*/ QMenu *pm_settings_; /*! \brief The main toolbar.*/ QToolBar *toolbar_; /*! \brief The action group for colors.*/ QActionGroup *group_colors_; /*! \brief The action group for widths.*/ QActionGroup *group_widths_; /*! \brief The action group for modes.*/ QActionGroup *group_modes_; /*! \brief The menu for colors.*/ QMenu *menu_colors_; /*! \brief The menu for widths.*/ QMenu *menu_widths_; /*! \brief The menu for modes.*/ QMenu *menu_modes_; QAction *act_color_, *act_fill_; IconAction *act_end_, *act_clear_, *act_save_, *act_geometry_, *act_widths_, *act_modes_; /*! \brief True if the target is a groupchat.*/ bool groupChat_; /*! \brief The number of whiteboard messages since last activation.*/ uint pending_; /*! \brief Boolean set true if a new edit was just received.*/ bool keepOpen_; /*! \brief Boolean about whether further edits to the session are allowed.*/ bool allowEdits_; /*! \brief Pointer to the timer that will invoke destruction.*/ QTimer *selfDestruct_; }; #endif psi-0.14/src/whiteboarding/wbitem.h0000644000175000017500000000756511305557613015433 0ustar janjan/* * wbitem.h - the item classes for the SVG WB * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBITEM_H #define WBITEM_H #include #include #include #include #include "iconaction.h" #include "../sxe/sxesession.h" class WbScene; class WbWidget; /*! \brief The context menu for WbItems * This menu pops up when as the context menu for WbItems and displays * \sa WbItem */ class WbItemMenu : public QMenu { Q_OBJECT public: /*! \brief Constructor * Constructs a new empty menu. */ WbItemMenu(QWidget* parent); /*! \brief Destructor * Deletes all the actiongroups and their actions. */ ~WbItemMenu(); /*! \brief Add actiongroup to the menu.*/ void addActionGroup(QActionGroup*); private slots: /*! \brief Destruct self.*/ void destructSelf(); private: /*! \brief The actiongroups that the menu shows.*/ QList groups_; }; class WbItem : public QGraphicsSvgItem { Q_OBJECT public: /*! \brief Constructor * Constructs a new whiteboard item that visualized \a node. */ WbItem(SxeSession* session, QSvgRenderer* renderer, QDomElement node, WbScene* scene, WbWidget* widget); /*! \brief Destructor * Makes sure that the item gets deleted from the underlying document */ ~WbItem(); /*! \brief Returns the xml:id of the node.*/ QString id(); /*! \brief Returns the underlying node.*/ QDomNode node(); /*! \brief Regenerates the SVG transformation matrix.*/ void regenerateTransform(); /*! \brief Adds the item to the scene. Generates an 'id' attribute for the node if none exists. */ void addToScene(); /*! \brief Removes the item from the scene. */ void removeFromScene(); /*! \brief Resets the position of the item according to the SVG and clears any QGraphicsItem transformations.*/ void resetPos(); /*! \brief Returns a QTransform based on \a string provided in the SVG 'transform' attribute format.*/ static QMatrix parseSvgTransform(QString string); /*! \brief Returns a QString in the SVG 'transform' attribute format based on \a matrix.*/ static QString toSvgTransform(const QMatrix &matrix); protected: /*! \brief Constructs and popsup the default context menu.*/ virtual void contextMenuEvent (QGraphicsSceneContextMenuEvent *); /*! \brief Implements the default item interaction behaviour. * The action depends on the mode of widget_; */ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *); /*! \brief Implements the default item interaction behaviour. * The action depends on the mode of widget_; */ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *); private: /*! \brief Construct a context menu with the default items.*/ WbItemMenu* constructContextMenu(); /*! \brief Return the center of the item in item coordinates.*/ QPointF center(); // The session that the item belongs to SxeSession* session_; // The WbScene that the item belongs to WbScene* scene_; // The WbWidget that shows the item WbWidget* widget_; // The node SVG node that's being visualized QDomElement node_; }; #endif psi-0.14/src/whiteboarding/wbwidget.cpp0000644000175000017500000003254711305557613016311 0ustar janjan/* * wbwidget.cpp - a widget for processing and showing whiteboard * messages. * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbwidget.h" #include "wbnewpath.h" #include "wbnewimage.h" #include #include WbWidget::WbWidget(SxeSession* session, QWidget *parent) : QGraphicsView(parent) { newWbItem_ = 0; adding_ = 0; addVertex_ = false; strokeColor_ = Qt::black; fillColor_ = Qt::transparent; strokeWidth_ = 1; session_ = session; // setCacheMode(CacheBackground); setRenderHint(QPainter::Antialiasing); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // Make the scroll bars always stay on because otherwise the resize event can cause // an infinite loop as the effective size of the widget changes when scroll bars are // added/removed setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // create the scene scene_ = new WbScene(session_, this); scene_->setItemIndexMethod(QGraphicsScene::NoIndex); setRenderHint(QPainter::Antialiasing); setTransformationAnchor(AnchorUnderMouse); setResizeAnchor(AnchorViewCenter); setScene(scene_); // render the initial document rerender(); // rerender on update connect(session_, SIGNAL(documentUpdated(bool)), SLOT(handleDocumentUpdated(bool))); // add the initial items const QDomNodeList children = session_->document().documentElement().childNodes(); for(uint i = 0; i < children.length(); i++) { const QDomNode node = children.at(i); if(node.isElement()) { queueNodeInspection(node.toElement()); } } inspectNodes(); // add new items as nodes are added // remove/add items if corresponding nodes are moved connect(session_, SIGNAL(nodeAdded(QDomNode, bool)), SLOT(queueNodeInspection(QDomNode))); connect(session_, SIGNAL(nodeMoved(QDomNode, bool)), SLOT(queueNodeInspection(QDomNode))); // remove items if corresponding nodes are deleted connect(session_, SIGNAL(nodeToBeRemoved(QDomNode, bool)), SLOT(removeWbItem(QDomNode))); connect(session_, SIGNAL(nodeToBeRemoved(QDomNode, bool)), SLOT(checkForRemovalOfId(QDomNode))); // adjust the viewBox as necessary connect(session_, SIGNAL(nodeAdded(QDomNode, bool)), SLOT(checkForViewBoxChange(QDomNode))); connect(session_, SIGNAL(nodeMoved(QDomNode, bool)), SLOT(checkForViewBoxChange(QDomNode))); connect(session_, SIGNAL(chdataChanged(QDomNode, bool)), SLOT(checkForViewBoxChange(QDomNode))); // set the default mode to select setMode(Select); // set the initial size if(session_->document().documentElement().hasAttribute("viewBox")) checkForViewBoxChange(session_->document().documentElement().attributeNode("viewBox")); else { QSize size; QRectF rect = scene_->sceneRect(); size.setWidth(rect.x() + rect.width()); size.setHeight(rect.y() + rect.height()); if(size.width() > 0 && size.height() > 0) setSize(size); else setSize(QSize(400, 600)); } } SxeSession* WbWidget::session() { return session_; } WbWidget::Mode WbWidget::mode() { return mode_; } void WbWidget::setMode(Mode mode) { mode_ = mode; if(mode_ < DrawPath) { if(newWbItem_) { delete newWbItem_; newWbItem_ = 0; } } if(mode_ >= Erase) { setDragMode(QGraphicsView::NoDrag); setInteractive(false); setCursor(Qt::CrossCursor); } else { setInteractive(true); } if(mode_ == Select) { setDragMode(QGraphicsView::RubberBandDrag); setCursor(Qt::ArrowCursor); } else if(mode_ == Translate) { setDragMode(QGraphicsView::RubberBandDrag); setCursor(Qt::SizeAllCursor); } else if(mode_ == Rotate) { setDragMode(QGraphicsView::RubberBandDrag); unsetCursor(); // TODO: load cursor from image } else if(mode_ == Scale) { setDragMode(QGraphicsView::RubberBandDrag); setCursor(Qt::SizeBDiagCursor); } else if(mode_ == Scroll) { setDragMode(QGraphicsView::ScrollHandDrag); } } void WbWidget::setSize(const QSize &size) { session_->setAttribute(session_->document().documentElement(), "viewBox", QString("0 0 %1 %2").arg(size.width()).arg(size.height())); session_->flush(); } /*! \brief Generates a QRectF based on \a string provided in the SVG viewBox format. */ static QRectF parseSvgViewBox(QString string) { QString strings[4]; qreal numbers[4]; for(int i = 0, j = 0; i < 4; i++) { // skip spaces before number while(string[j].isSpace() && j < string.length()) j++; while(!string[j].isSpace() && j < string.length()) { if(string[j].isNumber()) strings[i] += string[j]; j++; } numbers[i] = strings[i].toDouble(); } // qDebug() << QString("QRectF(%1 %2 %3 %4)").arg(numbers[0]).arg(numbers[1]).arg(numbers[2]).arg(numbers[3]).toAscii(); return QRect(numbers[0], numbers[1], numbers[2], numbers[3]); } void WbWidget::checkForViewBoxChange(const QDomNode &node) { if(node.isAttr() && node.nodeName().toLower() == "viewbox" && node.parentNode() == session_->document().documentElement()) { QRectF box = parseSvgViewBox(node.nodeValue()); if(box.width() > 0 && box.height() > 0) { scene_->setSceneRect(box); } } } void WbWidget::setStrokeColor(const QColor &color) { strokeColor_ = color; } void WbWidget::setFillColor(const QColor &color) { fillColor_ = color; } void WbWidget::setStrokeWidth(int width) { strokeWidth_ = width; } void WbWidget::clear() { foreach(QGraphicsItem* graphicsitem, scene_->items()) { WbItem* wbitem = dynamic_cast(graphicsitem); if(wbitem) session_->removeNode(wbitem->node()); } session_->flush(); } QSize WbWidget::sizeHint() const { if(scene_) return scene_->sceneRect().size().toSize(); else return QSize(); } void WbWidget::resizeEvent(QResizeEvent * event) { // Never show areas outside the sceneRect // Doesn't consider rotated views. QMatrix t; qreal sx = event->size().width() / scene_->sceneRect().width(); qreal sy = event->size().height() / scene_->sceneRect().height(); // Never shrink the view. Only enlarge if necessary. if(sx > 1 || sy > 1) { if(sx > sy) t.scale(sx, sx); else t.scale(sy, sy); } setMatrix(t); QGraphicsView::resizeEvent(event); } void WbWidget::mousePressEvent(QMouseEvent * event) { // ignore non-leftclicks when not in Select mode if(event->button() != Qt::LeftButton && mode_ != Select) return; // delete any temporary item being drawn if(newWbItem_) { delete newWbItem_; newWbItem_ = 0; } QPointF startPoint = mapToScene(mapFromGlobal(event->globalPos())); if(mode_ == DrawPath) { // // Create the element with starting position // QPointF sp = mapToScene(mapFromGlobal(event->globalPos())); // qDebug() << QString("1: (%1, %2)").arg(sp.x()).arg(sp.y()); newWbItem_ = new WbNewPath(scene_, startPoint, strokeWidth_, strokeColor_, fillColor_); return; } else if(mode_ == DrawText) { } else if(mode_ == DrawRectangle) { } else if(mode_ == DrawEllipse) { } else if(mode_ == DrawCircle) { } else if(mode_ == DrawLine) { } else if(mode_ == DrawImage) { QString filename = QFileDialog::getOpenFileName(this, "Choose an image", QString(), "Images (*.png *.jpg)"); if(!filename.isEmpty()) { newWbItem_ = new WbNewImage(scene_, startPoint, filename); session_->insertNodeAfter(newWbItem_->serializeToSvg(), session_->document().documentElement()); session_->flush(); delete newWbItem_; newWbItem_ = 0; } } QGraphicsView::mousePressEvent(event); } void WbWidget::mouseMoveEvent(QMouseEvent * event) { if(mode_ < Erase) { QGraphicsView::mouseMoveEvent(event); return; } if(QApplication::mouseButtons() != Qt::MouseButtons(Qt::LeftButton)) { if(newWbItem_) { delete newWbItem_; newWbItem_ = 0; } return; } if(mode_ == Erase) { if(event->buttons() != Qt::MouseButtons(Qt::LeftButton)) return; // Erase all items that appear in a 2*strokeWidth_ square with center at the event position QPointF p = mapToScene(mapFromGlobal(event->globalPos())); QGraphicsRectItem* eraseRect = scene_->addRect(QRectF(p.x() - strokeWidth_, p.y() - strokeWidth_, 2 * strokeWidth_, 2 * strokeWidth_)); foreach(QGraphicsItem * item, eraseRect->collidingItems()) { WbItem* wbitem = dynamic_cast(item); if(wbitem) session_->removeNode(wbitem->node()); } delete eraseRect; eraseRect = 0; event->ignore(); return; } else if(mode_ >= DrawPath && newWbItem_) { newWbItem_->parseCursorMove(mapToScene(mapFromGlobal(event->globalPos()))); } } void WbWidget::mouseReleaseEvent(QMouseEvent * event) { if(event->button() != Qt::LeftButton && mode_ >= Erase) return; if (newWbItem_ && mode_ >= DrawPath && mode_ != DrawImage) { session_->insertNodeAfter(newWbItem_->serializeToSvg(), session_->document().documentElement()); session_->flush(); delete newWbItem_; newWbItem_ = 0; return; } QGraphicsView::mouseReleaseEvent(event); } WbItem* WbWidget::wbItem(const QDomNode &node) { foreach(WbItem* wbitem, items_) { if(wbitem->node() == node) return wbitem; } return 0; } void WbWidget::handleDocumentUpdated(bool remote) { Q_UNUSED(remote); inspectNodes(); rerender(); } void WbWidget::inspectNodes() { while(!recentlyRelocatedNodes_.isEmpty()) { QDomNode node = recentlyRelocatedNodes_.takeFirst(); if(!node.isElement()) continue; // check if we already have a WbItem for the node WbItem* item = wbItem(node); // We don't need to do anything iff node is child of and item exists or vice versa if((item != NULL) == (node.parentNode() == session_->document().documentElement())) continue; // Otherwise, either item exists and needs to be removed // or it doesn't exist and needs to be added if(item) removeWbItem(item); else items_.append(new WbItem(session_, &renderer_, node.toElement(), scene_, this)); } } void WbWidget::queueNodeInspection(const QDomNode &node) { if(node.isElement()) recentlyRelocatedNodes_.append(node); } void WbWidget::removeWbItem(const QDomNode &node) { removeWbItem(wbItem(node)); } void WbWidget::removeWbItem(WbItem *wbitem) { if(wbitem) { // Remove from the lookup table to avoid infinite loop of deletes items_.removeAll(wbitem); // items_.takeAt(items_.indexOf(wbitem)); idlessItems_.removeAll(wbitem); delete wbitem; } } void WbWidget::addIds() { while(!idlessItems_.isEmpty()) idlessItems_.takeFirst()->addToScene(); session_->flush(); } void WbWidget::addToIdLess(const QDomElement &element) { if(element.parentNode() != session_->document().documentElement()) return; WbItem* item = wbItem(element); if(item && !idlessItems_.contains(item)) { // Remove from the scene until a new 'id' attribute is added item->removeFromScene(); idlessItems_.append(item); // Try adding the 'id' attribute after a random delay of 0 to 2s QTimer::singleShot(2000 * qrand() / RAND_MAX, this, SLOT(addIds())); } } void WbWidget::checkForRemovalOfId(QDomNode node) { if(node.isAttr()) { if(node.nodeName() == "id") { while(!(node.isElement() || node.isNull())) node = node.parentNode(); if(!node.isNull()) addToIdLess(node.toElement()); } } } void WbWidget::rerender() { QString xmldump; QTextStream stream(&xmldump); session_->document().save(stream, 1); // qDebug("Document in WbWidget:"); // qDebug() << xmldump.toAscii(); renderer_.load(xmldump.toAscii()); // Update all positions if changed foreach(WbItem* wbitem, items_) { // resetting elementId is necessary for rendering some updates to the element (e.g. adding child elements to ) wbitem->setElementId(wbitem->id()); // qDebug() << QString("Rerendering %1").arg((unsigned int) wbitem).toAscii(); wbitem->resetPos(); } } psi-0.14/src/whiteboarding/wbscene.cpp0000644000175000017500000001532211305557613016113 0ustar janjan/* * wbscene.cpp - an SVG whiteboard scene class * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbscene.h" WbScene::WbScene(SxeSession* session, QObject * parent) : QGraphicsScene(parent) { session_ = session; }; void WbScene::queueTransformationRegeneration(WbItem* item) { if(item && !pendingTranformations_.contains(item)) pendingTranformations_.append(QPointer(item)); } void WbScene::regenerateTransformations() { foreach(QPointer item, pendingTranformations_) { if(item) { // qDebug() << QString("Regenerating %1 transform.").arg((unsigned int) &(*item)).toAscii(); item->regenerateTransform(); } } pendingTranformations_.clear(); session_->flush(); } QPointF WbScene::selectionCenter() const { QList items = selectedItems(); if(items.size() < 1) return QPointF(); QRectF box = items.at(0)->sceneBoundingRect(); foreach(QGraphicsItem* item, items) { box = box.united(item->sceneBoundingRect()); } // qDebug() << QString("Selection center: %1 %2").arg(box.center().x()).arg(box.center().y()).toAscii(); return box.center(); } void WbScene::bringForward(int n) { bring(n, false); } void WbScene::bringToFront() { bring(1, true); } void WbScene::sendBackwards(int n) { bring(-n, false); } void WbScene::sendToBack() { bring(-1, true); } static bool zValueLessThan(QGraphicsItem* item1, QGraphicsItem* item2) { return (item1->zValue() < item2->zValue()); } void WbScene::group() { if(selectedItems().size() > 1) { // Create the group QDomElement temp = QDomDocument().createElement("g"); temp.setAttribute("id", "e" + SxeSession::generateUUID()); const QDomNode group = session_->insertNodeAfter(temp, session_->document().documentElement()); // Arrange the items by Z coordinate QList selected = selectedItems(); qSort(selected.begin(), selected.end(), zValueLessThan); // Reparent each selected item foreach(QGraphicsItem* item, selected) { WbItem* wbitem = dynamic_cast(item); if(wbitem) session_->insertNodeAfter(wbitem->node(), group); } clearSelection(); session_->flush(); } } void WbScene::ungroup() { foreach(QGraphicsItem* item, selectedItems()) { // find the QDomElement matching the selected item WbItem* wbitem = dynamic_cast(item); if(wbitem) { QDomElement group = wbitem->node().toElement(); if(group.nodeName() == "g") { QDomNodeList children = group.childNodes(); QMatrix groupTransform = WbItem::parseSvgTransform(group.attribute("transform")); for(int i = children.size() - 1; i >= 0; i--) { QDomElement child = children.at(i).toElement(); if(!child.isNull()) { if(!groupTransform.isIdentity()) { // combine the transformations of the group and the child QMatrix childTransform = WbItem::parseSvgTransform(child.attribute("transform")); session_->setAttribute(child, "transform", WbItem::toSvgTransform(childTransform * groupTransform)); } // move the child from the group to the root session_->insertNodeAfter(children.at(i), session_->document().documentElement(), group); } } // delete the group itself session_->removeNode(group); } } } clearSelection(); session_->flush(); } void WbScene::bring(int n, bool toExtremum) { if(n == 0) return; // bring each selected item foreach(QGraphicsItem* selecteditem, selectedItems()) { if (!(selecteditem->parentItem() && selecteditem->parentItem()->isSelected())) { WbItem* selectedwbitem = dynamic_cast(selecteditem); if(selectedwbitem) { QList colliding = selecteditem->collidingItems(); // find the relative position of selecteditem itself and // remove other selected items from the list colliding int i = 0; while(i < colliding.size()) { if(selectedItems().contains(colliding[i])) { colliding.removeAt(i); } else if(colliding[i]->zValue() < selecteditem->zValue()) { break; } else i++; } if(n < 0) i--; // bring the selected node n levels above/below the item itself if(colliding.size() > 0) { WbItem* referencewbitem; if(n > 0) { if(i - n > 0 && !toExtremum) referencewbitem = dynamic_cast(colliding[i - n]); else referencewbitem = dynamic_cast(colliding[0]); } else { if(i - n < colliding.size() && !toExtremum) referencewbitem = dynamic_cast(colliding[i - n]); else referencewbitem = dynamic_cast(colliding[colliding.size() - 1]); } if(referencewbitem && !referencewbitem->node().isNull()) { if(n > 0) session_->insertNodeAfter(selectedwbitem->node(), selectedwbitem->node().parentNode(), referencewbitem->node()); else session_->insertNodeBefore(selectedwbitem->node(), selectedwbitem->node().parentNode(), referencewbitem->node()); } } } } } session_->flush(); } psi-0.14/src/whiteboarding/wbnewpath.cpp0000644000175000017500000000717111305557613016467 0ustar janjan/* * wbnewpath.cpp - a class used for representing a path on the whiteboard * while it's being drawn. * Copyright (C) 2008 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbnewpath.h" #include "../sxe/sxesession.h" #include WbNewPath::WbNewPath(QGraphicsScene* s, QPointF startPos, int strokeWidth, const QColor &strokeColor, const QColor &fillColor) : WbNewItem(s) { controlPoint_ = 0; graphicsitem_.setZValue(std::numeric_limits::max()); graphicsitem_.setBrush(QBrush(fillColor)); graphicsitem_.setPen(QPen(QBrush(strokeColor), strokeWidth)); scene->addItem(&graphicsitem_); QPainterPath painterpath(startPos); painterpath.setFillRule(Qt::WindingFill); graphicsitem_.setPath(painterpath); } WbNewPath::~WbNewPath() { if(controlPoint_) delete controlPoint_; } void WbNewPath::parseCursorMove(QPointF newPos) { if(controlPoint_) { QPainterPath painterpath = graphicsitem_.path(); // FIXME: the path should actually go through the "controlPoint_". painterpath.quadTo(*controlPoint_, newPos); graphicsitem_.setPath(painterpath); delete controlPoint_; controlPoint_ = 0; } else { controlPoint_ = new QPointF(newPos); } } QDomNode WbNewPath::serializeToSvg() { if(controlPoint_) { QPainterPath painterpath = graphicsitem_.path(); painterpath.lineTo(*controlPoint_); graphicsitem_.setPath(painterpath); delete controlPoint_; controlPoint_ = 0; } // trim the generated SVG to remove unnecessary nested 's // first find the element QDomNode out = WbNewItem::serializeToSvg(); QDomNodeList children = out.childNodes(); QDomElement trimmed; for(uint i = 0; i < children.length(); i++) { if(children.at(i).isElement()) { if(children.at(i).nodeName() == "path") { trimmed = children.at(i).toElement(); break; } else { trimmed = children.at(i).toElement().elementsByTagName("path").at(0).toElement(); if(!trimmed.isNull()) break; } } } // copy relevant attributes from the parent QDomNamedNodeMap parentAttr = trimmed.parentNode().toElement().attributes(); for(int i = parentAttr.length() - 1; i >= 0; i--) { QString name = parentAttr.item(i).nodeName(); if((name == "stroke" || name == "stroke-width" || name == "stroke-linecap" || name == "fill" || name == "fill-opacity") && !trimmed.hasAttribute(name)) trimmed.setAttributeNode(parentAttr.item(i).toAttr()); } // add a unique 'id' attribute in anticipation of WbWidget's requirements trimmed.setAttribute("id", "e" + SxeSession::generateUUID()); return trimmed; } QGraphicsItem* WbNewPath::graphicsItem() { return &graphicsitem_; } psi-0.14/src/whiteboarding/wbmanager.h0000644000175000017500000000530711305557613016077 0ustar janjan/* * wbmanager.h - Whiteboard manager * Copyright (C) 2007 Joonas Govenius * * Influenced by: * pepmanager.h - Classes for PEP * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBMANAGER_H #define WBMANAGER_H #include "../sxe/sxemanager.h" #include "wbdlg.h" #include namespace XMPP { class Client; class Jid; class Message; } using namespace XMPP; /*! \brief The manager for whiteboard dialogs. * The manager listen to SxeManager to pick up any new sessions negotiated by * it and creates a dialog for each session. * * The manager also provides a possibillity for the local client to start * a new session negotiation with the desired contact. * * \sa WbDlg */ class WbManager : public QObject { Q_OBJECT public: /*! \brief Constructor. * Creates a new manager for the specified Client and PsiAccount */ WbManager(XMPP::Client* client, PsiAccount* pa, SxeManager* sxemanager); /*! \brief Returns true if features contains WBNS and the user wishes to accept the invitation. */ static bool checkInvitation(const Jid &peer, const QList &features); public slots: /*! \brief Opens the existing dialog to the specified contact or starts a new session negotiation if necessary.*/ void openWhiteboard(const Jid &target, const Jid &ownJid, bool groupChat, bool promptInitialDoc = true); private: /*! \brief Return a pointer to a dialog to the specified contact. * If such dialog doesn't exits, returns 0. */ WbDlg* findWbDlg(const Jid &target); /*! \brief A pointer to the PsiAccount to pass to new dialogs.*/ PsiAccount* pa_; /*! \brief A list of dialogs of established sessions.*/ QList dialogs_; /*! \brief A pointer to the SxeManager used for negotiating sessions.*/ SxeManager* sxemanager_; private slots: /*! \brief Removes and deletes the dialog for the given session.*/ void removeDialog(WbDlg* dialog); /*! \brief Returns a pointer to a new dialog to with given contact and session set.*/ void createWbDlg(SxeSession* session); }; #endif psi-0.14/src/whiteboarding/wbmanager.cpp0000644000175000017500000001220011305557613016420 0ustar janjan/* * wbmanager.cpp - Whiteboard manager * Copyright (C) 2007 Joonas Govenius * * Influenced by: * pepmanager.cpp - Classes for PEP * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbmanager.h" #include "psipopup.h" #include #include #define WBNS "http://www.w3.org/2000/svg" #define EMPTYWB " " using namespace XMPP; // ----------------------------------------------------------------------------- WbManager::WbManager(XMPP::Client* client, PsiAccount* pa, SxeManager* sxemanager) { pa_ = pa; sxemanager_ = sxemanager; client->addExtension("whiteboard", Features(WBNS)); connect(sxemanager_, SIGNAL(sessionNegotiated(SxeSession*)), SLOT(createWbDlg(SxeSession*))); sxemanager_->addInvitationCallback(WbManager::checkInvitation); } void WbManager::openWhiteboard(const Jid &target, const Jid &ownJid, bool groupChat, bool promptInitialDoc) { // check that the target supports whiteboarding via SXE QList features; features += WBNS; if(!sxemanager_->checkSupport(target, features)) { QMessageBox::information(NULL, tr("Unsupported"), tr("The contact does not support whiteboarding.")); return; } // See if we have a session for the JID WbDlg* w = findWbDlg(target); if(!w) { // else negotiate a new session and return null QDomDocument doc; if(promptInitialDoc) { bool openExisting = (QMessageBox::Yes == QMessageBox::question(NULL, tr("Open Existing SVG?"), tr("Would you like to open an existing SVG document in the whitebaord?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)); if(openExisting) { // prompt for an existing file QString fileName = QFileDialog::getOpenFileName(NULL, tr("Initial SVG Document for the Whiteboard"), QDir::homePath(), tr("Scalable Vector Graphics (*.svg)")); QFile file(fileName); if(file.open(QIODevice::ReadOnly)) { doc.setContent(file.readAll(), true); file.close(); } } } if(doc.documentElement().nodeName() != "svg") { // initialize with an empty whiteboarding document doc = QDomDocument(); doc.setContent(QString(EMPTYWB), true); } // negotiate the session sxemanager_->startNewSession(target, ownJid, groupChat, doc, features); } else bringToFront(w); } void WbManager::removeDialog(WbDlg* dialog) { dialogs_.takeAt(dialogs_.indexOf(dialog))->deleteLater(); } WbDlg* WbManager::findWbDlg(const Jid &jid) { // find if a dialog for the jid already exists foreach(WbDlg* w, dialogs_) { // does the jid match? if(w->session()->target().compare(jid)) { return w; } } return 0; } void WbManager::createWbDlg(SxeSession* session) { // check if the session is a whiteboarding session bool whiteboarding = false; foreach(QString feature, session->features()) { if(feature == WBNS) whiteboarding = true; } if(whiteboarding) { // create the WbDlg WbDlg* w = new WbDlg(session, pa_); // connect the signals connect(w, SIGNAL(sessionEnded(WbDlg*)), SLOT(removeDialog(WbDlg*))); connect(session, SIGNAL(peerLeftSession(Jid)), w, SLOT(peerLeftSession(Jid))); dialogs_.append(w); bringToFront(w); } } bool WbManager::checkInvitation(const Jid &peer, const QList &features) { if(!features.contains(WBNS)) return false; return (QMessageBox::Yes == QMessageBox::question(NULL, tr("Whiteboarding Invitation?"), tr("%1 has invited you to a whiteboarding session. Would you like to join?").arg(peer.full()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)); } psi-0.14/src/whiteboarding/wbitem.cpp0000644000175000017500000005335211305557613015761 0ustar janjan/* * wbitem.cpp - the item classes for the SVG WB * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbitem.h" #include "wbscene.h" #include "wbwidget.h" #include #include #include #include static QMatrix parseTransformationMatrix(const QString &value); /* * WbItemMenu */ WbItemMenu::WbItemMenu(QWidget* parent) : QMenu(parent) { connect(this, SIGNAL(aboutToHide()), SLOT(destructSelf())); } WbItemMenu::~WbItemMenu() { foreach(QActionGroup* g, groups_) { foreach(QAction* a, g->actions()) { a->deleteLater(); } g->deleteLater(); } } void WbItemMenu::addActionGroup(QActionGroup* g) { groups_.append(g); addActions(g->actions()); } void WbItemMenu::destructSelf() { deleteLater(); } /* * WbItem */ WbItem::WbItem(SxeSession* session, QSvgRenderer* renderer, QDomElement node, WbScene* scene, WbWidget* widget) : QGraphicsSvgItem() { // Store a pointer to the underlying session, scene and node session_ = session; scene_ = scene; widget_ = widget; node_ = node; // qDebug() << QString("constructing %1.").arg(id()).toAscii(); if(node.isNull()) { qDebug("Trying to create a WbItem from a null QDomNode."); return; } // Make the item selectable and movable setFlag(QGraphicsItem::ItemIsSelectable); setFlag(QGraphicsItem::ItemIsMovable); // Enable drag-n-drop setAcceptDrops(true); // Don't cache the SVG setCachingEnabled(false); // Set the renderer for the item setSharedRenderer(renderer); // add the new item to the scene addToScene(); } WbItem::~WbItem() { // qDebug() << QString("destructing %1.").arg(id()).toAscii(); } QString WbItem::id() { return node_.toElement().attribute("id"); } QDomNode WbItem::node() { return node_; } void WbItem::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) { constructContextMenu()->exec(event->screenPos()); } void WbItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event) { event->accept(); if(isSelected()) { if(widget_->mode() == WbWidget::Translate) { // Translate each selected item foreach(QGraphicsItem* graphicsitem, scene()->selectedItems()) { if (!graphicsitem->parentItem() || !graphicsitem->parentItem()->isSelected()) { QPointF d = graphicsitem->mapFromScene(event->scenePos()) - graphicsitem->mapFromScene(event->lastScenePos()); graphicsitem->translate(d.x(), d.y()); // qDebug() QString("Translated %1 by %2 %3").arg((unsigned int) graphicsitem).arg(d.x()).arg(d.y()).toAscii(); // Regenerate the SVG transformation matrix later WbItem* wbitem = dynamic_cast(graphicsitem); if(wbitem) scene_->queueTransformationRegeneration(wbitem); } } } else if(widget_->mode() == WbWidget::Rotate) { // Rotate each selected item // get center coordinates of selected items in scene coordinates QPointF scenePivot = scene_->selectionCenter(); // Determine the direction relative to the center // Divide the sum by two to reduce the "speed" of rotation QPointF difference = event->scenePos() - event->lastScenePos(); // qDebug() << QString("d: %1 %2 = %3 %4 + %5 %6").arg(difference.x()).arg(difference.y()).arg(event->scenePos().x()).arg(event->scenePos().y()).arg(event->lastScenePos().x()).arg(event->lastScenePos().y()); QPointF p = event->scenePos(); QMatrix delta; if(p.x() >= scenePivot.x() && p.y() >= scenePivot.y()) { delta.rotate((-difference.x() + difference.y()) / 2); } else if(p.x() < scenePivot.x() && p.y() >= scenePivot.y()) { delta.rotate((-difference.x() - difference.y()) / 2); } else if(p.x() < scenePivot.x() && p.y() < scenePivot.y()) { delta.rotate((difference.x() - difference.y()) / 2); } else if(p.x() >= scenePivot.x() && p.y() < scenePivot.y()) { delta.rotate((difference.x() + difference.y()) / 2); } foreach(QGraphicsItem* graphicsitem, scene()->selectedItems()) { if (!graphicsitem->parentItem() || !graphicsitem->parentItem()->isSelected()) { QMatrix translation; // get center coordinates of selected items in item coordinates QPointF itemPivot = graphicsitem->mapFromScene(scenePivot); // translates the the item's center to the origin of the item coordinates translation.translate(-itemPivot.x(), -itemPivot.y()); // set the matrix graphicsitem->setTransform(QTransform(translation * delta * translation.inverted()), true); // Regenerate the SVG transformation matrix later WbItem* wbitem = dynamic_cast(graphicsitem); if(wbitem) scene_->queueTransformationRegeneration(wbitem); } } } else if(widget_->mode() == WbWidget::Scale) { // Scale each selected item foreach(QGraphicsItem* graphicsitem, scene()->selectedItems()) { if (!graphicsitem->parentItem() || !graphicsitem->parentItem()->isSelected()) { // get center coordinates in item coordinates QPointF c = center(); QMatrix translation, delta; // translates the the item's center to the origin of the item coordinates translation.translate(-c.x(), -c.y()); // Scale. // Moving mouse up enlarges, down shrinks, y axis. // Moving mouse right enlarges, left shrinks, x axis. QPointF difference = event->scenePos() - event->lastScenePos(); // Note: the y axis points downwards in scene coordinates delta.scale(1 + difference.x()/50, 1 - difference.y()/50); // set the matrix setTransform(QTransform(translation * delta * translation.inverted()), true); // Regenerate the SVG transformation matrix later scene_->queueTransformationRegeneration(dynamic_cast(graphicsitem)); } } } } } void WbItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { QGraphicsSvgItem::mouseReleaseEvent(event); scene_->regenerateTransformations(); } QMatrix WbItem::parseSvgTransform(QString string) { string = string.trimmed(); if(string.isEmpty()) return QMatrix(); return parseTransformationMatrix(string); } QString WbItem::toSvgTransform(const QMatrix &m) { return QString("matrix(%1 %2 %3 %4 %5 %6)").arg(m.m11()).arg(m.m12()).arg(m.m21()).arg(m.m22()).arg(m.dx()).arg(m.dy()); } void WbItem::regenerateTransform() { // Replace the QGraphicsItem transformation with an SVG transformation. // Possible as long as no perspective transformations have been applied. // delta is the new transformation to be applied QMatrix delta = transform().toAffine(); if(delta.isIdentity()) return; // get the existing SVG transformation QString oldValue = node_.attribute("transform"); QMatrix oldTransform = parseSvgTransform(oldValue); // construct a translation that translates the item to (0,0) in scene coordinates QMatrix translation; // translates the the item's center to the origin of the item coordinates translation.translate(-pos().x(), -pos().y()); // generate the string representation QString newValue = toSvgTransform(oldTransform * translation * delta * translation.inverted()); if(newValue != oldValue) { resetTransform(); session_->setAttribute(node_, "transform", newValue); } } void WbItem::addToScene() { // qDebug() << QString("adding %1 to scene.").arg(id()).toAscii(); // Do nothing if already added and id matches if(scene_ == scene() && node_.hasAttribute("id") && node_.attribute("id") == elementId()) return; // Read or generate an xml:id for the node QString id; if(node_.hasAttribute("id")) id = node_.attribute("id"); else { id = "e" + SxeSession::generateUUID(); // qDebug() << QString("Setting new id to %1").arg(id).toAscii(); session_->setAttribute(node_, "id", id); session_->flush(); } // Only render the indicated item setElementId(id); // Set the position resetPos(); scene_->addItem(this); } void WbItem::removeFromScene() { // qDebug() << QString("removing %1 from scene.").arg(id()).toAscii(); scene_->removeItem(this); setElementId(QString()); } void WbItem::resetPos() { // set the x & y approriately; setPos(renderer()->boundsOnElement(id()).topLeft()); // set the drawing order // TODO: optimize int i = 0; QDomNodeList children = node_.parentNode().childNodes(); while(children.at(i) != node_) i++; setZValue(i); } WbItemMenu* WbItem::constructContextMenu() { WbItemMenu* menu = new WbItemMenu(0); if(scene_) { // Add the default actions QActionGroup* group; // QAction* qaction; QPixmap pixmap; // group = new QActionGroup(0); // pixmap(2, 2); // pixmap.fill(QColor(Qt::black)); // qaction = new QAction(QIcon(pixmap), tr("Thin stroke"), group); // qaction->setData(QVariant(1)); // pixmap = QPixmap(6, 6); // pixmap.fill(QColor(Qt::black)); // qaction = new QAction(QIcon(pixmap), tr("Medium stroke"), group); // qaction->setData(QVariant(3)); // pixmap = QPixmap(12, 12); // pixmap.fill(QColor(Qt::black)); // qaction = new QAction(QIcon(pixmap), tr("Thick stroke"), group); // qaction->setData(QVariant(6)); // connect(group, SIGNAL(triggered(QAction*)), wbscene, SLOT(setStrokeWidth(QAction*))); // menu->addActionGroup(group); // menu->addSeparator(); // group = new QActionGroup(0); // pixmap = QPixmap(16, 16); // pixmap.fill(QColor(Qt::darkCyan)); // qaction = new QAction(QIcon(pixmap), tr("Change stroke color"), group); // connect(qaction, SIGNAL(triggered()), wbscene, SLOT(setStrokeColor())); // pixmap.fill(QColor(Qt::darkYellow)); // qaction = new QAction(QIcon(pixmap), tr("Change fill color"), group); // connect(qaction, SIGNAL(triggered()), wbscene, SLOT(setFillColor())); // menu->addActionGroup(group); // menu->addSeparator(); group = new QActionGroup(0); IconAction* action = new IconAction(tr("Bring forward"), "psi/bringForwards", tr("Bring forward"), 0, group); connect(action, SIGNAL(triggered()), scene_, SLOT(bringForward())); action = new IconAction(tr("Bring to front"), "psi/bringToFront", tr("Bring to front"), 0, group); connect(action, SIGNAL(triggered()), scene_, SLOT(bringToFront())); action = new IconAction(tr("Send backwards"), "psi/sendBackwards", tr("Send backwards"), 0, group); connect(action, SIGNAL(triggered()), scene_, SLOT(sendBackwards())); action = new IconAction(tr("Send to back"), "psi/sendToBack", tr("Send to back"), 0, group); connect(action, SIGNAL(triggered()), scene_, SLOT(sendToBack())); menu->addActionGroup(group); menu->addSeparator(); group = new QActionGroup(0); action = new IconAction(tr("Group"), "psi/group", tr("Group"), 0, group); connect(action, SIGNAL(triggered()), scene_, SLOT(group())); action = new IconAction(tr("Ungroup"), "psi/ungroup", tr("Ungroup"), 0, group); connect(action, SIGNAL(triggered()), scene_, SLOT(ungroup())); menu->addActionGroup(group); } return menu; } QPointF WbItem::center() { // Determine the center of the item in item coordinates before transformation QRectF r = boundingRect(); QPointF c(r.x() + r.width()/2, r.y() + r.height()/2); // qDebug() << QString("center: %1 + %2 %3 + %4").arg(r.x()).arg(r.width()/2).arg(r.y()).arg(r.height()/2); // return the center with transformation applied return transform().map(c); } // The following functions are from qt-mac-opensource-src-4.3.1/src/svg/qsvghandler.cpp /**************************************************************************** ** ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. ** ** This file is part of the QtSVG module of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://trolltech.com/products/qt/licenses/licensing/opensource/ ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://trolltech.com/products/qt/licenses/licensing/licensingoverview ** or contact the sales department at sales@trolltech.com. ** ** In addition, as a special exception, Trolltech gives you certain ** additional rights. These rights are described in the Trolltech GPL ** Exception version 1.0, which can be found at ** http://www.trolltech.com/products/qt/gplexception/ and in the file ** GPL_EXCEPTION.txt in this package. ** ** In addition, as a special exception, Trolltech, as the sole copyright ** holder for Qt Designer, grants users of the Qt/Eclipse Integration ** plug-in the right for the Qt/Eclipse Integration to link to ** functionality provided by Qt Designer and its related libraries. ** ** Trolltech reserves all rights not expressly granted herein. ** ** Trolltech ASA (c) 2007 ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ double qstrtod(const char *s00, char const **se, bool *ok); static qreal toDouble(const QChar *&str) { const int maxLen = 255;//technically doubles can go til 308+ but whatever char temp[maxLen+1]; int pos = 0; if (*str == QLatin1Char('-')) { temp[pos++] = '-'; ++str; } else if (*str == QLatin1Char('+')) { ++str; } while (*str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } if (*str == QLatin1Char('.') && pos < maxLen) { temp[pos++] = '.'; ++str; } while (*str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } bool exponent = false; if (*str == QLatin1Char('e') && pos < maxLen) { exponent = true; temp[pos++] = 'e'; ++str; if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } while (*str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } } temp[pos] = '\0'; qreal val; if (!exponent && pos < 10) { int ival = 0; const char *t = temp; bool neg = false; if(*t == '-') { neg = true; ++t; } while(*t && *t != '.') { ival *= 10; ival += (*t) - '0'; ++t; } if(*t == '.') { ++t; int div = 1; while(*t) { ival *= 10; ival += (*t) - '0'; div *= 10; ++t; } val = ((qreal)ival)/((qreal)div); } else { val = ival; } if (neg) val = -val; } else { #ifdef Q_WS_QWS if(sizeof(qreal) == sizeof(float)) val = strtof(temp, 0); else #endif { bool ok = false; val = qstrtod(temp, 0, &ok); } } return val; } static QVector parseNumbersList(const QChar *&str) { QVector points; if (!str) return points; points.reserve(32); while (*str == QLatin1Char(' ')) ++str; while ((*str >= QLatin1Char('0') && *str <= QLatin1Char('9')) || *str == QLatin1Char('-') || *str == QLatin1Char('+') || *str == QLatin1Char('.')) { points.append(::toDouble(str)); while (*str == QLatin1Char(' ')) ++str; if (*str == QLatin1Char(',')) ++str; //eat the rest of space while (*str == QLatin1Char(' ')) ++str; } return points; } static QMatrix parseTransformationMatrix(const QString &value) { QMatrix matrix; const QChar *str = value.constData(); while (*str != QLatin1Char(0)) { if (str->isSpace() || *str == QLatin1Char(',')) { ++str; continue; } enum State { Matrix, Translate, Rotate, Scale, SkewX, SkewY }; State state = Matrix; if (*str == QLatin1Char('m')) { //matrix const char *ident = "atrix"; for (int i = 0; i < 5; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Matrix; } else if (*str == QLatin1Char('t')) { //translate const char *ident = "ranslate"; for (int i = 0; i < 8; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Translate; } else if (*str == QLatin1Char('r')) { //rotate const char *ident = "otate"; for (int i = 0; i < 5; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Rotate; } else if (*str == QLatin1Char('s')) { //scale, skewX, skewY ++str; if (*str == QLatin1Char('c')) { const char *ident = "ale"; for (int i = 0; i < 3; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Scale; } else if (*str == QLatin1Char('k')) { if (*(++str) != QLatin1Char('e')) goto error; if (*(++str) != QLatin1Char('w')) goto error; ++str; if (*str == QLatin1Char('X')) state = SkewX; else if (*str == QLatin1Char('Y')) state = SkewY; else goto error; ++str; } else { goto error; } } else { goto error; } while (str->isSpace()) ++str; if (*str != QLatin1Char('(')) goto error; ++str; QVector points = parseNumbersList(str); if (*str != QLatin1Char(')')) goto error; ++str; if(state == Matrix) { if(points.count() != 6) goto error; matrix = matrix * QMatrix(points[0], points[1], points[2], points[3], points[4], points[5]); } else if (state == Translate) { if (points.count() == 1) matrix.translate(points[0], 0); else if (points.count() == 2) matrix.translate(points[0], points[1]); else goto error; } else if (state == Rotate) { if(points.count() == 1) { matrix.rotate(points[0]); } else if (points.count() == 3) { matrix.translate(points[1], points[2]); matrix.rotate(points[0]); matrix.translate(-points[1], -points[2]); } else { goto error; } } else if (state == Scale) { if (points.count() < 1 || points.count() > 2) goto error; qreal sx = points[0]; qreal sy = sx; if(points.count() == 2) sy = points[1]; matrix.scale(sx, sy); } else if (state == SkewX) { if (points.count() != 1) goto error; const qreal deg2rad = qreal(0.017453292519943295769); matrix.shear(tan(points[0]*deg2rad), 0); } else if (state == SkewY) { if (points.count() != 1) goto error; const qreal deg2rad = qreal(0.017453292519943295769); matrix.shear(0, tan(points[0]*deg2rad)); } } error: return matrix; } psi-0.14/src/whiteboarding/wbnewitem.cpp0000644000175000017500000000462611305557613016473 0ustar janjan/* * wbnewitem.cpp - a class used for representing items on the whiteboard * while they're being drawn. * Copyright (C) 2008 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbnewitem.h" #include "../sxe/sxesession.h" #include #include #include #include WbNewItem::WbNewItem(QGraphicsScene* s) { scene = s; } WbNewItem::~WbNewItem() { } QDomNode WbNewItem::serializeToSvg() { if(!graphicsItem()) return QDomDocumentFragment(); // Generate the SVG using QSvgGenerator QBuffer buffer; QSvgGenerator generator; generator.setOutputDevice(&buffer); QPainter painter; QStyleOptionGraphicsItem options; painter.begin(&generator); graphicsItem()->paint(&painter, &options); painter.end(); // qDebug("Serialized SVG doc:"); // qDebug(buffer.buffer()); // Parse the children of the new root from the buffer to a document fragment // also add an 'id' attribute to each of the children QDomDocument tempDoc; tempDoc.setContent(buffer.buffer()); QDomDocumentFragment fragment = tempDoc.createDocumentFragment(); QDomNodeList children = tempDoc.documentElement().childNodes(); for(int i = children.length() - 1; i >= 0; i--) { // skip , <desc/>, and <defs/> if(children.at(i).isElement() && !(children.at(i).nodeName() == "title" || children.at(i).nodeName() == "desc" || children.at(i).nodeName() == "defs")) { children.at(i).toElement().setAttribute("id", "e" + SxeSession::generateUUID()); fragment.insertBefore(children.at(i), QDomNode()); } } return fragment; } ����������������������������������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbdlg.cpp����������������������������������������������������������������0000644�0001750�0001750�00000032662�11305557613�015572� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbdlg.cpp - dialog for whiteboarding * Copyright (C) 2006 Joonas Govenius * * Originally developed from: * chatdlg.cpp - dialog for handling chats * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbdlg.h" #include <QMessageBox> #include <QHBoxLayout> #include <QVBoxLayout> #include <QColorDialog> #include "accountlabel.h" #include "stretchwidget.h" #include "iconset.h" //---------------------------------------------------------------------------- // WbDlg //---------------------------------------------------------------------------- WbDlg::WbDlg(SxeSession* session, PsiAccount* pa) { if ( PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool() ) setAttribute(Qt::WA_MacMetalStyle); groupChat_ = session->groupChat(); pending_ = 0; keepOpen_ = false; allowEdits_ = true; selfDestruct_ = 0; QVBoxLayout *vb1 = new QVBoxLayout(this); // first row le_jid_ = new QLineEdit(this); le_jid_->setReadOnly(true); le_jid_->setFocusPolicy(Qt::NoFocus); le_jid_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); lb_ident_ = new AccountLabel(this); lb_ident_->setAccount(pa); lb_ident_->setShowJid(false); lb_ident_->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); QHBoxLayout *hb1 = new QHBoxLayout(); hb1->addWidget(le_jid_); hb1->addWidget(lb_ident_); vb1->addLayout(hb1); // mid area wbWidget_ = new WbWidget(session, this); wbWidget_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); vb1->addWidget(wbWidget_); // Bottom (tool) area act_save_ = new IconAction(tr("Save session"), "psi/saveBoard", tr("Save the contents of the whiteboard"), 0, this ); act_geometry_ = new IconAction(tr("Change the geometry"), "psi/whiteboard", tr("Change the geometry"), 0, this ); act_clear_ = new IconAction(tr("End session"), "psi/clearChat", tr("Clear the whiteboard"), 0, this ); act_end_ = new IconAction(tr("End session"), "psi/closetab", tr("End session"), 0, this ); // Black is the default color QPixmap pixmap(16, 16); pixmap.fill(QColor(Qt::black)); act_color_ = new QAction(QIcon(pixmap), tr("Stroke color"), this); pixmap.fill(QColor(Qt::lightGray)); act_fill_ = new QAction(QIcon(pixmap), tr("Fill color"), this); act_widths_ = new IconAction(tr("Stroke width" ), "psi/drawPaths", tr("Stroke width"), 0, this ); act_modes_ = new IconAction(tr("Edit mode" ), "psi/select", tr("Edit mode"), 0, this ); group_widths_ = new QActionGroup(this); group_modes_ = new QActionGroup(this); connect(act_color_, SIGNAL(triggered()), SLOT(setStrokeColor())); connect(act_fill_, SIGNAL(triggered()), SLOT(setFillColor())); connect(group_widths_, SIGNAL(triggered(QAction *)), SLOT(setStrokeWidth(QAction *))); connect(group_modes_, SIGNAL(triggered(QAction *)), SLOT(setMode(QAction *))); connect(act_save_, SIGNAL(triggered()), SLOT(save())); connect(act_geometry_, SIGNAL(triggered()), SLOT(setGeometry())); connect(act_clear_, SIGNAL(triggered()), wbWidget_, SLOT(clear())); connect(act_end_, SIGNAL(triggered()), SLOT(endSession())); pixmap = QPixmap(2, 2); pixmap.fill(QColor(Qt::black)); QAction* widthaction = new QAction(QIcon(pixmap), tr("Thin stroke"), group_widths_); widthaction->setData(QVariant(1)); widthaction->setCheckable(true); widthaction->trigger(); pixmap = QPixmap(6, 6); pixmap.fill(QColor(Qt::black)); widthaction = new QAction(QIcon(pixmap), tr("Medium stroke"), group_widths_); widthaction->setData(QVariant(3)); widthaction->setCheckable(true); pixmap = QPixmap(12, 12); pixmap.fill(QColor(Qt::black)); widthaction = new QAction(QIcon(pixmap), tr("Thick stroke"), group_widths_); widthaction->setData(QVariant(6)); widthaction->setCheckable(true); IconAction* action; action = new IconAction(tr("Select"), "psi/select", tr("Select"), 0, group_modes_ ); action->setData(QVariant(WbWidget::Select)); action->setCheckable(true); action = new IconAction(tr( "Translate"), "psi/translate", tr("Translate"), 0, group_modes_ ); action->setData(QVariant(WbWidget::Translate)); action->setCheckable(true); action = new IconAction(tr( "Rotate"), "psi/rotate", tr("Rotate"), 0, group_modes_ ); action->setData(QVariant(WbWidget::Rotate)); action->setCheckable(true); action = new IconAction(tr( "Scale"), "psi/scale", tr("Scale"), 0, group_modes_ ); action->setData(QVariant(WbWidget::Scale)); action->setCheckable(true); action = new IconAction(tr( "Erase"), "psi/erase", tr("Erase"), 0, group_modes_ ); action->setData(QVariant(WbWidget::Erase)); action->setCheckable(true); QAction *separator = new QAction(group_modes_); separator->setSeparator(true); action = new IconAction(tr( "Scroll view"), "psi/scroll", tr("Scroll"), 0, group_modes_ ); action->setData(QVariant(WbWidget::Scroll)); action->setCheckable(true); separator = new QAction(group_modes_); separator->setSeparator(true); action = new IconAction(tr( "Draw paths"), "psi/drawPaths", tr("Draw paths"), 0, group_modes_ ); action->setData(QVariant(WbWidget::DrawPath)); action->setCheckable(true); action->trigger(); // action = new IconAction(tr( "Draw lines"), "psi/drawLines", tr("Draw lines"), 0, group_modes_ ); // action->setData(QVariant(WbWidget::DrawLine)); // action->setCheckable(true); // action = new IconAction(tr( "Draw ellipses"), "psi/drawEllipses", tr("Draw ellipses"), 0, group_modes_ ); // action->setData(QVariant(WbWidget::DrawEllipse)); // action->setCheckable(true); // action = new IconAction(tr( "Draw circles"), "psi/drawCircles", tr("Draw circles"), 0, group_modes_ ); // action->setData(QVariant(WbWidget::DrawCircle)); // action->setCheckable(true); // action = new IconAction(tr( "Draw rectangles"), "psi/drawRectangles", tr("Draw rectangles"), 0, group_modes_ ); // action->setData(QVariant(WbWidget::DrawRectangle)); // action->setCheckable(true); // action = new IconAction(tr( "Add text"), "psi/addText", tr("Add text"), 0, group_modes_ ); // action->setData(QVariant(WbWidget::DrawText)); // action->setCheckable(true); action = new IconAction(tr( "Add images"), "psi/addImage", tr("Add images"), 0, group_modes_ ); action->setData(QVariant(WbWidget::DrawImage)); action->setCheckable(true); menu_widths_ = new QMenu(this); menu_widths_->addActions(group_widths_->actions()); act_widths_->setMenu(menu_widths_); menu_modes_ = new QMenu(this); menu_modes_->addActions(group_modes_->actions()); act_modes_->setMenu(menu_modes_); toolbar_ = new QToolBar(tr("Whiteboard toolbar"), this); toolbar_->setIconSize(QSize(16,16)); toolbar_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); toolbar_->addAction(act_end_); toolbar_->addAction(act_clear_); toolbar_->addAction(act_save_); toolbar_->addAction(act_geometry_); toolbar_->addWidget(new StretchWidget(this)); toolbar_->addAction(act_fill_); toolbar_->addAction(act_color_); toolbar_->addAction(act_widths_); toolbar_->addAction(act_modes_); vb1->addWidget(toolbar_); // Context menu pm_settings_ = new QMenu(this); connect(pm_settings_, SIGNAL(aboutToShow()), SLOT(buildMenu())); X11WM_CLASS("whiteboard"); // set the Jid -> le_jid. le_jid_->setText(QString("%1 (session: %2)").arg(session->target().full()).arg(session->session())); le_jid_->setCursorPosition(0); le_jid_->setToolTip(session->target().full()); // update the widget icon #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/whiteboard").icon()); #endif setWindowOpacity(double(qMax(MINIMUM_OPACITY, PsiOptions::instance()->getOption("options.ui.chat.opacity").toInt())) / 100); resize(PsiOptions::instance()->getOption("options.ui.chat.size").toSize()); } WbDlg::~WbDlg() { // terminate the underlying SXE session session()->endSession(); emit sessionEnded(this); } SxeSession* WbDlg::session() const { return wbWidget_->session(); } bool WbDlg::allowEdits() const { return allowEdits_; } void WbDlg::setAllowEdits(bool a) { allowEdits_ = a; if(!allowEdits_) wbWidget_->setMode(WbWidget::Scroll); } void WbDlg::peerLeftSession(const Jid &peer) { le_jid_->setText(tr("%1 left (session: %2).").arg(peer.full()).arg(session()->session())); } void WbDlg::endSession() { if(sender() == act_end_) { int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to end the session?\nThe contents of the whiteboard will be lost."), tr("&Yes"), tr("&No")); if(n != 0) return; } setAttribute(Qt::WA_DeleteOnClose); close(); } void WbDlg::activated() { if(pending_ > 0) { pending_ = 0; updateCaption(); } doFlash(false); } void WbDlg::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Escape && !PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool()) close(); else if(e->key() == Qt::Key_W && e->state() & Qt::ControlButton && !PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool()) close(); else e->ignore(); } void WbDlg::closeEvent(QCloseEvent *e) { e->accept(); if(testAttribute(Qt::WA_DeleteOnClose)) return; if(keepOpen_) { int n = QMessageBox::information(this, tr("Warning"), tr("A new whiteboard message was just received.\nDo you still want to close the window?"), tr("&Yes"), tr("&No")); if(n != 0) { e->ignore(); return; } } // destroy the dialog if delChats is dcClose if(PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "instant") endSession(); else { if(PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "hour") setSelfDestruct(60); else if(PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "day") setSelfDestruct(60 * 24); } } void WbDlg::resizeEvent(QResizeEvent *e) { if (PsiOptions::instance()->getOption("options.ui.remember-window-sizes").toBool()) { PsiOptions::instance()->setOption("options.ui.chat.size", e->size()); } } void WbDlg::showEvent(QShowEvent *) { setSelfDestruct(0); } void WbDlg::changeEvent(QEvent *e) { if (e->type() == QEvent::ActivationChange && isActiveWindow()) { activated(); } e->ignore(); } void WbDlg::setStrokeColor() { QColor newColor = QColorDialog::getColor(); if(newColor.isValid()) { QPixmap pixmap(16, 16); pixmap.fill(newColor); act_color_->setIcon(QIcon(pixmap)); wbWidget_->setStrokeColor(newColor); } } void WbDlg::setFillColor() { QColor newColor = QColorDialog::getColor(); if(newColor.isValid()) { QPixmap pixmap(16, 16); pixmap.fill(newColor); act_fill_->setIcon(QIcon(pixmap)); wbWidget_->setFillColor(newColor); } } void WbDlg::setStrokeWidth(QAction *a) { wbWidget_->setStrokeWidth(a->data().toInt()); } void WbDlg::setMode(QAction *a) { if(allowEdits_) wbWidget_->setMode(WbWidget::Mode(a->data().toInt())); else wbWidget_->setMode(WbWidget::Scroll); } void WbDlg::setKeepOpenFalse() { keepOpen_ = false; } void WbDlg::buildMenu() { pm_settings_->clear(); pm_settings_->addAction(act_modes_); pm_settings_->addAction(act_widths_); pm_settings_->addAction(act_color_); pm_settings_->insertSeparator(); pm_settings_->addAction(act_save_); pm_settings_->addAction(act_clear_); pm_settings_->addAction(act_end_); } void WbDlg::setGeometry() { // TODO: make a proper dialog QSize size; bool ok; size.setWidth(QInputDialog::getInteger(this, tr("Set new width:"), tr("Width:"), static_cast<int>(wbWidget_->scene()->sceneRect().width()), 10, 100000, 10, &ok)); if(!ok) return; size.setHeight(QInputDialog::getInteger(this, tr("Set new height:"), tr("Height:"), static_cast<int>(wbWidget_->scene()->sceneRect().height()), 10, 100000, 10, &ok)); if(!ok) return; wbWidget_->setSize(size); } void WbDlg::save() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Whitebaord"), QDir::homePath(), tr("Scalable Vector Graphics (*.svg)")); fileName = fileName.trimmed(); if(!fileName.endsWith(".svg", Qt::CaseInsensitive)) fileName += ".svg"; QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream stream(&file); wbWidget_->session()->document().save(stream, 2); file.close(); } void WbDlg::contextMenuEvent(QContextMenuEvent * e) { pm_settings_->exec(QCursor::pos()); e->accept(); } void WbDlg::setSelfDestruct(int minutes) { if(minutes <= 0) { if(selfDestruct_) { delete selfDestruct_; selfDestruct_ = 0; } return; } if(!selfDestruct_) { selfDestruct_ = new QTimer(this); connect(selfDestruct_, SIGNAL(timeout()), SLOT(endSession())); } selfDestruct_->start(minutes * 60000); } void WbDlg::updateCaption() { QString cap = ""; if(pending_ > 0) { cap += "* "; if(pending_ > 1) cap += QString("[%1] ").arg(pending_); } cap += session()->target().full(); setWindowTitle(cap); } ������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbwidget.h���������������������������������������������������������������0000644�0001750�0001750�00000013626�11305557613�015753� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbwidget.h - a widget for processing and showing whiteboard * messages. * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBWIDGET_H #define WBWIDGET_H #include "../sxe/sxesession.h" #include "wbscene.h" #include "wbitem.h" #include "wbnewitem.h" #include <QSvgRenderer> #include <QWidget> #include <QGraphicsView> #include <QTimer> #include <QTime> #include <QFileDialog> /*! \brief The whiteboard widget. * Visualizes the whiteboard scene and provides different modes for editing and adding new elements. * Local edits to existing elements are handled by the elements themselves * as mouse events are passed on to them but new items are temporarily * added to the scene while being drawn and only when finished, added to * the WbScene. * * \sa WbScene * \sa WbDlg */ class WbWidget : public QGraphicsView { Q_OBJECT public: /*! \brief Mode * Indicates the mode the widget is in. */ enum Mode { Select, Translate, Rotate, Scale, Scroll, Erase, DrawPath, DrawLine, DrawRectangle, DrawEllipse, DrawCircle, DrawPolyline, DrawText, DrawImage }; /*! \brief Constructor * Constructs a new widget with \a session and parent \a parent. */ WbWidget(SxeSession* session, QWidget* parent = 0); /*! \brief Returns the session this widget is visualizing.*/ SxeSession* session(); /*! \brief Returns the mode this widget is in.*/ Mode mode(); /*! \brief Sets the mode which determines how to react to user interaction.*/ void setMode(Mode mode); /*! \brief Sets the size of the whiteboard.*/ void setSize(const QSize &s); /*! \brief Sets the stroke color of new items.*/ void setStrokeColor(const QColor &color); /*! \brief Sets the stroke color of new items.*/ void setFillColor(const QColor &color); /*! \brief Sets the stroke width of new items.*/ void setStrokeWidth(int width); /*! \brief Returns the size set by setSize().*/ virtual QSize sizeHint() const; public slots: /*! \brief Clears the whiteboard. */ void clear(); protected: /*! \brief Makes sure that area outside the whiteboard is not shown by zooming if necessary.*/ virtual void resizeEvent(QResizeEvent * event); /*! \brief Passes events to items as specified by the mode.*/ virtual void mousePressEvent(QMouseEvent * event); /*! \brief Passes events to items as specified by the mode.*/ virtual void mouseMoveEvent(QMouseEvent * event); /*! \brief Passes events to items as specified by the mode.*/ virtual void mouseReleaseEvent(QMouseEvent * event); private: /*! \brief Returns the item representing the node (if any).*/ WbItem* wbItem(const QDomNode &node); /*! \brief The SxeSession synchronizing the document.*/ SxeSession* session_; /*! \brief The WbScene used for visualizing the document.*/ WbScene* scene_; /*! \brief The user interaction mode the widget is in.*/ Mode mode_; /*! \brief The stroke color used for new items.*/ QColor strokeColor_; /*! \brief The fill color used for new items.*/ QColor fillColor_; /*! \brief The stroke width used for new items.*/ int strokeWidth_; /*! \brief A list of existing WbItems */ QList<WbItem*> items_; // /*! \brief A list of WbItems to be deleted. */ // QList<WbItem*> deletionQueue_; /*! \brief A list of QDomNode's that were added since last documentUpdated() signal received. */ QList<QDomNode> recentlyRelocatedNodes_; /*! \brief A list of WbItem's whose nodes don't have 'id' attributes. */ QList<WbItem*> idlessItems_; /*! \brief Pointer to a new item that is being drawn.*/ WbNewItem* newWbItem_; /*! \brief Boolean used to force adding a vertex to a path being drawn.*/ bool addVertex_; /*! \brief Timer used for forcing the addition of a new vertex.*/ QTimer* adding_; /*! \brief The primary renderer used for rendering the document.*/ QSvgRenderer renderer_; private slots: /*! \brief Tries to add 'id' attributes to nodes in deletionQueue_ if they still don't have them.*/ void handleDocumentUpdated(bool remote); /*! \brief Ensures that an item for the nodes in the inspection queue exist * iff they're children of the root <svg/>.*/ void inspectNodes(); /*! \brief Adds a node to the list of nodes that will be processed by inspectNodes() at next documentUpdated().*/ void queueNodeInspection(const QDomNode &node); /*! \brief Removes the item representing the node (if any). * Doesn't affect \a node. */ void removeWbItem(const QDomNode &node); /*! \brief Removes the item from the scene. * Doesn't affect the underlying node. */ void removeWbItem(WbItem *wbitem); /*! \brief Tries to add 'id' attributes to nodes in idlessItems_ if they still don't have them.*/ void addIds(); /*! \brief Adds the item associated with node to idlessItems_. */ void addToIdLess(const QDomElement &element); /*! \brief If node is an 'id' attribute node, adds the ownerElement to idlessItems_. */ void checkForRemovalOfId(QDomNode node); /*! \brief Checks if \a node is the 'viewBox' attribute of the <svg/> element. * If so, the scene size is adjusted accordingly. */ void checkForViewBoxChange(const QDomNode &node); // /*! \brief Deletes the WbItem's in the deletion queue. */ // void flushDeletionQueue(); /*! \brief Rerenders the contents of the document.*/ void rerender(); }; #endif ����������������������������������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbscene.h����������������������������������������������������������������0000644�0001750�0001750�00000005175�11305557613�015565� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbscene.h - an SVG whiteboard scene class * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBSCENE_H #define WBSCENE_H #include <QPointer> #include "wbitem.h" /*! \brief The scene class for whiteboard items. * Inherits QGraphicsScene. * * Processes remote whiteboard edits. * * This class also provides methods for queueing new edits and * emits a signal with the corresponding whiteboard element. * * \sa WbWidget * \sa WbItem */ class WbScene : public QGraphicsScene { Q_OBJECT public: /*! \brief Constructor * Constructs a new scene with parent \a parent. */ WbScene(SxeSession* session, QObject * parent = 0); /*! \brief Appends the item to a list of items whose "transform" attribute is to be regenerated.*/ void queueTransformationRegeneration(WbItem* item); /*! \brief Regenerate the SVG transformation matrices for items queued by queueTransformationRegeneration(WbItem* item) since last regeneration.*/ void regenerateTransformations(); /*! \brief Returns the coordinates of the center of all selected items. */ QPointF selectionCenter() const; public slots: /*! \brief Brings the selected items \a n levels forward. */ void bringForward(int n = 1); /*! \brief Brings the item to the top. */ void bringToFront(); /*! \brief Sends the selected items \a n levels backwards. */ void sendBackwards(int n = 1); /*! \brief Brings the item to the back. */ void sendToBack(); /*! \brief Groups the selected items.*/ void group(); /*! \brief Ungroups the selected item groups.*/ void ungroup(); private: /*! \brief Brings the selected items \a n levels forward. * If \a n < 0, the items are send \a n levels baskwards. * If \a toExtremum is true, the item is sent to the front/back. */ void bring(int n, bool toExtremum); SxeSession* session_; QList< QPointer<WbItem> > pendingTranformations_; QPointF selectionCenter_; }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbnewpath.h��������������������������������������������������������������0000644�0001750�0001750�00000002536�11305557613�016134� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbnewpath.h - a class used for representing a path on the whiteboard * while it's being drawn. * Copyright (C) 2008 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBNEWPATH_H #define WBNEWPATH_H #include "wbnewitem.h" class WbNewPath : public WbNewItem { public: WbNewPath(QGraphicsScene* s, QPointF startPos, int strokeWidth, const QColor &strokeColor, const QColor &fillColor); ~WbNewPath(); void parseCursorMove(QPointF newPos); QDomNode serializeToSvg(); protected: QGraphicsItem* graphicsItem(); private: QGraphicsPathItem graphicsitem_; QPointF* controlPoint_; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbnewimage.h�������������������������������������������������������������0000644�0001750�0001750�00000002374�11305557613�016262� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbnewimage.h - a class used for representing an image on the whiteboard * while it's being added. * Copyright (C) 2008 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBNEWIMAGE_H #define WBNEWIMAGE_H #include "wbnewitem.h" class WbNewImage : public WbNewItem { public: WbNewImage(QGraphicsScene* s, QPointF startPos, const QString &filename); void parseCursorMove(QPointF newPos); QDomNode serializeToSvg(); protected: QGraphicsItem* graphicsItem(); private: QGraphicsPixmapItem graphicsitem_; QString filename_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbnewimage.cpp�����������������������������������������������������������0000644�0001750�0001750�00000005060�11305557613�016610� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbnewimage.cpp - a class used for representing an image on the whiteboard * while it's being added. * Copyright (C) 2008 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "wbnewimage.h" #include "../sxe/sxesession.h" #include <QGraphicsScene> #include <QFile> WbNewImage::WbNewImage(QGraphicsScene* s, QPointF startPos, const QString &filename) : WbNewItem(s), graphicsitem_(QPixmap(filename)) { filename_ = filename; graphicsitem_.setZValue(std::numeric_limits<double>::max()); graphicsitem_.setPos(startPos); scene->addItem(&graphicsitem_); } QDomNode WbNewImage::serializeToSvg() { // TODO: Should we perhaps scale large images? if(graphicsitem_.pixmap().isNull()) return QDomNode(); QFile file(filename_); if (file.open(QIODevice::ReadOnly)) { QDomDocument d = QDomDocument(); QDomElement image = QDomDocument().createElement("image"); image.setAttribute("id", "e" + SxeSession::generateUUID()); image.setAttribute("x", graphicsitem_.x()); image.setAttribute("y", graphicsitem_.y()); image.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); image.setAttribute("xlink:href", QString("data:image/%1;base64,%2") .arg(filename_.mid(filename_.lastIndexOf(".") + 1).toLower()) .arg(file.readAll().toBase64().constData())); // QDomElement g = QDomDocument().createElement("g"); // g.setAttribute("id", "e" + SxeSession::generateUUID()); // g.appendChild(image); return image; } return QDomNode(); } void WbNewImage::parseCursorMove(QPointF newPos) { Q_UNUSED(newPos); } QGraphicsItem* WbNewImage::graphicsItem() { return &graphicsitem_; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/whiteboarding/wbnewitem.h��������������������������������������������������������������0000644�0001750�0001750�00000002336�11305557613�016134� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * wbnewitem.h - a class used for representing items on the whiteboard * while they're being drawn. * Copyright (C) 2008 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WBNEWITEM_H #define WBNEWITEM_H #include <QGraphicsItem> #include <QDomNode> class WbNewItem { public: WbNewItem(QGraphicsScene* s); virtual ~WbNewItem(); virtual void parseCursorMove(QPointF newPos) = 0; virtual QDomNode serializeToSvg(); protected: virtual QGraphicsItem* graphicsItem() = 0; QGraphicsScene* scene; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/alertable.h����������������������������������������������������������������������������0000644�0001750�0001750�00000002300�11305557613�013227� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * alertable.h - simplify alert icon plumbing * Copyright (C) 2006 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ALERTABLE_H #define ALERTABLE_H #include <QObject> class AlertIcon; class PsiIcon; class QIcon; class Alertable : public QObject { Q_OBJECT public: Alertable(QObject* parent = 0); ~Alertable(); bool alerting() const; QIcon currentAlertFrame() const; void setAlert(const PsiIcon* icon); private slots: virtual void alertFrameUpdated() = 0; private: AlertIcon* alert_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/adhoc_fileserver.h���������������������������������������������������������������������0000644�0001750�0001750�00000002434�11305557613�014610� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * adhoc_fileserver.h - Implementation of a personal file server using ad-hoc * commands * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHFILESERVER_H #define AHFILESERVER_H #include "adhoc.h" class AHFileServer : public AHCommandServer { public: AHFileServer(AHCServerManager* m) : AHCommandServer(m) { } virtual QString node() const { return QString("http://psi.affinix.com/commands/files"); } virtual bool isAllowed(const Jid&) const; virtual QString name() const { return QString("Send file"); } virtual AHCommand execute(const AHCommand& c, const Jid&); }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/mucaffiliationsproxymodel.cpp����������������������������������������������������������0000644�0001750�0001750�00000001053�11305557613�017133� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "mucaffiliationsproxymodel.h" MUCAffiliationsProxyModel::MUCAffiliationsProxyModel(QObject* parent) : QSortFilterProxyModel(parent) { sort(0, Qt::AscendingOrder); setDynamicSortFilter(true); } bool MUCAffiliationsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); if (!idx.isValid()) return false; if (!idx.parent().isValid()) return true; if (filterRegExp().indexIn(idx.data().toString()) >= 0) return true; return false; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pluginmanager.h������������������������������������������������������������������������0000644�0001750�0001750�00000003303�11305557613�014131� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * (c) 2006 Kevin Smith * (c) 2008 Maciej Niedzielski */ #ifndef PLUGINMANAGER_H #define PLUGINMANAGER_H #include <QtCore> #include <QList> #include <QMap> #include <QHash> #include <QDomElement> class QPluginLoader; class PsiAccount; class PsiPlugin; class PluginHost; namespace XMPP { class Client; } namespace QCA { class DirWatch; } class PluginManager : public QObject { Q_OBJECT; public: static PluginManager* instance(); QStringList availablePlugins(); void addAccount(const PsiAccount* account, XMPP::Client* client); void loadEnabledPlugins(); bool unloadAllPlugins(); QString pathToPlugin(const QString& plugin); QString shortName(const QString& plugin); QWidget* optionsWidget(const QString& plugin); bool processEvent(const PsiAccount* account, QDomElement& eventXml); bool processMessage(const PsiAccount* account, const QString& jidFrom, const QString& body, const QString& subject); static const QString loadOptionPrefix; static const QString pluginOptionPrefix; private: PluginManager(); void loadAllPlugins(); bool verifyStanza(const QString& stanza); void updatePluginsList(); static PluginManager* instance_; //account id, client QVector<XMPP::Client*> clients_; //account, account id QHash<const PsiAccount*, int> accountIds_; //name, host QHash<QString, PluginHost*> hosts_; //file, host QHash<QString, PluginHost*> pluginByFile_; QList<QCA::DirWatch*> dirWatchers_; class StreamWatcher; bool incomingXml(int account, const QDomElement &eventXml); void sendXml(int account, const QString& xml); QString uniqueId(int account); friend class PluginHost; private slots: void dirsChanged(); void optionChanged(const QString& option); }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/common.cpp�����������������������������������������������������������������������������0000644�0001750�0001750�00000031000�11305557613�013116� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * common.cpp - contains all the common variables and functions for Psi * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "common.h" #include "profiles.h" #include "rtparse.h" #include "psievent.h" #include "psiiconset.h" #include "applicationinfo.h" #include "psioptions.h" #include <QUrl> #include <QProcess> #include <QBoxLayout> #include <QRegExp> #include <QFile> #include <QApplication> #include <QSound> #include <QObject> #include <QMessageBox> #include <QUuid> #include <QDir> #include <stdio.h> #ifdef Q_WS_X11 #include <QX11Info> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #endif #ifdef Q_WS_WIN #include <windows.h> #endif #ifdef Q_WS_MAC #include <sys/types.h> #include <sys/stat.h> #include <Carbon/Carbon.h> // for HIToolbox/InternetConfig #include <CoreServices/CoreServices.h> #endif Qt::WFlags psi_dialog_flags = (Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); // used to be part of the global options struct. // FIXME find it a new home! int common_smallFontSize=0; bool useSound; QString CAP(const QString &str) { return QString("%1: %2").arg(ApplicationInfo::name()).arg(str); } // clips plain text QString clipStatus(const QString &str, int width, int height) { QString out = ""; int at = 0; int len = str.length(); if(len == 0) return out; // only take the first "height" lines for(int n2 = 0; n2 < height; ++n2) { // only take the first "width" chars QString line; bool hasNewline = false; for(int n = 0; at < len; ++n, ++at) { if(str.at(at) == '\n') { hasNewline = true; break; } line += str.at(at); } ++at; if((int)line.length() > width) { line.truncate(width-3); line += "..."; } out += line; if(hasNewline) out += '\n'; if(at >= len) break; } return out; } QString encodePassword(const QString &pass, const QString &key) { QString result; int n1, n2; if(key.length() == 0) return pass; for(n1 = 0, n2 = 0; n1 < pass.length(); ++n1) { ushort x = pass.at(n1).unicode() ^ key.at(n2++).unicode(); QString hex; hex.sprintf("%04x", x); result += hex; if(n2 >= key.length()) n2 = 0; } return result; } QString decodePassword(const QString &pass, const QString &key) { QString result; int n1, n2; if(key.length() == 0) return pass; for(n1 = 0, n2 = 0; n1 < pass.length(); n1 += 4) { ushort x = 0; if(n1 + 4 > pass.length()) break; x += QString(pass.at(n1)).toInt(NULL,16)*4096; x += QString(pass.at(n1+1)).toInt(NULL,16)*256; x += QString(pass.at(n1+2)).toInt(NULL,16)*16; x += QString(pass.at(n1+3)).toInt(NULL,16); QChar c(x ^ key.at(n2++).unicode()); result += c; if(n2 >= key.length()) n2 = 0; } return result; } QString status2txt(int status) { switch(status) { case STATUS_OFFLINE: return QObject::tr("Offline"); case STATUS_AWAY: return QObject::tr("Away"); case STATUS_XA: return QObject::tr("Not Available"); case STATUS_DND: return QObject::tr("Do not Disturb"); case STATUS_CHAT: return QObject::tr("Free for Chat"); case STATUS_INVISIBLE: return QObject::tr("Invisible"); case STATUS_ONLINE: default: return QObject::tr("Online"); } } QString logencode(QString str) { str.replace(QRegExp("\\\\"), "\\\\"); // backslash to double-backslash str.replace(QRegExp("\\|"), "\\p"); // pipe to \p str.replace(QRegExp("\n"), "\\n"); // newline to \n return str; } QString logdecode(const QString &str) { QString ret; for(int n = 0; n < str.length(); ++n) { if(str.at(n) == '\\') { ++n; if(n >= str.length()) break; if(str.at(n) == 'n') ret.append('\n'); if(str.at(n) == 'p') ret.append('|'); if(str.at(n) == '\\') ret.append('\\'); } else { ret.append(str.at(n)); } } return ret; } bool fileCopy(const QString &src, const QString &dest) { QFile in(src); QFile out(dest); if(!in.open(QIODevice::ReadOnly)) return false; if(!out.open(QIODevice::WriteOnly)) return false; char *dat = new char[16384]; int n = 0; while(!in.atEnd()) { n = in.read(dat, 16384); if(n == -1) { delete[] dat; return false; } out.write(dat, n); } delete[] dat; out.close(); in.close(); return true; } /** Detect default player helper on unix like systems */ QString soundDetectPlayer() { // prefer ALSA on linux if (QFile("/proc/asound").exists()) { return "aplay"; } // fallback to "play" return "play"; } void soundPlay(const QString &s) { QString str = s; if(str == "!beep") { QApplication::beep(); return; } if (QDir::isRelativePath(str)) { str = ApplicationInfo::resourcesDir() + '/' + str; } if(!QFile::exists(str)) return; #if defined(Q_WS_WIN) || defined(Q_WS_MAC) QSound::play(str); #else QString player = PsiOptions::instance()->getOption("options.ui.notifications.sounds.unix-sound-player").toString(); if (player == "") player = soundDetectPlayer(); QStringList args = player.split(' '); args += str; QString prog = args.takeFirst(); QProcess::startDetached(prog, args); #endif } XMPP::Status makeStatus(int x, const QString &str, int priority) { XMPP::Status s = makeStatus(x,str); if (priority > 127) s.setPriority(127); else if (priority < -128) s.setPriority(-128); else s.setPriority(priority); return s; } XMPP::Status makeStatus(int x, const QString &str) { return XMPP::Status(static_cast<XMPP::Status::Type>(x), str); } XMPP::Status::Type makeSTATUS(const XMPP::Status &s) { return s.type(); } #include <qlayout.h> QLayout *rw_recurseFindLayout(QLayout *lo, QWidget *w) { //printf("scanning layout: %p\n", lo); for (int index = 0; index < lo->count(); ++index) { QLayoutItem* i = lo->itemAt(index); //printf("found: %p,%p\n", i->layout(), i->widget()); QLayout *slo = i->layout(); if(slo) { QLayout *tlo = rw_recurseFindLayout(slo, w); if(tlo) return tlo; } else if(i->widget() == w) return lo; } return 0; } QLayout *rw_findLayoutOf(QWidget *w) { return rw_recurseFindLayout(w->parentWidget()->layout(), w); } void replaceWidget(QWidget *a, QWidget *b) { if(!a) return; QLayout *lo = rw_findLayoutOf(a); if(!lo) return; //printf("decided on this: %p\n", lo); if(lo->inherits("QBoxLayout")) { QBoxLayout *bo = (QBoxLayout *)lo; int n = bo->indexOf(a); bo->insertWidget(n+1, b); delete a; } } void closeDialogs(QWidget *w) { // close qmessagebox? QList<QDialog*> dialogs; QObjectList list = w->children(); for(QObjectList::Iterator it = list.begin() ; it != list.end(); ++it) { if((*it)->inherits("QDialog")) dialogs.append((QDialog *)(*it)); } for(QList<QDialog*>::Iterator w = dialogs.begin(); w != dialogs.end(); ++w) { (*w)->close(); } } #ifdef Q_WS_X11 #include <X11/Xlib.h> #include <X11/Xutil.h> // needed for WM_CLASS hinting void x11wmClass(Display *dsp, WId wid, QString resName) { char app_name[] = "psi"; //Display *dsp = x11Display(); // get the display //WId win = winId(); // get the window XClassHint classhint; // class hints const QByteArray latinResName = resName.toLatin1(); classhint.res_name = (char *)latinResName.data(); // res_name classhint.res_class = app_name; // res_class XSetClassHint(dsp, wid, &classhint); // set the class hints } //>>>-- Nathaniel Gray -- Caltech Computer Science ------> //>>>-- Mojave Project -- http://mojave.cs.caltech.edu --> // Copied from http://www.nedit.org/archives/discuss/2002-Aug/0386.html // Helper function bool getCardinal32Prop(Display *display, Window win, char *propName, long *value) { Atom nameAtom, typeAtom, actual_type_return; int actual_format_return, result; unsigned long nitems_return, bytes_after_return; long *result_array=NULL; nameAtom = XInternAtom(display, propName, False); typeAtom = XInternAtom(display, "CARDINAL", False); if (nameAtom == None || typeAtom == None) { //qDebug("Atoms not interned!"); return false; } // Try to get the property result = XGetWindowProperty(display, win, nameAtom, 0, 1, False, typeAtom, &actual_type_return, &actual_format_return, &nitems_return, &bytes_after_return, (unsigned char **)&result_array); if( result != Success ) { //qDebug("not Success"); return false; } if( actual_type_return == None || actual_format_return == 0 ) { //qDebug("Prop not found"); return false; } if( actual_type_return != typeAtom ) { //qDebug("Wrong type atom"); } *value = result_array[0]; XFree(result_array); return true; } // Get the desktop number that a window is on bool desktopOfWindow(Window *window, long *desktop) { Display *display = QX11Info::display(); bool result = getCardinal32Prop(display, *window, (char *)"_NET_WM_DESKTOP", desktop); //if( result ) // qDebug("Desktop: " + QString::number(*desktop)); return result; } // Get the current desktop the WM is displaying bool currentDesktop(long *desktop) { Window rootWin; Display *display = QX11Info::display(); bool result; rootWin = RootWindow(QX11Info::display(), XDefaultScreen(QX11Info::display())); result = getCardinal32Prop(display, rootWin, (char *)"_NET_CURRENT_DESKTOP", desktop); //if( result ) // qDebug("Current Desktop: " + QString::number(*desktop)); return result; } #endif void bringToFront(QWidget *widget, bool) { Q_ASSERT(widget); QWidget* w = widget->window(); #ifdef Q_WS_X11 // If we're not on the current desktop, do the hide/show trick long dsk, curr_dsk; Window win = w->winId(); if(desktopOfWindow(&win, &dsk) && currentDesktop(&curr_dsk)) { //qDebug() << "bringToFront current desktop=" << curr_dsk << " windowDesktop=" << dsk; if((dsk != curr_dsk) && (dsk != -1)) { // second condition for sticky windows w->hide(); } } // FIXME: multi-desktop hacks for Win and Mac required #endif if(w->isMaximized()) w->showMaximized(); else w->showNormal(); //if(grabFocus) // w->setActiveWindow(); w->raise(); w->activateWindow(); } bool operator!=(const QMap<QString, QString> &m1, const QMap<QString, QString> &m2) { if ( m1.size() != m2.size() ) return true; QMap<QString, QString>::ConstIterator it = m1.begin(), it2; for ( ; it != m1.end(); ++it) { it2 = m2.find( it.key() ); if ( it2 == m2.end() ) return true; if ( it.value() != it2.value() ) return true; } return false; } //---------------------------------------------------------------------------- // ToolbarPrefs //---------------------------------------------------------------------------- ToolbarPrefs::ToolbarPrefs() : dock(Qt3Dock_Top) // , dirty(true) , on(false) , locked(false) // , stretchable(false) // , index(0) , nl(true) // , extraOffset(0) { id = QUuid::createUuid().toString(); } bool ToolbarPrefs::operator==(const ToolbarPrefs& other) { return id == other.id && name == other.name && keys == other.keys && dock == other.dock && // dirty == other.dirty && on == other.on && locked == other.locked && // stretchable == other.stretchable && // index == other.index && nl == other.nl; // extraOffset == other.extraOffset; } int versionStringToInt(const char* version) { QString str = QString::fromLatin1(version); QStringList parts = str.split('.', QString::KeepEmptyParts); if (parts.count() != 3) { return 0; } int versionInt = 0; for (int n = 0; n < 3; ++n) { bool ok; int x = parts[n].toInt(&ok); if (ok && x >= 0 && x <= 0xff) { versionInt <<= 8; versionInt += x; } else { return 0; } } return versionInt; } int qVersionInt() { static int out = -1; if (out == -1) { out = versionStringToInt(qVersion()); } return out; } psi-0.14/src/aboutdlg.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000013014�11305557613�013434� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * aboutdlg.cpp * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QTextStream> #include <QFile> #include <QtCrypto> #include "applicationinfo.h" #include "aboutdlg.h" AboutDlg::AboutDlg(QWidget* parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); setModal(false); ui_.lb_name->setText ( QString("<h3><b>%1 v%2</b></h3>").arg(ApplicationInfo::name()).arg(ApplicationInfo::version()) ); ui_.te_license->setText ( loadText(":/COPYING") ); QString lang_name = qApp->translate( "@default", "language_name" ); if ( lang_name == "language_name" ) // remove the translation tab, if no translation is used ui_.tw_tabs->removeTab ( 3 ); // fill in Authors tab... QString authors; authors += details(QString::fromUtf8("Justin Karneges"), "justin@affinix.com", "", "", tr("Current Maintainer and Original Author")); authors += details(QString::fromUtf8("Kevin Smith"), "kismith@psi-im.org", "", "", tr("Lead Developer and Past Maintainer")); authors += details(QString::fromUtf8("Remko Tronçon"), "", "", "http://el-tramo.be", tr("Lead Developer")); authors += details(QString::fromUtf8("Michail Pishchagin"), "mblsha@psi-im.org", "", "", tr("Lead Widget Developer")); authors += details(QString::fromUtf8("Maciej Niedzielski"), "machekku@psi-im.org", "", "", tr("Developer")); authors += details(QString::fromUtf8("Martin Hostettler"), "martin@psi-im.org", "", "", tr("Developer")); ui_.te_authors->setText( authors ); // fill in Thanks To tab... QString thanks; thanks += details(QString::fromUtf8("Frederik Schwarzer"), "schwarzerf@gmail.com", "", "", tr("Language coordinator, miscellaneous assistance")); thanks += details(QString::fromUtf8("Akito Nozaki"), "anpluto@usa.net", "", "", tr("Former language coordinator, miscellaneous assistance")); thanks += details(QString::fromUtf8("Jan Niehusmann"), "jan@gondor.com", "", "", tr("Build setup, miscellaneous assistance")); thanks += details(QString::fromUtf8("Everaldo Coelho"), "", "", "http://www.everaldo.com", tr("Many icons are from his Crystal icon theme")); thanks += details(QString::fromUtf8("Jason Kim"), "", "", "", tr("Graphics")); thanks += details(QString::fromUtf8("Hideaki Omuro"), "", "", "", tr("Graphics")); thanks += details(QString::fromUtf8("Bill Myers"), "", "", "", tr("Original Mac Port")); thanks += details(QString::fromUtf8("Eric Smith (Tarkvara Design, Inc.)"), "eric@tarkvara.org", "", "", tr("Mac OS X Port")); thanks += details(QString::fromUtf8("Tony Collins"), "", "", "", tr("Original End User Documentation")); thanks += details(QString::fromUtf8("Hal Rottenberg"), "", "", "", tr("Webmaster, Marketing")); thanks += details(QString::fromUtf8("Mircea Bardac"), "", "", "", tr("Bug Tracker Management")); thanks += details(QString::fromUtf8("Jacek Tomasiak"), "", "", "", tr("Patches")); foreach(QCA::Provider *p, QCA::providers()) { QString credit = p->credit(); if(!credit.isEmpty()) { thanks += details(tr("Security plugin: %1").arg(p->name()), "", "", "", credit); } } //thanks += tr("Thanks to many others.\n" // "The above list only reflects the contributors I managed to keep track of.\n" // "If you're not included but you think that you must be in the list, contact the developers."); ui_.te_thanks->setText( thanks ); QString translation = tr( "I. M. Anonymous <note text=\"replace with your real name\"><br>\n" "  <a href=\"http://me.com\">http://me.com</a><br>\n" "  Jabber: <a href=\"xmpp:me@me.com\">me@me.com</a><br>\n" "  <a href=\"mailto:me@me.com\">me@me.com</a><br>\n" "  Translator<br>\n" "<br>\n" "Join the translation team today! Go to \n" "<a href=\"http://forum.psi-im.org/forum/14\">\n" "http://forum.psi-im.org/forum/14</a> for further details!" ); ui_.te_translation->appendText(translation); } QString AboutDlg::loadText( const QString & fileName ) { QString text; QFile f(fileName); if(f.open(QIODevice::ReadOnly)) { QTextStream t(&f); while(!t.atEnd()) text += t.readLine() + '\n'; f.close(); } return text; } QString AboutDlg::details( QString name, QString email, QString jabber, QString www, QString desc ) { QString ret; const QString nbsp = "  "; ret += name + "<br>\n"; if ( !email.isEmpty() ) ret += nbsp + "E-mail: " + "<a href=\"mailto:" + email + "\">" + email + "</a><br>\n"; if ( !jabber.isEmpty() ) ret += nbsp + "Jabber: " + "<a href=\"jabber:" + jabber + "\">" + jabber + "</a><br>\n"; if ( !www.isEmpty() ) ret += nbsp + "WWW: " + "<a href=\"" + www + "\">" + www + "</a><br>\n"; if ( !desc.isEmpty() ) ret += nbsp + desc + "<br>\n"; ret += "<br>\n"; return ret; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/contactview.cpp������������������������������������������������������������������������0000644�0001750�0001750�00000272707�11305557613�014201� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * contactview.cpp - contact list widget * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "contactview.h" #include <QFileDialog> #include <qapplication.h> #include <q3ptrlist.h> #include <q3header.h> #include <qtimer.h> #include <qpainter.h> #include <q3popupmenu.h> #include <qmessagebox.h> #include <qinputdialog.h> #include <qicon.h> #include <q3dragobject.h> #include <qlayout.h> #include <QKeyEvent> #include <QEvent> #include <QList> #include <QDropEvent> #include <QPixmap> #include <QDesktopWidget> #include <stdlib.h> #include "common.h" #include "userlist.h" #include "psiaccount.h" #include "psicon.h" #include "jidutil.h" #include "psioptions.h" #include "iconaction.h" #include "pgputil.h" #include "alerticon.h" #include "avatars.h" #include "psiiconset.h" #include "serverinfomanager.h" #include "pepmanager.h" #include "psitooltip.h" #include "capsmanager.h" #include "resourcemenu.h" #include "shortcutmanager.h" #include "xmpp_message.h" #include "textutil.h" #include "bookmarkmanagedlg.h" #include "bookmarkmanager.h" static inline int rankStatus(int status) { switch (status) { case STATUS_CHAT : return 0; case STATUS_ONLINE : return 1; case STATUS_AWAY : return 2; case STATUS_XA : return 3; case STATUS_DND : return 4; case STATUS_INVISIBLE: return 5; default: return 6; } return 0; } static bool caseInsensitiveLessThan(const QString &s1, const QString &s2) { return s1.toLower() < s2.toLower(); } //---------------------------------------------------------------------------- // ContactProfile //---------------------------------------------------------------------------- class ContactProfile::Entry { public: Entry() { alerting = false; cvi.setAutoDelete(true); } ~Entry() { } UserListItem u; Q3PtrList<ContactViewItem> cvi; bool alerting; PsiIcon anim; }; class ContactProfile::Private : public QObject { Q_OBJECT public: Private() {} QString name; ContactView *cv; ContactViewItem *cvi; ContactViewItem *self; UserListItem su; Q3PtrList<Entry> roster; Q3PtrList<ContactViewItem> groups; int oldstate; QTimer *t; PsiAccount *pa; bool v_enabled; public slots: /* * \brief This slot is toggled when number of active accounts is changed * * At the moment, it tries to recalculate the roster size. */ void numAccountsChanged() { cv->recalculateSize(); } }; ContactProfile::ContactProfile(PsiAccount *pa, const QString &name, ContactView *cv, bool unique) { d = new Private; d->pa = pa; d->v_enabled = d->pa->enabled(); d->name = name; d->cv = cv; d->cv->link(this); d->t = new QTimer; connect(d->t, SIGNAL(timeout()), SLOT(updateGroups())); connect(pa->psi(), SIGNAL(accountCountChanged()), d, SLOT(numAccountsChanged())); d->roster.setAutoDelete(true); d->self = 0; if (!unique) { d->cvi = new ContactViewItem(name, this, d->cv); } else { d->cvi = 0; } d->oldstate = -2; deferredUpdateGroups(); } ContactProfile::~ContactProfile() { // delete the roster clear(); // clean up delete d->self; delete d->cvi; delete d->t; d->cv->unlink(this); delete d; } void ContactProfile::setEnabled(bool e) { d->v_enabled = e; if(d->v_enabled){ if(!d->cvi) d->cvi = new ContactViewItem(d->name, this, d->cv); addAllNeededContactItems(); } else{ if(d->self) removeSelf(); removeAllUnneededContactItems(); if(d->cvi) delete d->cvi; d->cvi = 0; d->self = 0; } } ContactView *ContactProfile::contactView() const { return d->cv; } ContactViewItem *ContactProfile::self() const { return d->self; } PsiAccount *ContactProfile::psiAccount() const { return d->pa; } const QString & ContactProfile::name() const { return d->name; } void ContactProfile::setName(const QString &name) { d->name = name; if (d->cvi) { d->cvi->setProfileName(name); } } void ContactProfile::setName(const char *s) { QObject::setName(s); } void ContactProfile::setState(int state) { if(state == d->oldstate) return; d->oldstate = state; if(d->cvi) { d->cv->resetAnim(); d->cvi->setProfileState(state); } } void ContactProfile::setUsingSSL(bool on) { if(d->cvi) d->cvi->setProfileSSL(on); } ContactViewItem *ContactProfile::addGroup(int type) { ContactViewItem *item; QString gname; if(type == ContactViewItem::gGeneral) gname = tr("General"); else if(type == ContactViewItem::gNotInList) gname = tr("Not in list"); else if(type == ContactViewItem::gAgents) gname = tr("Agents/Transports"); else if(type == ContactViewItem::gPrivate) gname = tr("Private Messages"); if(d->cvi) item = new ContactViewItem(gname, type, this, d->cvi); else item = new ContactViewItem(gname, type, this, d->cv); d->groups.append(item); return item; } ContactViewItem *ContactProfile::addGroup(const QString &name) { ContactViewItem *item; if(d->cvi) item = new ContactViewItem(name, ContactViewItem::gUser, this, d->cvi); else item = new ContactViewItem(name, ContactViewItem::gUser, this, d->cv); d->groups.append(item); return item; } // check for special group ContactViewItem *ContactProfile::checkGroup(int type) { ContactViewItem *item; if(d->cvi) item = (ContactViewItem *)d->cvi->firstChild(); else item = (ContactViewItem *)d->cv->firstChild(); for(; item; item = (ContactViewItem *)item->nextSibling()) { if(item->type() == ContactViewItem::Group && item->groupType() == type) return item; } return 0; } // make a tooltip with account information QString ContactProfile::makeTip(bool trim, bool doLinkify) const { if (d->cvi) return "<qt> <center> <b>" + d->cvi->text(0) + " " + d->cvi->groupInfo() + "</b> </center> " + d->su.makeBareTip(trim,doLinkify) + "</qt>"; else return d->su.makeTip(trim,doLinkify); } // check for user group ContactViewItem *ContactProfile::checkGroup(const QString &name) { ContactViewItem *item; if(d->cvi) item = (ContactViewItem *)d->cvi->firstChild(); else item = (ContactViewItem *)d->cv->firstChild(); for(; item; item = (ContactViewItem *)item->nextSibling()) { if(item->type() == ContactViewItem::Group && item->groupType() == ContactViewItem::gUser && item->groupName() == name) return item; } return 0; } ContactViewItem *ContactProfile::ensureGroup(int type) { ContactViewItem *group_item = checkGroup(type); if(!group_item) group_item = addGroup(type); return group_item; } ContactViewItem *ContactProfile::ensureGroup(const QString &name) { ContactViewItem *group_item = checkGroup(name); if(!group_item) group_item = addGroup(name); return group_item; } void ContactProfile::checkDestroyGroup(const QString &group) { ContactViewItem *group_item = checkGroup(group); if(group_item) checkDestroyGroup(group_item); } void ContactProfile::checkDestroyGroup(ContactViewItem *group) { if(group->childCount() == 0) { d->groups.remove(group); delete group; } } void ContactProfile::updateEntry(const UserListItem &u) { if (u.isSelf()) { // Update the self item d->su = u; // Show and/or update item if necessary if (d->cv->isShowSelf() || d->su.userResourceList().count() > 1) { if (d->self) { updateSelf(); } else { addSelf(); } } else { removeSelf(); } } else { Entry *e = findEntry(u.jid()); if(!e) { e = new Entry; d->roster.append(e); e->u = u; } else { e->u = u; removeUnneededContactItems(e); // update remaining items Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current()); ++it) { i->setContact(&e->u); if(!u.isAvailable()) i->stopAnimateNick(); } } deferredUpdateGroups(); addNeededContactItems(e); } } void ContactProfile::updateSelf() { if (d->self) { d->self->setContact(&d->su); if(!d->su.isAvailable()) d->self->stopAnimateNick(); } } void ContactProfile::addSelf() { if(!d->self) { if(!d->cvi) return; d->self = new ContactViewItem(&d->su, this, d->cvi); } } void ContactProfile::removeSelf() { if (d->self) { delete d->self; d->self = 0; } } ContactViewItem *ContactProfile::addContactItem(Entry *e, ContactViewItem *group_item) { ContactViewItem *i = new ContactViewItem(&e->u, this, group_item); e->cvi.append(i); if(e->alerting) i->setAlert(&e->anim); deferredUpdateGroups(); //printf("ContactProfile: adding [%s] to group [%s]\n", e->u.jid().full().latin1(), group_item->groupName().latin1()); return i; } /* * \brief Ensures that specified Entry is present in contactlist * * \param e - Entry with the necessary data about item * \param group_item - ContactViewItem that will be the group for this item */ ContactViewItem *ContactProfile::ensureContactItem(Entry *e, ContactViewItem *group_item) { d->cv->recalculateSize(); Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current()); ++it) { ContactViewItem *g = (ContactViewItem *)static_cast<Q3ListViewItem *>(i)->parent(); if(g == group_item) return i; } return addContactItem(e, group_item); } /* * \brief Removes specified item from ContactView * * \param e - Entry with item's data * \param i - ContactViewItem corresponding to the e */ void ContactProfile::removeContactItem(Entry *e, ContactViewItem *i) { d->cv->recalculateSize(); ContactViewItem *group_item = (ContactViewItem *)static_cast<Q3ListViewItem *>(i)->parent(); //printf("ContactProfile: removing [%s] from group [%s]\n", e->u.jid().full().latin1(), group_item->groupName().latin1()); e->cvi.removeRef(i); deferredUpdateGroups(); checkDestroyGroup(group_item); } void ContactProfile::addNeededContactItems(Entry *e) { if(!d->v_enabled) return; const UserListItem &u = e->u; if(u.inList()) { // don't add if we're not supposed to see it if(u.isTransport()) { if(!d->cv->isShowAgents() && !e->alerting) { return; } } else { if(!e->alerting) { if((!d->cv->isShowOffline() && !u.isAvailable()) || (!d->cv->isShowAway() && u.isAway()) || (!d->cv->isShowHidden() && u.isHidden())) return; } } } if(u.isPrivate()) ensureContactItem(e, ensureGroup(ContactViewItem::gPrivate)); else if(!u.inList()) ensureContactItem(e, ensureGroup(ContactViewItem::gNotInList)); else if(u.isTransport()) { ensureContactItem(e, ensureGroup(ContactViewItem::gAgents)); } else if(u.groups().isEmpty()) ensureContactItem(e, ensureGroup(ContactViewItem::gGeneral)); else { const QStringList &groups = u.groups(); for(QStringList::ConstIterator git = groups.begin(); git != groups.end(); ++git) ensureContactItem(e, ensureGroup(*git)); } } void ContactProfile::removeUnneededContactItems(Entry *e) { const UserListItem &u = e->u; if(u.inList()) { bool delAll = !d->v_enabled; if(u.isTransport()) { if(!d->cv->isShowAgents() && !e->alerting) { delAll = true; } } else { if(!e->alerting) { if((!d->cv->isShowOffline() && !u.isAvailable()) || (!d->cv->isShowAway() && u.isAway()) || (!d->cv->isShowHidden() && u.isHidden())) delAll = true; } } if(delAll) { clearContactItems(e); return; } } Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current());) { bool del = false; ContactViewItem *g = (ContactViewItem *)static_cast<Q3ListViewItem *>(i)->parent(); if(g->groupType() == ContactViewItem::gNotInList && u.inList()) del = true; else if(g->groupType() != ContactViewItem::gNotInList && g->groupType() != ContactViewItem::gPrivate && !u.inList()) del = true; else if(g->groupType() == ContactViewItem::gAgents && !u.isTransport()) del = true; else if(g->groupType() != ContactViewItem::gAgents && u.isTransport()) del = true; else if(g->groupType() == ContactViewItem::gGeneral && !u.groups().isEmpty()) del = true; else if(g->groupType() != ContactViewItem::gPrivate && g->groupType() != ContactViewItem::gGeneral && u.groups().isEmpty() && !u.isTransport() && u.inList()) del = true; else if(g->groupType() == ContactViewItem::gUser) { const QStringList &groups = u.groups(); if(!groups.isEmpty()) { bool found = false; for(QStringList::ConstIterator git = groups.begin(); git != groups.end(); ++git) { if(g->groupName() == *git) { found = true; break; } } if(!found) del = true; } } else if(PsiOptions::instance()->getOption("options.ui.contactlist.auto-delete-unlisted").toBool() && !e->alerting && (g->groupType() == ContactViewItem::gPrivate || g->groupType() == ContactViewItem::gNotInList)) { del = true; } if(del) { removeContactItem(e, i); } else ++it; } } void ContactProfile::clearContactItems(Entry *e) { Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current());) removeContactItem(e, i); } void ContactProfile::addAllNeededContactItems() { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) addNeededContactItems(e); } void ContactProfile::removeAllUnneededContactItems() { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) removeUnneededContactItems(e); } void ContactProfile::resetAllContactItemNames() { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { Q3PtrListIterator<ContactViewItem> cvi_it(e->cvi); for(ContactViewItem *i; (i = cvi_it.current()); ++cvi_it) { i->resetName(); contactView()->filterContact(i); } } } void ContactProfile::removeEntry(const Jid &j) { Entry *e = findEntry(j); if(e) removeEntry(e); } void ContactProfile::removeEntry(Entry *e) { e->alerting = false; clearContactItems(e); d->roster.remove(e); } void ContactProfile::setAlert(const Jid &j, const PsiIcon *anim) { if(d->su.jid().compare(j)) { if(d->self) d->self->setAlert(anim); } else { Entry *e = findEntry(j); if(!e) return; e->alerting = true; e->anim = *anim; addNeededContactItems(e); Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current()); ++it) i->setAlert(anim); if(PsiOptions::instance()->getOption("options.ui.contactlist.ensure-contact-visible-on-event").toBool()) ensureVisible(e); } } void ContactProfile::clearAlert(const Jid &j) { if(d->su.jid().compare(j)) { if(d->self) d->self->clearAlert(); } else { Entry *e = findEntry(j); if(!e) return; e->alerting = false; Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current()); ++it) i->clearAlert(); removeUnneededContactItems(e); } } void ContactProfile::clear() { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current());) removeEntry(e); } ContactProfile::Entry *ContactProfile::findEntry(const Jid &jid) const { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { if(e->u.jid().compare(jid)) return e; } return 0; } ContactProfile::Entry *ContactProfile::findEntry(ContactViewItem *i) const { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { Q3PtrListIterator<ContactViewItem> ci(e->cvi); for(ContactViewItem *cvi; (cvi = ci.current()); ++ci) { if(cvi == i) return e; } } return 0; } // return a list of contacts from a CVI group QList<XMPP::Jid> ContactProfile::contactListFromCVGroup(ContactViewItem *group) const { QList<XMPP::Jid> list; for(ContactViewItem *item = (ContactViewItem *)group->firstChild(); item ; item = (ContactViewItem *)item->nextSibling()) { if(item->type() != ContactViewItem::Contact) continue; list.append(item->u()->jid()); } return list; } // return the number of contacts from a CVI group int ContactProfile::contactSizeFromCVGroup(ContactViewItem *group) const { int total = 0; for(ContactViewItem *item = (ContactViewItem *)group->firstChild(); item ; item = (ContactViewItem *)item->nextSibling()) { if(item->type() != ContactViewItem::Contact) continue; ++total; } return total; } // return the number of contacts from a CVI group int ContactProfile::contactsOnlineFromCVGroup(ContactViewItem *group) const { int total = 0; for(ContactViewItem *item = (ContactViewItem *)group->firstChild(); item ; item = (ContactViewItem *)item->nextSibling()) { if(item->type() == ContactViewItem::Contact && item->u()->isAvailable()) ++total; } return total; } // return a list of contacts associated with "groupName" QList<XMPP::Jid> ContactProfile::contactListFromGroup(const QString &groupName) const { QList<XMPP::Jid> list; Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { const UserListItem &u = e->u; if(u.isTransport()) continue; const QStringList &g = u.groups(); if(g.isEmpty()) { if(groupName.isEmpty()) list.append(u.jid()); } else { for(QStringList::ConstIterator git = g.begin(); git != g.end(); ++git) { if(*git == groupName) { list.append(u.jid()); break; } } } } return list; } // return the number of contacts associated with "groupName" int ContactProfile::contactSizeFromGroup(const QString &groupName) const { int total = 0; Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { const UserListItem &u = e->u; if(u.isTransport()) continue; const QStringList &g = u.groups(); if(g.isEmpty()) { if(groupName.isEmpty()) ++total; } else { for(QStringList::ConstIterator git = g.begin(); git != g.end(); ++git) { if(*git == groupName) { ++total; break; } } } } return total; } void ContactProfile::updateGroupInfo(ContactViewItem *group) { int type = group->groupType(); if(type == ContactViewItem::gGeneral || type == ContactViewItem::gAgents || type == ContactViewItem::gPrivate || type == ContactViewItem::gUser) { int online = contactsOnlineFromCVGroup(group); int total; if(type == ContactViewItem::gGeneral || type == ContactViewItem::gUser) { QString gname; if(type == ContactViewItem::gUser) gname = group->groupName(); else gname = ""; total = contactSizeFromGroup(gname); } else { total = group->childCount(); } if (PsiOptions::instance()->getOption("options.ui.contactlist.show-group-counts").toBool()) group->setGroupInfo(QString("(%1/%2)").arg(online).arg(total)); } else if (PsiOptions::instance()->getOption("options.ui.contactlist.show-group-counts").toBool()) { int inGroup = contactSizeFromCVGroup(group); group->setGroupInfo(QString("(%1)").arg(inGroup)); } } QStringList ContactProfile::groupList() const { QStringList groupList; Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { foreach(QString group, e->u.groups()) { if (!groupList.contains(group)) groupList.append(group); } } groupList.sort(); return groupList; } void ContactProfile::animateNick(const Jid &j) { if(d->su.jid().compare(j)) { if(d->self) d->self->setAnimateNick(); } Entry *e = findEntry(j); if(!e) return; Q3PtrListIterator<ContactViewItem> it(e->cvi); for(ContactViewItem *i; (i = it.current()); ++it) i->setAnimateNick(); } void ContactProfile::deferredUpdateGroups() { d->t->start(250, true); } void ContactProfile::updateGroups() { int totalOnline = 0; { Q3PtrListIterator<Entry> it(d->roster); for(Entry *e; (e = it.current()); ++it) { if(e->u.isAvailable()) ++totalOnline; } if(d->cvi && PsiOptions::instance()->getOption("options.ui.contactlist.show-group-counts").toBool()) d->cvi->setGroupInfo(QString("(%1/%2)").arg(totalOnline).arg(d->roster.count())); } { Q3PtrListIterator<ContactViewItem> it(d->groups); for(ContactViewItem *g; (g = it.current()); ++it) { updateGroupInfo(g); contactView()->filterGroup(g); } } } void ContactProfile::ensureVisible(const Jid &j) { Entry *e = findEntry(j); if(!e) return; ensureVisible(e); } void ContactProfile::ensureVisible(Entry *e) { if(!e->alerting) { if(!d->cv->isShowAgents() && e->u.isTransport()) d->cv->setShowAgents(true); if(!d->cv->isShowOffline() && !e->u.isAvailable()) d->cv->setShowOffline(true); if(!d->cv->isShowAway() && e->u.isAway()) d->cv->setShowAway(true); if(!d->cv->isShowHidden() && e->u.isHidden()) d->cv->setShowHidden(true); } ContactViewItem *i = e->cvi.first(); if(!i) return; d->cv->ensureItemVisible(i); } void ContactProfile::doContextMenu(ContactViewItem *i, const QPoint &pos) { bool online = d->pa->loggedIn(); if(i->type() == ContactViewItem::Profile) { Q3PopupMenu pm; Q3PopupMenu *am = new Q3PopupMenu(&pm); am->insertItem(IconsetFactory::icon("psi/disco").icon(), tr("Online Users"), 5); am->insertItem(IconsetFactory::icon("psi/sendMessage").icon(), tr("Send Server Message"), 1); am->insertSeparator(); am->insertItem(/*IconsetFactory::iconPixmap("psi/edit"),*/ tr("Set MOTD"), 2); am->insertItem(/*IconsetFactory::iconPixmap("psi/edit/clear"),*/ tr("Update MOTD"), 3); am->insertItem(IconsetFactory::icon("psi/remove").icon(), tr("Delete MOTD"), 4); const int status_start = 15; Q3PopupMenu *sm = new Q3PopupMenu(&pm); sm->insertItem(PsiIconset::instance()->status(STATUS_ONLINE).icon(), status2txt(STATUS_ONLINE), STATUS_ONLINE + status_start); if (PsiOptions::instance()->getOption("options.ui.menu.status.chat").toBool()) sm->insertItem(PsiIconset::instance()->status(STATUS_CHAT).icon(), status2txt(STATUS_CHAT), STATUS_CHAT + status_start); sm->insertSeparator(); sm->insertItem(PsiIconset::instance()->status(STATUS_AWAY).icon(), status2txt(STATUS_AWAY), STATUS_AWAY + status_start); if (PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()) sm->insertItem(PsiIconset::instance()->status(STATUS_XA).icon(), status2txt(STATUS_XA), STATUS_XA + status_start); sm->insertItem(PsiIconset::instance()->status(STATUS_DND).icon(), status2txt(STATUS_DND), STATUS_DND + status_start); if (PsiOptions::instance()->getOption("options.ui.menu.status.invisible").toBool()) { sm->insertSeparator(); sm->insertItem(PsiIconset::instance()->status(STATUS_INVISIBLE).icon(), status2txt(STATUS_INVISIBLE), STATUS_INVISIBLE + status_start); } sm->insertSeparator(); sm->insertItem(PsiIconset::instance()->status(STATUS_OFFLINE).icon(), status2txt(STATUS_OFFLINE), STATUS_OFFLINE + status_start); pm.insertItem(tr("&Status"), sm); #ifdef USE_PEP pm.insertItem(tr("Mood"), 11); pm.setItemEnabled(11, d->pa->serverInfoManager()->hasPEP()); Q3PopupMenu *avatarm = new Q3PopupMenu (&pm); avatarm->insertItem(tr("Set Avatar"), 12); avatarm->insertItem(tr("Unset Avatar"), 13); pm.insertItem(tr("Avatar"), avatarm, 14); pm.setItemEnabled(14, d->pa->serverInfoManager()->hasPEP()); #endif const int bookmarks_start = STATUS_CHAT + status_start + 1; // STATUS_CHAT is the highest value of the states QMenu *bookmarks = new QMenu(&pm); bookmarks->insertItem(tr("Manage..."), bookmarks_start); if (d->pa->bookmarkManager()->isAvailable()) { int idx = 1; bookmarks->insertSeparator(); foreach(ConferenceBookmark c, psiAccount()->bookmarkManager()->conferences()) { bookmarks->insertItem(QString(tr("Join %1")).arg(c.name()), bookmarks_start + idx); idx++; } } else { bookmarks->setEnabled(false); } pm.insertItem(tr("Bookmarks"), bookmarks); pm.insertSeparator(); pm.insertItem(IconsetFactory::icon("psi/addContact").icon(), tr("&Add a Contact"), 7); pm.insertItem(IconsetFactory::icon("psi/disco").icon(), tr("Service &Discovery"), 9); if (PsiOptions::instance()->getOption("options.ui.message.enabled").toBool()) pm.insertItem(IconsetFactory::icon("psi/sendMessage").icon(), tr("New &Blank Message"), 6); pm.insertSeparator(); pm.insertItem(IconsetFactory::icon("psi/xml").icon(), tr("&XML Console"), 10); pm.insertSeparator(); pm.insertItem(IconsetFactory::icon("psi/account").icon(), tr("&Modify Account..."), 0); if (PsiOptions::instance()->getOption("options.ui.menu.account.admin").toBool()) { pm.insertSeparator(); pm.setItemEnabled(pm.insertItem(tr("&Admin"), am), online); } int x = pm.exec(pos); if(x == -1) return; if(x == 0) d->pa->modify(); else if(x == 1) { Jid j = d->pa->jid().domain() + '/' + "announce/online"; actionSendMessage(j); } else if(x == 2) { Jid j = d->pa->jid().domain() + '/' + "announce/motd"; actionSendMessage(j); } else if(x == 3) { Jid j = d->pa->jid().domain() + '/' + "announce/motd/update"; actionSendMessage(j); } else if(x == 4) { Jid j = d->pa->jid().domain() + '/' + "announce/motd/delete"; Message m; m.setTo(j); d->pa->dj_sendMessage(m, false); } else if(x == 5) { // FIXME: will it still work on XMPP servers? Jid j = d->pa->jid().domain() + '/' + "admin"; actionDisco(j, ""); } else if(x == 6) { actionSendMessage(""); } else if(x == 7) { d->pa->openAddUserDlg(); } else if(x == 9) { Jid j = d->pa->jid().domain(); actionDisco(j, ""); } else if(x == 10) { d->pa->showXmlConsole(); } else if(x == 11 && pm.isItemEnabled(11)) { emit actionSetMood(); } else if(x == 12 && pm.isItemEnabled(14)) { emit actionSetAvatar(); } else if(x == 13 && pm.isItemEnabled(14)) { emit actionUnsetAvatar(); } else if(x >= status_start && x <= STATUS_CHAT + status_start) { // STATUS_CHAT is the highest value of the states int status = x - status_start; d->pa->changeStatus(status); } else if(x == bookmarks_start) { BookmarkManageDlg *dlg = d->pa->findDialog<BookmarkManageDlg*>(); if(dlg) { bringToFront(dlg); } else { dlg = new BookmarkManageDlg(d->pa); dlg->show(); } } else if (x > bookmarks_start) { ConferenceBookmark c = psiAccount()->bookmarkManager()->conferences()[x - bookmarks_start - 1]; psiAccount()->actionJoin(c, true); } } else if(i->type() == ContactViewItem::Group) { QString gname = i->groupName(); Q3PopupMenu pm; if (PsiOptions::instance()->getOption("options.ui.message.enabled").toBool()) pm.insertItem(IconsetFactory::icon("psi/sendMessage").icon(), tr("Send Message to Group"), 0); if(!PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { // disable if it's not a user group if(!online || i->groupType() != ContactViewItem::gUser || gname == ContactView::tr("Hidden")) { d->cv->qa_ren->setEnabled(false); pm.setItemEnabled(2, false); pm.setItemEnabled(3, false); } else d->cv->qa_ren->setEnabled(true); d->cv->qa_ren->addTo(&pm); pm.insertSeparator(); pm.insertItem(IconsetFactory::icon("psi/remove").icon(), tr("Remove Group"), 2); pm.insertItem(IconsetFactory::icon("psi/remove").icon(), tr("Remove Group and Contacts"), 3); } if(i->groupType() == ContactViewItem::gAgents) { pm.insertSeparator(); pm.insertItem(tr("Hide"), 4); } int x = pm.exec(pos); // restore actions if(PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) d->cv->qa_ren->setEnabled(false); else d->cv->qa_ren->setEnabled(true); if(x == -1) return; if(x == 0) { QList<XMPP::Jid> list = contactListFromCVGroup(i); // send multi actionSendMessage(list); } else if(x == 2 && online) { int n = QMessageBox::information(d->cv, tr("Remove Group"),tr( "This will cause all contacts in this group to be disassociated with it.\n" "\n" "Proceed?"), tr("&Yes"), tr("&No")); if(n == 0) { QList<XMPP::Jid> list = contactListFromGroup(i->groupName()); for(QList<Jid>::Iterator it = list.begin(); it != list.end(); ++it) actionGroupRemove(*it, gname); } } else if(x == 3 && online) { int n = QMessageBox::information(d->cv, tr("Remove Group and Contacts"),tr( "WARNING! This will remove all contacts associated with this group!\n" "\n" "Proceed?"), tr("&Yes"), tr("&No")); if(n == 0) { QList<XMPP::Jid> list = contactListFromGroup(i->groupName()); for(QList<Jid>::Iterator it = list.begin(); it != list.end(); ++it) { removeEntry(*it); actionRemove(*it); } } } else if(x == 4) { if(i->groupType() == ContactViewItem::gAgents) d->cv->setShowAgents(false); } } else if(i->type() == ContactViewItem::Contact) { bool self = false; UserListItem *u; Entry *e = 0; if(i == d->self) { self = true; u = &d->su; } else { e = findEntry(i); if(!e) return; u = &e->u; } QStringList gl = groupList(); qSort(gl.begin(), gl.end(), caseInsensitiveLessThan); bool inList = e ? e->u.inList() : false; bool isPrivate = e ? e->u.isPrivate(): false; bool isAgent = e ? e->u.isTransport() : false; bool avail = e ? e->u.isAvailable() : false; QString groupNameCache = ((ContactViewItem *)static_cast<Q3ListViewItem *>(i)->parent())->groupName(); Q3PopupMenu pm; if(!self && !inList && !isPrivate && !PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { pm.insertItem(IconsetFactory::icon("psi/addContact").icon(), tr("Add/Authorize to Contact List"), 10); if(!online) pm.setItemEnabled(10, false); pm.insertSeparator(); } if ( (self && i->isAlerting()) || (!self && e->alerting) ) { d->cv->qa_recv->addTo(&pm); pm.insertSeparator(); } if (PsiOptions::instance()->getOption("options.ui.message.enabled").toBool()) d->cv->qa_send->addTo(&pm); //pm.insertItem(QIconSet(PsiIconset::instance()->url), tr("Send &URL"), 2); const UserResourceList &rl = u->userResourceList(); int base_sendto = 32; int at_sendto = 0; ResourceMenu *s2m = new ResourceMenu(&pm); ResourceMenu *c2m = new ResourceMenu(&pm); #ifdef WHITEBOARDING ResourceMenu *wb2m = new ResourceMenu(&pm); #endif ResourceMenu *rc2m = new ResourceMenu(&pm); if(!rl.isEmpty()) { for(UserResourceList::ConstIterator it = rl.begin(); it != rl.end(); ++it) { const UserResource &r = *it; s2m->addResource(r, base_sendto+at_sendto++); c2m->addResource(r, base_sendto+at_sendto++); #ifdef WHITEBOARDING wb2m->addResource(r, base_sendto+at_sendto++); #endif rc2m->addResource(r, base_sendto+at_sendto++); } } if(!isPrivate && PsiOptions::instance()->getOption("options.ui.message.enabled").toBool()) pm.insertItem(tr("Send Message To"), s2m, 17); d->cv->qa_chat->setIconSet(IconsetFactory::iconPixmap("psi/start-chat")); d->cv->qa_chat->addTo(&pm); if(!isPrivate) pm.insertItem(tr("Open Chat To"), c2m, 18); #ifdef WHITEBOARDING d->cv->qa_wb->setIconSet(IconsetFactory::iconPixmap("psi/whiteboard")); d->cv->qa_wb->addTo(&pm); if(!isPrivate) pm.insertItem(tr("Open a Whiteboard To"), wb2m, 19); #endif if(!isPrivate) { if(rl.isEmpty()) { pm.setItemEnabled(17, false); pm.setItemEnabled(18, false); #ifdef WHITEBOARDING pm.setItemEnabled(19, false); #endif } } // TODO: Add executeCommand() thing if(!isPrivate) { pm.insertItem(tr("E&xecute Command"), rc2m, 25); pm.setItemEnabled(25, !rl.isEmpty()); } int base_hidden = base_sendto + at_sendto; int at_hidden = 0; QStringList hc; if(!isPrivate && PsiOptions::instance()->getOption("options.ui.menu.contact.active-chats").toBool()) { hc = d->pa->hiddenChats(u->jid()); ResourceMenu *cm = new ResourceMenu(&pm); for(QStringList::ConstIterator it = hc.begin(); it != hc.end(); ++it) { // determine status int status; const UserResourceList &rl = u->userResourceList(); UserResourceList::ConstIterator uit = rl.find(*it); if(uit != rl.end() || (uit = rl.priority()) != rl.end()) status = makeSTATUS((*uit).status()); else status = STATUS_OFFLINE; cm->addResource(status, *it, base_hidden+at_hidden++); } pm.insertItem(tr("Active Chats"), cm, 7); if(hc.isEmpty()) pm.setItemEnabled(7, false); } // Voice call if(d->pa->avCallManager() && !isAgent) { //if(d->pa->voiceCaller() && !isAgent) { pm.insertItem(IconsetFactory::icon("psi/voice").icon(), tr("Voice Call"), 24); if(!online) { pm.setItemEnabled(24, false); } /*else { bool hasVoice = false; const UserResourceList &rl = u->userResourceList(); for (UserResourceList::ConstIterator it = rl.begin(); it != rl.end() && !hasVoice; ++it) { hasVoice = psiAccount()->capsManager()->features(u->jid().withResource((*it).name())).canVoice(); } pm.setItemEnabled(24,!psiAccount()->capsManager()->isEnabled() || hasVoice); }*/ } if(!isAgent) { pm.insertSeparator(); pm.insertItem(IconsetFactory::icon("psi/upload").icon(), tr("Send &File"), 23); if(!online) pm.setItemEnabled(23, false); } // invites int base_gc = base_hidden + at_hidden; int at_gc = 0; QStringList groupchats; if(!isPrivate && !isAgent) { Q3PopupMenu *gm = new Q3PopupMenu(&pm); groupchats = d->pa->groupchats(); for(QStringList::ConstIterator it = groupchats.begin(); it != groupchats.end(); ++it) { int id = gm->insertItem(*it, base_gc+at_gc++); if(!online) gm->setItemEnabled(id, false); } pm.insertItem(IconsetFactory::iconPixmap("psi/groupChat"), tr("Invite To"), gm, 14); if(groupchats.isEmpty()) pm.setItemEnabled(14, false); } // weird? if(inList || !isAgent) pm.insertSeparator(); int base_group = base_gc + at_gc; if(!self) { if(inList) { if(!PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { d->cv->qa_ren->setEnabled(online); d->cv->qa_ren->addTo(&pm); } } if(!isAgent) { if(inList && !PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { Q3PopupMenu *gm = new Q3PopupMenu(&pm); gm->setCheckable(true); gm->insertItem(tr("&None"), 8); gm->insertSeparator(); QString g; if(e->u.groups().isEmpty()) gm->setItemChecked(8, true); else g = groupNameCache; int n = 0; gl.remove(ContactView::tr("Hidden")); for(QStringList::ConstIterator it = gl.begin(); it != gl.end(); ++it) { QString str; if(n < 9) str = "&"; str += QString("%1. %2").arg(n+1).arg(*it); gm->insertItem(str, n+base_group); if(*it == g) gm->setItemChecked(n+base_group, true); ++n; } if(n > 0) gm->insertSeparator(); gm->insertItem(ContactView::tr("Hidden"),n+base_group); if(g == ContactView::tr("Hidden")) gm->setItemChecked(n+base_group, true); gm->insertSeparator(); gm->insertItem(/*IconsetFactory::iconPixmap("psi/edit/clear"),*/ tr("&Create New..."), 9); pm.insertItem(tr("&Group"), gm, 5); if(!online) pm.setItemEnabled(5, false); } } else { pm.insertSeparator(); d->cv->qa_logon->setEnabled( !avail && online ); d->cv->qa_logon->setIcon(PsiIconset::instance()->status(e->u.jid(), STATUS_ONLINE).icon()); d->cv->qa_logon->addTo(&pm); pm.insertItem(PsiIconset::instance()->status(e->u.jid(), STATUS_OFFLINE).icon(), tr("Log Off"), 16); if(!avail || !online) pm.setItemEnabled(16, false); pm.insertSeparator(); } } if(inList && !PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { Q3PopupMenu *authm = new Q3PopupMenu (&pm); authm->insertItem(tr("Resend Authorization To"), 6); authm->insertItem(tr("Rerequest Authorization From"), 11); authm->insertItem(/*IconsetFactory::iconPixmap("psi/edit/delete"),*/ tr("Remove Authorization From"), 15); pm.insertItem (IconsetFactory::iconPixmap("psi/register"), tr("Authorization"), authm, 20); if(!online) pm.setItemEnabled(20, false); } if(!self) { if(!PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { if(online || !inList) d->cv->qa_rem->setEnabled(true); else d->cv->qa_rem->setEnabled(false); d->cv->qa_rem->addTo(&pm); } pm.insertSeparator(); } // Avatars if (PsiOptions::instance()->getOption("options.ui.menu.contact.custom-picture").toBool()) { Q3PopupMenu *avpm = new Q3PopupMenu(&pm); d->cv->qa_assignAvatar->addTo(avpm); d->cv->qa_clearAvatar->setEnabled(d->pa->avatarFactory()->hasManualAvatar(u->jid())); d->cv->qa_clearAvatar->addTo(avpm); pm.insertItem(tr("&Picture"), avpm); } if(PGPUtil::instance().pgpAvailable() && PsiOptions::instance()->getOption("options.ui.menu.contact.custom-pgp-key").toBool()) { if(u->publicKeyID().isEmpty()) pm.insertItem(IconsetFactory::icon("psi/gpg-yes").icon(), tr("Assign Open&PGP Key"), 21); else pm.insertItem(IconsetFactory::icon("psi/gpg-no").icon(), tr("Unassign Open&PGP Key"), 22); } d->cv->qa_vcard->addTo( &pm ); if(!isPrivate) { d->cv->qa_hist->addTo(&pm); } QString name = u->jid().full(); QString show = JIDUtil::nickOrJid(u->name(), u->jid().full()); if(name != show) name += QString(" (%1)").arg(u->name()); int x = pm.exec(pos); // restore actions d->cv->qa_logon->setEnabled(true); if(PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { d->cv->qa_ren->setEnabled(false); d->cv->qa_rem->setEnabled(false); } else { d->cv->qa_ren->setEnabled(true); d->cv->qa_rem->setEnabled(true); } if(x == -1) return; if(x == 0) { actionRecvEvent(u->jid()); } else if(x == 1) { actionSendMessage(u->jid()); } else if(x == 2) { actionSendUrl(u->jid()); } else if(x == 6) { if(online) { actionAuth(u->jid()); QMessageBox::information(d->cv, tr("Authorize"), tr("Sent authorization to <b>%1</b>.").arg(name)); } } else if(x == 8) { if(online) { // if we have groups, but we are setting to 'none', then remove that particular group if(!u->groups().isEmpty()) { QString gname = groupNameCache; actionGroupRemove(u->jid(), gname); } } } else if(x == 9) { if(online) { while(1) { bool ok = false; QString newgroup = QInputDialog::getText(tr("Create New Group"), tr("Enter the new group name:"), QLineEdit::Normal, QString::null, &ok, d->cv); if(!ok) break; if(newgroup.isEmpty()) continue; // make sure we don't have it already bool found = false; const QStringList &groups = u->groups(); for(QStringList::ConstIterator it = groups.begin(); it != groups.end(); ++it) { if(*it == newgroup) { found = true; break; } } if(!found) { QString gname = groupNameCache; actionGroupRemove(u->jid(), gname); actionGroupAdd(u->jid(), newgroup); break; } } } } else if(x == 10) { if(online) { actionAdd(u->jid()); actionAuth(u->jid()); QMessageBox::information(d->cv, tr("Add"), tr("Added/Authorized <b>%1</b> to the contact list.").arg(name)); } } else if(x == 11) { if(online) { actionAuthRequest(u->jid()); QMessageBox::information(d->cv, tr("Authorize"), tr("Rerequested authorization from <b>%1</b>.").arg(name)); } } else if(x == 15) { if(online) { int n = QMessageBox::information(d->cv, tr("Remove"), tr("Are you sure you want to remove authorization from <b>%1</b>?").arg(name), tr("&Yes"), tr("&No")); if(n == 0) actionAuthRemove(u->jid()); } } else if(x == 16) { if(online) { Status s=makeStatus(STATUS_OFFLINE,""); actionAgentSetStatus(u->jid(), s); } } else if(x == 21) { actionAssignKey(u->jid()); } else if(x == 22) { actionUnassignKey(u->jid()); } else if(x == 23) { if(online) actionSendFile(u->jid()); } else if (x == 25) { if(online) actionExecuteCommand(u->jid(),""); } else if (x == 24) { if(online) actionVoice(u->jid()); } else if(x >= base_sendto && x < base_hidden) { int n = x - base_sendto; #ifndef WHITEBOARDING int res = n / 3; int type = n % 3; #else int res = n / 4; int type = n % 4; #endif QString rname = ""; //if(res > 0) { const UserResource &r = rl[res]; rname = r.name(); //} QString s = u->jid().bare(); if(!rname.isEmpty()) { s += '/'; s += rname; } Jid j(s); if(type == 0) actionSendMessage(j); else if(type == 1) actionOpenChatSpecific(j); #ifndef WHITEBOARDING else if (type == 2) actionExecuteCommandSpecific(j,""); #else else if (type == 2) actionOpenWhiteboardSpecific(j); else if (type == 3) actionExecuteCommandSpecific(j,""); #endif } else if(x >= base_hidden && x < base_gc) { int n = 0; int n2 = x - base_hidden; QString rname; for(QStringList::ConstIterator it = hc.begin(); it != hc.end(); ++it) { if(n == n2) { rname = *it; break; } ++n; } QString s = u->jid().bare(); if(!rname.isEmpty()) { s += '/'; s += rname; } Jid j(s); actionOpenChatSpecific(j); } else if(x >= base_gc && x < base_group) { if(online) { QString gc = groupchats[x - base_gc]; actionInvite(u->jid(), gc); QMessageBox::information(d->cv, tr("Invitation"), tr("Sent groupchat invitation to <b>%1</b>.").arg(name)); } } else if(x >= base_group) { if(online) { int n = 0; int n2 = x - base_group; QString newgroup; for(QStringList::Iterator it = gl.begin(); it != gl.end(); ++it) { if(n == n2) { newgroup = *it; break; } ++n; } if(newgroup.isEmpty()) newgroup = ContactView::tr("Hidden"); if(n == n2) { // remove the group of this cvi if there is one if(!u->groups().isEmpty()) { //QString gname = ((ContactViewItem *)static_cast<QListViewItem *>(i)->parent())->groupName(); QString gname = groupNameCache; actionGroupRemove(u->jid(), gname); } // add the group actionGroupAdd(u->jid(), newgroup); } } } } } void ContactProfile::scActionDefault(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionDefault(i->u()->jid()); } void ContactProfile::scRecvEvent(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionRecvEvent(i->u()->jid()); } void ContactProfile::scSendMessage(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionSendMessage(i->u()->jid()); } void ContactProfile::scRename(ContactViewItem *i) { if(!d->pa->loggedIn()) return; if((i->type() == ContactViewItem::Contact && i->u()->inList()) || (i->type() == ContactViewItem::Group && i->groupType() == ContactViewItem::gUser && i->groupName() != ContactView::tr("Hidden"))) { i->resetName(true); i->setRenameEnabled(0, true); i->startRename(0); i->setRenameEnabled(0, false); } } void ContactProfile::scVCard(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionInfo(i->u()->jid()); } void ContactProfile::scHistory(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionHistory(i->u()->jid()); } void ContactProfile::scOpenChat(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionOpenChat(i->u()->jid()); } #ifdef WHITEBOARDING void ContactProfile::scOpenWhiteboard(ContactViewItem *i) { if(i->type() == ContactViewItem::Contact) actionOpenWhiteboard(i->u()->jid()); } #endif void ContactProfile::scAgentSetStatus(ContactViewItem *i, Status &s) { if(i->type() != ContactViewItem::Contact) return; if(!i->isAgent()) return; if(i->u()->isAvailable() || !d->pa->loggedIn()) return; actionAgentSetStatus(i->u()->jid(), s); } void ContactProfile::scRemove(ContactViewItem *i) { if(i->type() != ContactViewItem::Contact) return; Entry *e = findEntry(i); if(!e) return; bool ok = true; if(!d->pa->loggedIn()) ok = false; if(!i->u()->inList()) ok = true; if(ok) { QString name = e->u.jid().full(); QString show = JIDUtil::nickOrJid(e->u.name(), e->u.jid().full()); if(name != show) name += QString(" (%1)").arg(e->u.name()); int n = 0; int gt = i->parentGroupType(); if(gt != ContactViewItem::gNotInList && gt != ContactViewItem::gPrivate) { n = QMessageBox::information(d->cv, tr("Remove"), tr("Are you sure you want to remove <b>%1</b> from your contact list?").arg(name), tr("&Yes"), tr("&No")); } else n = 0; if(n == 0) { Jid j = e->u.jid(); removeEntry(e); actionRemove(j); } } } void ContactProfile::doItemRenamed(ContactViewItem *i, const QString &text) { if(i->type() == ContactViewItem::Contact) { Entry *e = findEntry(i); if(!e) return; // no change? //if(text == i->text(0)) // return; if(text.isEmpty()) { i->resetName(); QMessageBox::information(d->cv, tr("Error"), tr("You cannot set a blank name.")); return; } //e->u.setName(text); //i->setContact(&e->u); actionRename(e->u.jid(), text); i->resetName(); // to put the status message in if needed } else { // no change? if(text == i->groupName()) { i->resetGroupName(); return; } if(text.isEmpty()) { i->resetGroupName(); QMessageBox::information(d->cv, tr("Error"), tr("You cannot set a blank group name.")); return; } // make sure we don't have it already QStringList g = groupList(); bool found = false; for(QStringList::ConstIterator it = g.begin(); it != g.end(); ++it) { if(*it == text) { found = true; break; } } if(found) { i->resetGroupName(); QMessageBox::information(d->cv, tr("Error"), tr("You already have a group with that name.")); return; } QString oldName = i->groupName(); // set group name i->setGroupName(text); // send signal actionGroupRename(oldName, text); } } void ContactProfile::dragDrop(const QString &text, ContactViewItem *i) { if(!d->pa->loggedIn()) return; // get group ContactViewItem *gr; if(i->type() == ContactViewItem::Group) gr = i; else gr = (ContactViewItem *)static_cast<Q3ListViewItem *>(i)->parent(); Jid j(text); if(!j.isValid()) return; Entry *e = findEntry(j); if(!e) return; const UserListItem &u = e->u; QStringList gl = u.groups(); // already in the general group if(gr->groupType() == ContactViewItem::gGeneral && gl.isEmpty()) return; // already in this user group if(gr->groupType() == ContactViewItem::gUser && u.inGroup(gr->groupName())) return; //printf("putting [%s] into group [%s]\n", u.jid().full().latin1(), gr->groupName().latin1()); // remove all other groups from this contact for(QStringList::ConstIterator it = gl.begin(); it != gl.end(); ++it) { actionGroupRemove(u.jid(), *it); } if(gr->groupType() == ContactViewItem::gUser) { // add the new group actionGroupAdd(u.jid(), gr->groupName()); } } void ContactProfile::dragDropFiles(const QStringList &files, ContactViewItem *i) { if(files.isEmpty() || !d->pa->loggedIn() || i->type() != ContactViewItem::Contact) return; Entry *e = findEntry(i); if(!e) return; actionSendFiles(e->u.jid(),files); } //---------------------------------------------------------------------------- // ContactView //---------------------------------------------------------------------------- class ContactView::Private : public QObject { Q_OBJECT public: Private(ContactView *_cv) : QObject(_cv) { cv = _cv; autoRosterResizeInProgress = false; } ContactView *cv; QTimer *animTimer, *recalculateSizeTimer; Q3PtrList<ContactProfile> profiles; QSize lastSize; bool autoRosterResizeInProgress; public slots: /* * \brief Recalculates the size of ContactView and resizes it accordingly */ void recalculateSize() { // save some CPU if ( !cv->allowResize() ) return; if ( !cv->isUpdatesEnabled() ) return; QSize oldSize = cv->size(); QSize newSize = cv->sizeHint(); if ( newSize.height() != oldSize.height() ) { lastSize = newSize; QWidget *topParent = cv->window(); if ( cv->allowResize() ) { topParent->layout()->setEnabled( false ); // try to reduce some flicker int dh = newSize.height() - oldSize.height(); topParent->resize( topParent->width(), topParent->height() + dh ); autoRosterResizeInProgress = true; QRect desktop = qApp->desktop()->availableGeometry( (QWidget *)topParent ); if ( PsiOptions::instance()->getOption("options.ui.contactlist.grow-roster-upwards").toBool() ) { int newy = topParent->y() - dh; // check, if we need to move roster lower if ( dh > 0 && ( topParent->frameGeometry().top() <= desktop.top() ) ) { newy = desktop.top(); } topParent->move( topParent->x(), newy ); } // check, if we need to move roster upper if ( dh > 0 && ( topParent->frameGeometry().bottom() >= desktop.bottom() ) ) { int newy = desktop.bottom() - topParent->frameGeometry().height(); topParent->move( topParent->x(), newy ); } QTimer::singleShot( 0, this, SLOT( resetAutoRosterResize() ) ); topParent->layout()->setEnabled( true ); } // issue a layout update cv->parentWidget()->layout()->update(); } } /* * \brief Determine in which direction to grow Psi roster window when autoRosterSize is enabled */ void determineAutoRosterSizeGrowSide() { if ( autoRosterResizeInProgress ) return; QWidget *topParent = cv->window(); QRect desktop = qApp->desktop()->availableGeometry( (QWidget *)topParent ); int top_offs = abs( desktop.top() - topParent->frameGeometry().top() ); int bottom_offs = abs( desktop.bottom() - topParent->frameGeometry().bottom() ); PsiOptions::instance()->setOption("options.ui.contactlist.grow-roster-upwards", (bool) (bottom_offs < top_offs)); //qWarning("growTop = %d", PsiOptions::instance()->getOption("options.ui.contactlist.automatically-resize-roster").toBool()GrowTop); } /* * \brief Display tool tip for item under cursor. */ bool doToolTip(QPoint pos) { ContactViewItem *i = (ContactViewItem *)cv->itemAt(pos); if(i) { QRect r(cv->itemRect(i)); QPoint globalPos = cv->mapToGlobal(pos); if(i->type() == ContactViewItem::Contact) PsiToolTip::showText(globalPos, i->u()->makeTip(true, false), cv); else if(i->type() == ContactViewItem::Profile) PsiToolTip::showText(globalPos, i->contactProfile()->makeTip(true, false), cv); else PsiToolTip::showText(globalPos, i->groupName() + " " + i->groupInfo(), cv); return true; } return false; } private slots: void resetAutoRosterResize() { //qWarning("resetAutoRosterResize"); autoRosterResizeInProgress = false; } }; ContactView::ContactView(QWidget *parent, const char *name) :Q3ListView(parent, name, Qt::WNoAutoErase | Qt::WResizeNoErase) { d = new Private(this); // setup the QListView setAllColumnsShowFocus(true); setShowToolTips(false); setHScrollBarMode(AlwaysOff); setMinimumSize(96,32); setTreeStepSize(4); setSorting(0,true); window()->installEventFilter( this ); // create the column and hide the header addColumn(""); header()->hide(); setResizeMode(Q3ListView::LastColumn); setDefaultRenameAction(Q3ListView::Accept); // catch signals lcto_active = false; connect(this, SIGNAL(itemRenamed(Q3ListViewItem *, int, const QString &)), SLOT(qlv_itemRenamed(Q3ListViewItem *, int, const QString &))); connect(this, SIGNAL(mouseButtonPressed(int, Q3ListViewItem *, const QPoint &, int)),SLOT(qlv_singleclick(int, Q3ListViewItem *, const QPoint &, int)) ); connect(this, SIGNAL(doubleClicked(Q3ListViewItem *)),SLOT(qlv_doubleclick(Q3ListViewItem *)) ); connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem *, const QPoint &, int)), SLOT(qlv_contextMenuRequested(Q3ListViewItem *, const QPoint &, int))); v_showOffline = PsiOptions::instance()->getOption("options.ui.contactlist.show.offline-contacts").toBool(); v_showAway = PsiOptions::instance()->getOption("options.ui.contactlist.show.away-contacts").toBool(); v_showHidden = PsiOptions::instance()->getOption("options.ui.contactlist.show.hidden-contacts-group").toBool(); v_showAgents = PsiOptions::instance()->getOption("options.ui.contactlist.show.agent-contacts").toBool(); v_showSelf = PsiOptions::instance()->getOption("options.ui.contactlist.show.self-contact").toBool(); v_showStatusMsg = PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.show").toBool(); d->lastSize = QSize( 0, 0 ); // animation timer d->animTimer = new QTimer(this); d->animTimer->start(120 * 5); d->recalculateSizeTimer = new QTimer(this); connect(d->recalculateSizeTimer, SIGNAL(timeout()), d, SLOT(recalculateSize())); // actions qa_send = new IconAction("", "psi/sendMessage", tr("Send &Message"), 0, this); connect(qa_send, SIGNAL(activated()), SLOT(doSendMessage())); qa_ren = new IconAction("", /*"psi/edit/clear",*/ tr("Re&name"), 0, this); connect(qa_ren, SIGNAL(activated()), SLOT(doRename())); qa_assignAvatar = new IconAction("", tr("&Assign Custom Picture"), 0, this); connect(qa_assignAvatar, SIGNAL(activated()), SLOT(doAssignAvatar())); qa_clearAvatar = new IconAction("", tr("&Clear Custom Picture"), 0, this); connect(qa_clearAvatar, SIGNAL(activated()), SLOT(doClearAvatar())); qa_chat = new IconAction("", "psi/start-chat", tr("Open &Chat Window"), 0, this); connect(qa_chat, SIGNAL(activated()), SLOT(doOpenChat())); #ifdef WHITEBOARDING qa_wb = new IconAction("", "psi/whiteboard", tr("Open a &Whiteboard"), Qt::CTRL+Qt::Key_W, this); connect(qa_wb, SIGNAL(activated()), SLOT(doOpenWhiteboard())); #endif qa_hist = new IconAction("", "psi/history", tr("&History"), 0, this); connect(qa_hist, SIGNAL(activated()), SLOT(doHistory())); qa_logon = new IconAction("", tr("&Log on"), 0, this); connect(qa_logon, SIGNAL(activated()), SLOT(doLogon())); qa_recv = new IconAction("", tr("&Receive Incoming Event"), 0, this); connect(qa_recv, SIGNAL(activated()), SLOT(doRecvEvent())); qa_rem = new IconAction("", "psi/remove", tr("Rem&ove"), 0, this); connect(qa_rem, SIGNAL(activated()), SLOT(doRemove())); qa_vcard = new IconAction("", "psi/vCard", tr("User &Info"), 0, this); connect(qa_vcard, SIGNAL(activated()), SLOT(doVCard())); if(PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) { qa_ren->setEnabled(false); qa_rem->setEnabled(false); } optionsUpdate(); setAcceptDrops(true); viewport()->setAcceptDrops(true); filterString_ = QString(); applyingFilter = false; } ContactView::~ContactView() { clear(); delete d; } bool ContactView::filterContact(ContactViewItem *item, bool refineSearch) { if (!item) { return false; } if (item->type() != ContactViewItem::Contact) { return false; } if (filterString_.isNull()) { return true; } //if refineSearch, only search still visible items if (refineSearch && !item->isVisible()) { return false; } if (TextUtil::rich2plain(item->text(0)).contains(filterString_,Qt::CaseInsensitive)) { ensureItemVisible(item); item->setVisible(true); item->optionsUpdate(); } else { item->setVisible(false); } item->repaint(); return item->isVisible(); } bool ContactView::filterGroup(ContactViewItem *group, bool refineSearch) { if (!group) { return false; } else if (group->type() != ContactViewItem::Group) { return false; } else if (filterString_.isNull()) { return true; } //if refine_search, only search still visible items if (refineSearch && !group->isVisible()) { return false; } group->setVisible(true); //if not refined search //iterate over children Q3ListViewItemIterator it(group); bool groupContainsAFinding = false; ContactViewItem *item = static_cast<ContactViewItem*>(group->firstChild()); while(item) { if (filterContact(item,refineSearch)) groupContainsAFinding = true; item = static_cast<ContactViewItem*>(item->nextSibling()); } if (groupContainsAFinding == false) { group->setVisible(false); } group->repaint(); return groupContainsAFinding; } void ContactView::setFilter(QString const &text) { bool refineSearch = text.startsWith(filterString_); filterString_ = text; applyingFilter = true; Q3ListViewItemIterator it(d->cv); for (ContactViewItem *item; (item = (ContactViewItem *)it.current()); ++it) { if (item->type() == ContactViewItem::Group) { filterGroup(item, refineSearch); } } applyingFilter = false; } void ContactView::clearFilter() { filterString_=QString(); Q3ListViewItemIterator it(d->cv); for (ContactViewItem *item; (item = (ContactViewItem *)it.current()); ++it) { item->setVisible(true); item->clearFilter(); item->optionsUpdate(); item->repaint(); } } QTimer *ContactView::animTimer() const { return d->animTimer; } void ContactView::clear() { d->profiles.setAutoDelete(true); d->profiles.clear(); d->profiles.setAutoDelete(false); } void ContactView::link(ContactProfile *cp) { d->profiles.append(cp); } void ContactView::unlink(ContactProfile *cp) { d->profiles.removeRef(cp); } void ContactView::keyPressEvent(QKeyEvent *e) { int key = e->key(); if(key == Qt::Key_Enter || key == Qt::Key_Return) { doEnter(); } else if(key == Qt::Key_Space /*&& d->typeAhead.isEmpty()*/) { doContext(); } else if (key == Qt::Key_Home || key == Qt::Key_End || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_Left || key == Qt::Key_Right) { //d->typeAhead = QString::null; Q3ListView::keyPressEvent(e); #ifdef Q_WS_MAC } else if (e->modifiers() == Qt::ControlModifier) { Q3ListView::keyPressEvent(e); #endif } else { QString text = e->text().lower(); if (text.isEmpty()) { Q3ListView::keyPressEvent(e); } else { bool printable = true; foreach (QChar ch, text) { if (!ch.isPrint()) { Q3ListView::keyPressEvent(e); printable = false; break; } } if (printable) { emit searchInput(text); } } } } void ContactView::setShowOffline(bool x) { bool oldstate = v_showOffline; v_showOffline = x; PsiOptions::instance()->setOption("options.ui.contactlist.show.offline-contacts", x); if(v_showOffline != oldstate) { showOffline(v_showOffline); Q3PtrListIterator<ContactProfile> it(d->profiles); for(ContactProfile *cp; (cp = it.current()); ++it) { if(!v_showOffline) cp->removeAllUnneededContactItems(); else cp->addAllNeededContactItems(); } } } void ContactView::setShowAway(bool x) { bool oldstate = v_showAway; v_showAway = x; PsiOptions::instance()->setOption("options.ui.contactlist.show.away-contacts", x); if(v_showAway != oldstate) { showAway(v_showAway); Q3PtrListIterator<ContactProfile> it(d->profiles); for(ContactProfile *cp; (cp = it.current()); ++it) { if(!v_showAway) cp->removeAllUnneededContactItems(); else cp->addAllNeededContactItems(); } } } void ContactView::setShowHidden(bool x) { bool oldstate = v_showHidden; v_showHidden = x; PsiOptions::instance()->setOption("options.ui.contactlist.show.hidden-contacts-group", x); if(v_showHidden != oldstate) { showHidden(v_showHidden); Q3PtrListIterator<ContactProfile> it(d->profiles); for(ContactProfile *cp; (cp = it.current()); ++it) { if(!v_showHidden) cp->removeAllUnneededContactItems(); else cp->addAllNeededContactItems(); } } } void ContactView::setShowStatusMsg(bool x) { if (v_showStatusMsg != x) { v_showStatusMsg = x; PsiOptions::instance()->setOption("options.ui.contactlist.status-messages.show",x); emit showStatusMsg(v_showStatusMsg); Q3PtrListIterator<ContactProfile> it(d->profiles); for(ContactProfile *cp; (cp = it.current()); ++it) { cp->resetAllContactItemNames(); } recalculateSize(); } } /* * \brief Shows/hides the self contact in roster * * \param x - boolean variable specifies whether to show self-contact or not */ void ContactView::setShowSelf(bool x) { if (v_showSelf != x) { v_showSelf = x; PsiOptions::instance()->setOption("options.ui.contactlist.show.self-contact", x); showSelf(v_showSelf); Q3PtrListIterator<ContactProfile> it(d->profiles); for(ContactProfile *cp; (cp = it.current()); ++it) { if (v_showSelf && ! cp->self()) { cp->addSelf(); } else if (!v_showSelf && cp->self() && cp->self()->u()->userResourceList().count() <= 1) { cp->removeSelf(); } } recalculateSize(); } } /* * \brief Event filter. Nuff said. */ bool ContactView::eventFilter( QObject *obj, QEvent *event ) { if ( event->type() == QEvent::Move ) d->determineAutoRosterSizeGrowSide(); else if (event->type() == QEvent::ToolTip && obj == viewport()) { if (d->doToolTip(((QHelpEvent*)event)->pos())) { event->accept(); return true; } } return Q3ListView::eventFilter( obj, event ); } void ContactView::setShowAgents(bool x) { bool oldstate = v_showAgents; v_showAgents = x; PsiOptions::instance()->setOption("options.ui.contactlist.show.agent-contacts", x); if(v_showAgents != oldstate) { showAgents(v_showAgents); Q3PtrListIterator<ContactProfile> it(d->profiles); for(ContactProfile *cp; (cp = it.current()); ++it) { if(!v_showAgents) cp->removeAllUnneededContactItems(); else cp->addAllNeededContactItems(); } } } // right-click context menu void ContactView::qlv_contextMenuRequested(Q3ListViewItem *lvi, const QPoint &pos, int c) { if(PsiOptions::instance()->getOption("options.ui.contactlist.use-left-click").toBool()) return; qlv_contextPopup(lvi, pos, c); } void ContactView::qlv_contextPopup(Q3ListViewItem *lvi, const QPoint &pos, int) { ContactViewItem *i = (ContactViewItem *)lvi; if(!i) return; i->contactProfile()->doContextMenu(i, pos); } void ContactView::qlv_singleclick(int button, Q3ListViewItem *i, const QPoint &pos, int c) { lcto_active = false; if(!i) return; ContactViewItem *item = (ContactViewItem *)i; setSelected(item, true); if(button == Qt::MidButton) { if(item->type() == ContactViewItem::Contact) item->contactProfile()->scActionDefault(item); } else { const QPixmap * pix = item->pixmap(0); if (button == Qt::LeftButton && item->type() == ContactViewItem::Group && pix && viewport()->mapFromGlobal(pos).x() <= pix->width() + treeStepSize()) { setOpen(item, !item->isOpen()); } else if(PsiOptions::instance()->getOption("options.ui.contactlist.use-left-click").toBool()) { if(button == Qt::LeftButton) { if(PsiOptions::instance()->getOption("options.ui.contactlist.use-single-click").toBool()) { qlv_contextPopup(i, pos, c); } else { lcto_active = true; lcto_pos = pos; lcto_item = i; QTimer::singleShot(QApplication::doubleClickInterval()/2, this, SLOT(leftClickTimeOut())); } } else if(PsiOptions::instance()->getOption("options.ui.contactlist.use-single-click").toBool() && button == Qt::RightButton) { if(item->type() == ContactViewItem::Contact) item->contactProfile()->scActionDefault(item); } } else { //if(button == QListView::RightButton) { // qlv_contextPopup(i, pos, c); //} /*else*/if(button == Qt::LeftButton && PsiOptions::instance()->getOption("options.ui.contactlist.use-single-click").toBool()) { if(item->type() == ContactViewItem::Contact) item->contactProfile()->scActionDefault(item); } } } //d->typeAhead = ""; } void ContactView::qlv_doubleclick(Q3ListViewItem *i) { lcto_active = false; if(!i) return; if(PsiOptions::instance()->getOption("options.ui.contactlist.use-single-click").toBool()) return; ContactViewItem *item = (ContactViewItem *)i; item->contactProfile()->scActionDefault(item); //d->typeAhead = ""; } void ContactView::qlv_itemRenamed(Q3ListViewItem *lvi, int, const QString &text) { ContactViewItem *i = (ContactViewItem *)lvi; i->contactProfile()->doItemRenamed(i, text); } void ContactView::leftClickTimeOut() { if(lcto_active) { qlv_contextPopup(lcto_item, lcto_pos, 0); lcto_active = false; } } void ContactView::optionsUpdate() { // set the font QFont f; f.fromString(PsiOptions::instance()->getOption("options.ui.look.font.contactlist").toString()); Q3ListView::setFont(f); // set the text and background colors QPalette mypal = Q3ListView::palette(); mypal.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.online").value<QColor>()); mypal.setColor(QColorGroup::Base, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.background").value<QColor>()); Q3ListView::setPalette(mypal); // reload the icons Q3ListViewItemIterator it(this); ContactViewItem *item; for(; it.current() ; ++it) { item = (ContactViewItem *)it.current(); item->optionsUpdate(); } // shortcuts setShortcuts(); // resize if necessary if (PsiOptions::instance()->getOption("options.ui.contactlist.automatically-resize-roster").toBool()) recalculateSize(); update(); } void ContactView::setShortcuts() { qa_send->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.message")); qa_ren->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.rename")); qa_assignAvatar->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.assign-custom-avatar")); qa_clearAvatar->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.clear-custom-avatar")); qa_chat->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.chat")); qa_hist->setShortcuts(ShortcutManager::instance()->shortcuts("common.history")); qa_logon->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.login-transport")); qa_recv->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.event")); qa_rem->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.delete")); qa_vcard->setShortcuts(ShortcutManager::instance()->shortcuts("common.user-info")); } void ContactView::resetAnim() { for(Q3ListViewItemIterator it(this); it.current() ; ++it) { ContactViewItem *item = (ContactViewItem *)it.current(); if(item->isAlerting()) item->resetAnim(); } } void ContactView::doRecvEvent() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scRecvEvent(i); } void ContactView::doRename() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scRename(i); } void ContactView::doAssignAvatar() { // FIXME: Should check the supported filetypes dynamically QString file = QFileDialog::getOpenFileName(this, tr("Choose an Image"), "", tr("All files (*.png *.jpg *.gif)")); if (!file.isNull()) { ContactViewItem *i = (ContactViewItem *)selectedItem(); i->contactProfile()->psiAccount()->avatarFactory()->importManualAvatar(i->u()->jid(),file); } } void ContactView::doClearAvatar() { ContactViewItem *i = (ContactViewItem *)selectedItem(); i->contactProfile()->psiAccount()->avatarFactory()->removeManualAvatar(i->u()->jid()); } void ContactView::doEnter() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scActionDefault(i); } void ContactView::doContext() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; ensureItemVisible(i); if(i->type() == ContactViewItem::Group) setOpen(i, !i->isOpen()); else qlv_contextPopup(i, viewport()->mapToGlobal(QPoint(32, itemPos(i))), 0); } void ContactView::doSendMessage() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scSendMessage(i); } void ContactView::doOpenChat() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scOpenChat(i); } #ifdef WHITEBOARDING void ContactView::doOpenWhiteboard() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scOpenWhiteboard(i); } #endif void ContactView::doHistory() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scHistory(i); } void ContactView::doVCard() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scVCard(i); } void ContactView::doLogon() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; Status s=i->contactProfile()->psiAccount()->status(); i->contactProfile()->scAgentSetStatus(i, s); } void ContactView::doRemove() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return; i->contactProfile()->scRemove(i); } Q3DragObject *ContactView::dragObject() { ContactViewItem *i = (ContactViewItem *)selectedItem(); if(!i) return 0; if(i->type() != ContactViewItem::Contact) return 0; Q3DragObject *d = new Q3TextDrag(i->u()->jid().full(), this); d->setPixmap(IconsetFactory::iconPixmap("status/online"), QPoint(8,8)); return d; } bool ContactView::allowResize() const { if ( !PsiOptions::instance()->getOption("options.ui.contactlist.automatically-resize-roster").toBool() ) return false; if ( window()->isMaximized() ) return false; return true; } QSize ContactView::minimumSizeHint() const { return QSize( minimumWidth(), minimumHeight() ); } QSize ContactView::sizeHint() const { // save some CPU if ( !allowResize() ) return minimumSizeHint(); QSize s( Q3ListView::sizeHint().width(), 0 ); int border = 5; int h = border; Q3ListView *listView = (Q3ListView *)this; Q3ListViewItemIterator it( listView ); while ( it.current() ) { if ( it.current()->isVisible() ) { // also we need to check whether the group is open or closed bool show = true; Q3ListViewItem *item = it.current()->parent(); while ( item ) { if ( !item->isOpen() ) { show = false; break; } item = item->parent(); } if ( show ) h += it.current()->height(); } ++it; } QWidget *topParent = window(); QRect desktop = qApp->desktop()->availableGeometry( (QWidget *)topParent ); int dh = h - d->lastSize.height(); // check that our dialog's height doesn't exceed the desktop's if ( allowResize() && dh > 0 && (topParent->frameGeometry().height() + dh) >= desktop.height() ) { h = desktop.height() - ( topParent->frameGeometry().height() - d->lastSize.height() ); } int minH = minimumSizeHint().height(); if ( h < minH ) h = minH + border; s.setHeight( h ); return s; } /* * \brief Adds the request to recalculate the ContactView size to the event queue */ void ContactView::recalculateSize() { d->recalculateSizeTimer->start( 0, true ); } //------------------------------------------------------------------------------ // RichListViewItem: A RichText listview item //------------------------------------------------------------------------------ #include <q3simplerichtext.h> #include <qpainter.h> static const int icon_vpadding = 2; RichListViewStyleSheet::RichListViewStyleSheet(QObject* parent, const char * name) : Q3StyleSheet(parent, name) { } RichListViewStyleSheet* RichListViewStyleSheet::instance() { if (!instance_) instance_ = new RichListViewStyleSheet(); return instance_; } void RichListViewStyleSheet::scaleFont(QFont& font, int logicalSize) const { int size = font.pointSize() + (logicalSize - 3)*2; if (size > 0) font.setPointSize(size); else font.setPointSize(1); } RichListViewStyleSheet* RichListViewStyleSheet::instance_ = 0; RichListViewItem::RichListViewItem( Q3ListView * parent ) : Q3ListViewItem(parent) { v_rt = 0; v_active = v_selected = false; v_rich = !PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool(); } RichListViewItem::RichListViewItem( Q3ListViewItem * parent ) : Q3ListViewItem(parent) { v_rt = 0; v_active = v_selected = false; v_rich = !PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool(); } RichListViewItem::~RichListViewItem() { delete v_rt; } void RichListViewItem::setText(int column, const QString& text) { Q3ListViewItem::setText(column, text); setup(); } void RichListViewItem::setup() { Q3ListViewItem::setup(); if (v_rich) { int h = height(); QString txt = text(0); if( txt.isEmpty() ){ delete v_rt; v_rt = 0; return; } const Q3ListView* lv = listView(); const QPixmap* px = pixmap(0); int left = lv->itemMargin() + ((px)?(px->width() + lv->itemMargin()):0); v_active = lv->isActiveWindow(); v_selected = isSelected(); if ( v_selected ) { txt = QString("<font color=\"%1\">").arg(listView()->colorGroup().color( QColorGroup::HighlightedText ).name()) + txt + "</font>"; } if(v_rt) delete v_rt; v_rt = new Q3SimpleRichText(txt, lv->font(), QString::null, RichListViewStyleSheet::instance()); v_rt->setWidth(lv->columnWidth(0) - left - depth() * lv->treeStepSize()); v_widthUsed = v_rt->widthUsed() + left; h = QMAX( h, v_rt->height() ); if ( h % 2 > 0 ) h++; setHeight( h ); } } void RichListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align) { if(!v_rt){ Q3ListViewItem::paintCell(p, cg, column, width, align); return; } p->save(); Q3ListView* lv = listView(); if ( isSelected() != v_selected || lv->isActiveWindow() != v_active) setup(); int r = lv->itemMargin(); const QBrush *paper; // setup (colors, sizes, ...) if ( isSelected() ) { paper = new QBrush(cg.brush( QColorGroup::Highlight )); } else{ #if QT_VERSION >= 0x040103 paper = new QBrush(cg.background(), Qt::NoBrush); #else paper = new QBrush(cg.brush( QColorGroup::WindowText )); #endif } const QPixmap * px = pixmap( column ); QRect pxrect; int pxw = 0; int pxh = 0; if(px) { pxw = px->width(); pxh = px->height(); pxrect = QRect(r, icon_vpadding, pxw, pxh); r += pxw + lv->itemMargin(); } //if(px) // pxrect.moveTop((height() - pxh)/2); // start drawing QRect rtrect(r, (height() - v_rt->height())/2, v_widthUsed, v_rt->height()); v_rt->draw(p, rtrect.left(), rtrect.top(), rtrect, cg, paper); QRegion clip(0, 0, width, height()); clip -= rtrect; p->setClipRegion(clip); p->fillRect( 0, 0, width, height(), *paper ); if(px) p->drawPixmap(pxrect, *px); p->restore(); delete paper; } int RichListViewItem::widthUsed() { return v_widthUsed; } //---------------------------------------------------------------------------- // ContactViewItem //---------------------------------------------------------------------------- class ContactViewItem::Private { private: ContactViewItem *cvi; public: Private(ContactViewItem *parent, ContactProfile *_cp) { cvi = parent; cp = _cp; u = 0; animateNickColor = false; icon = lastIcon = 0; prefilterOpen = cvi->isOpen(); } ~Private() { } void initGroupState() { UserAccount::GroupData gd = groupData(); cvi->setOpen(gd.open); } QString getGroupName() { QString group; if ( cvi->type() == Profile ) group = "/\\/" + profileName + "\\/\\"; else group = groupName; return group; } QMap<QString, UserAccount::GroupData> *groupState() { return (QMap<QString, UserAccount::GroupData> *)&cp->psiAccount()->userAccount().groupState; } UserAccount::GroupData groupData() { QMap<QString, UserAccount::GroupData> groupState = (QMap<QString, UserAccount::GroupData>)cp->psiAccount()->userAccount().groupState; QMap<QString, UserAccount::GroupData>::Iterator it = groupState.find(getGroupName()); UserAccount::GroupData gd; gd.open = true; gd.rank = 0; if ( it != groupState.end() ) gd = it.data(); return gd; } ContactProfile *cp; int status; // profiles QString profileName; bool ssl; // groups int groupType; QString groupName; QString groupInfo; // contact UserListItem *u; bool isAgent; bool alerting; bool animatingNick; bool status_single; PsiIcon *icon, *lastIcon; int animateNickX, animateNickColor; // nick animation bool prefilterOpen; }; ContactViewItem::ContactViewItem(const QString &profileName, ContactProfile *cp, ContactView *parent) :RichListViewItem(parent) { type_ = Profile; d = new Private(this, cp); d->profileName = profileName; d->alerting = false; d->ssl = false; d->status_single = !PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool(); setProfileState(STATUS_OFFLINE); if (!PsiOptions::instance()->getOption("options.ui.account.single").toBool()) setText(0, profileName); d->initGroupState(); } ContactViewItem::ContactViewItem(const QString &groupName, int groupType, ContactProfile *cp, ContactView *parent) :RichListViewItem(parent) { type_ = Group; d = new Private(this, cp); d->groupName = groupName; d->groupType = groupType; d->alerting = false; d->status_single = !PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool(); drawGroupIcon(); resetGroupName(); setDropEnabled(true); d->initGroupState(); } ContactViewItem::ContactViewItem(const QString &groupName, int groupType, ContactProfile *cp, ContactViewItem *parent) :RichListViewItem(parent) { type_ = Group; d = new Private(this, cp); d->groupName = groupName; d->groupType = groupType; d->alerting = false; d->status_single = !PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool(); drawGroupIcon(); resetGroupName(); setDropEnabled(true); if(!parent->isVisible()) setVisible(false); d->initGroupState(); } ContactViewItem::ContactViewItem(UserListItem *u, ContactProfile *cp, ContactViewItem *parent) :RichListViewItem(parent) { type_ = Contact; d = new Private(this, cp); d->cp = cp; d->u = u; d->alerting = false; d->animatingNick = false; d->status_single = !PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.single-line").toBool(); cacheValues(); resetStatus(); resetName(); setDragEnabled(true); setDropEnabled(true); if(!parent->isVisible()) setVisible(false); else setup(); } ContactViewItem::~ContactViewItem() { setIcon( 0 ); delete d; } void ContactViewItem::cacheValues() { if ( d->u ) { if( !d->u->isAvailable() ) d->status = STATUS_OFFLINE; else d->status = makeSTATUS((*d->u->priority()).status()); d->isAgent = d->u->isTransport(); } } ContactProfile *ContactViewItem::contactProfile() const { return d->cp; } int ContactViewItem::type() const { return type_; } const QString & ContactViewItem::groupName() const { return d->groupName; } const QString & ContactViewItem::groupInfo() const { return d->groupInfo; } int ContactViewItem::groupType() const { return d->groupType; } UserListItem *ContactViewItem::u() const { return d->u; } int ContactViewItem::status() const { return d->status; } bool ContactViewItem::isAgent() const { return d->isAgent; } bool ContactViewItem::isAlerting() const { return d->alerting; } bool ContactViewItem::isAnimatingNick() const { return d->animatingNick; } int ContactViewItem::parentGroupType() const { ContactViewItem *item = (ContactViewItem *)Q3ListViewItem::parent(); return item->groupType(); } void ContactViewItem::drawGroupIcon() { if ( type_ == Group ) { if ( childCount() == 0 ) setIcon(IconsetFactory::iconPtr("psi/groupEmpty")); else if ( isOpen() ) setIcon(IconsetFactory::iconPtr("psi/groupOpen")); else setIcon(IconsetFactory::iconPtr("psi/groupClosed")); } else if ( type_ == Profile ) { if ( !d->alerting ) setProfileState(d->status); } } void ContactViewItem::paintFocus(QPainter *, const QColorGroup &, const QRect &) { // re-implimented to do nothing. selection is enough of a focus } void ContactViewItem::paintBranches(QPainter *p, const QColorGroup &cg, int w, int, int h) { // paint a square of nothing p->fillRect(0, 0, w, h, cg.base()); } void ContactViewItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int alignment) { if ( type_ == Contact ) { QColorGroup xcg = cg; if(d->status == STATUS_AWAY || d->status == STATUS_XA) xcg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.away").value<QColor>()); else if(d->status == STATUS_DND) xcg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.do-not-disturb").value<QColor>()); else if(d->status == STATUS_OFFLINE) xcg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status.offline").value<QColor>()); if(d->animatingNick) { xcg.setColor(QColorGroup::Text, d->animateNickColor ? PsiOptions::instance()->getOption("options.ui.look.contactlist.status-change-animation.color1").value<QColor>() : PsiOptions::instance()->getOption("options.ui.look.contactlist.status-change-animation.color2").value<QColor>()); xcg.setColor(QColorGroup::HighlightedText, d->animateNickColor ? PsiOptions::instance()->getOption("options.ui.look.contactlist.status-change-animation.color1").value<QColor>() : PsiOptions::instance()->getOption("options.ui.look.contactlist.status-change-animation.color2").value<QColor>()); } RichListViewItem::paintCell(p, xcg, column, width, alignment); int x; if (d->status_single) x = widthUsed(); else { QFontMetrics fm(p->font()); const QPixmap *pix = pixmap(column); x = fm.width(text(column)) + (pix ? pix->width() : 0) + 8; } if ( d->u ) { UserResourceList::ConstIterator it = d->u->priority(); if(it != d->u->userResourceList().end()) { if(d->u->isSecure((*it).name())) { const QPixmap &pix = IconsetFactory::iconPixmap("psi/cryptoYes"); int y = (height() - pix.height()) / 2; p->drawPixmap(x, y, pix); x += 24; } } } } else if ( type_ == Group || type_ == Profile ) { QColorGroup xcg = cg; if(type_ == Profile) { xcg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.profile.header-foreground").value<QColor>()); #if QT_VERSION < 0x040301 xcg.setColor(QColorGroup::Background, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.profile.header-background").value<QColor>()); #else xcg.setColor(QColorGroup::Base, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.profile.header-background").value<QColor>()); #endif } else if(type_ == Group) { QFont f = p->font(); f.setPointSize(common_smallFontSize); p->setFont(f); xcg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-foreground").value<QColor>()); if (!PsiOptions::instance()->getOption("options.ui.look.contactlist.use-slim-group-headings").toBool()) { #if QT_VERSION < 0x040301 xcg.setColor(QColorGroup::Background, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value<QColor>()); #else xcg.setColor(QColorGroup::Base, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value<QColor>()); #endif } } Q3ListViewItem::paintCell(p, xcg, column, width, alignment); QFontMetrics fm(p->font()); const QPixmap *pix = pixmap(column); int x = fm.width(text(column)) + (pix ? pix->width() : 0) + 8; if(type_ == Profile) { const QPixmap &pix = d->ssl ? IconsetFactory::iconPixmap("psi/cryptoYes") : IconsetFactory::iconPixmap("psi/cryptoNo"); int y = (height() - pix.height()) / 2; p->drawPixmap(x, y, pix); x += 24; } if(isSelected()) p->setPen(xcg.highlightedText()); else p->setPen(xcg.text()); QFont f_info = p->font(); f_info.setPointSize(common_smallFontSize); p->setFont(f_info); QFontMetrics fm_info(p->font()); //int info_x = width - fm_info.width(d->groupInfo) - 8; int info_x = x; int info_y = ((height() - fm_info.height()) / 2) + fm_info.ascent(); p->drawText((info_x > x ? info_x : x), info_y, d->groupInfo); if(type_ == Group && PsiOptions::instance()->getOption("options.ui.look.contactlist.use-slim-group-headings").toBool() && !isSelected()) { x += fm.width(d->groupInfo) + 8; if(x < width - 8) { int h = (height() / 2) - 1; p->setPen(QPen(PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value<QColor>())); p->drawLine(x, h, width - 8, h); h++; p->setPen(QPen(PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-foreground").value<QColor>())); /*int h = height() / 2; p->setPen(QPen(PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value<QColor>(), 2));*/ p->drawLine(x, h, width - 8, h); } } else { if (PsiOptions::instance()->getOption("options.ui.look.contactlist.use-outlined-group-headings").toBool()) { p->setPen(QPen(PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-foreground").value<QColor>())); p->drawRect(0, 0, width, height()); } } } } /* * \brief "Opens" or "closes the ContactViewItem * * When the item is in "open" state, all it's children items are visible. * * \param o - if true, the item will be "open" */ void ContactViewItem::setOpen(bool o) { ((ContactView *)listView())->recalculateSize(); Q3ListViewItem::setOpen(o); drawGroupIcon(); if (!((ContactView *)listView())->isApplyingFilter()) { d->prefilterOpen = o; // save state UserAccount::GroupData gd = d->groupData(); gd.open = o; d->groupState()->insert(d->getGroupName(), gd); } } void ContactViewItem::insertItem(Q3ListViewItem *i) { Q3ListViewItem::insertItem(i); drawGroupIcon(); } void ContactViewItem::takeItem(Q3ListViewItem *i) { Q3ListViewItem::takeItem(i); drawGroupIcon(); } int ContactViewItem::rankGroup(int groupType) const { static int rankgroups[5] = { gGeneral, gUser, gPrivate, gAgents, gNotInList, }; int n; for(n = 0; n < (int)sizeof(rankgroups); ++n) { if(rankgroups[n] == groupType) break; } if(n == sizeof(rankgroups)) return sizeof(rankgroups)-1; return n; } int ContactViewItem::compare(Q3ListViewItem *lvi, int, bool) const { ContactViewItem *i = (ContactViewItem *)lvi; int ret = 0; if(type_ == Contact) { // contacts always go before groups if(i->type() == Group) ret = -1; else { if ( PsiOptions::instance()->getOption("options.ui.contactlist.contact-sort-style").toString() == "status" ) { ret = rankStatus(d->status) - rankStatus(i->status()); if(ret == 0) ret = text(0).lower().localeAwareCompare(i->text(0).lower()); } else { // ContactSortStyle_Alpha ret = text(0).lower().localeAwareCompare(i->text(0).lower()); } } } else if(type_ == Group || type_ == Profile) { // contacts always go before groups if(i->type() == Contact) ret = 1; else if(i->type() == Group) { if ( PsiOptions::instance()->getOption("options.ui.contactlist.group-sort-style").toString() == "rank") { int ourRank = d->groupData().rank; int theirRank = i->d->groupData().rank; ret = ourRank - theirRank; } else { // GroupSortStyle_Alpha ret = rankGroup(d->groupType) - rankGroup(i->groupType()); if(ret == 0) ret = text(0).lower().localeAwareCompare(i->text(0).lower()); } } else if(i->type() == Profile) { if ( PsiOptions::instance()->getOption("options.ui.contactlist.account-sort-style").toString() == "rank" ) { int ourRank = d->groupData().rank; int theirRank = i->d->groupData().rank; ret = ourRank - theirRank; } else // AccountSortStyle_Alpha ret = text(0).lower().localeAwareCompare(i->text(0).lower()); } } return ret; } void ContactViewItem::setProfileName(const QString &name) { d->profileName = name; if (!PsiOptions::instance()->getOption("options.ui.account.single").toBool()) setText(0, d->profileName); else setText(0, ""); } void ContactViewItem::setProfileState(int status) { if ( status == -1 ) { setAlert( IconsetFactory::iconPtr("psi/connect") ); } else { d->status = status; clearAlert(); setIcon(PsiIconset::instance()->statusPtr(status)); } } void ContactViewItem::setProfileSSL(bool on) { d->ssl = on; repaint(); } void ContactViewItem::setGroupName(const QString &name) { d->groupName = name; resetGroupName(); updatePosition(); } void ContactViewItem::setGroupInfo(const QString &info) { d->groupInfo = info; repaint(); } void ContactViewItem::resetStatus() { if ( !d->alerting && d->u ) { setIcon(PsiIconset::instance()->statusPtr(d->u)); } // If the status is shown, update the text of the item too if (static_cast<ContactView*>(Q3ListViewItem::listView())->isShowStatusMsg()) resetName(); } void ContactViewItem::resetName(bool forceNoStatusMsg) { if ( d->u ) { QString s = JIDUtil::nickOrJid(d->u->name(), d->u->jid().full()); if (d->status_single && !forceNoStatusMsg) { s = "<nobr>" + TextUtil::plain2rich(s) + "</nobr>"; } // Add the status message if wanted if (!forceNoStatusMsg && static_cast<ContactView*>(Q3ListViewItem::listView())->isShowStatusMsg()) { QString statusMsg; if (d->u->priority() != d->u->userResourceList().end()) { statusMsg = (*d->u->priority()).status().status(); } else { statusMsg = d->u->lastUnavailableStatus().status(); } if (d->status_single) { statusMsg = statusMsg.simplifyWhiteSpace(); if (!statusMsg.isEmpty()) { s += "<br><font size=-1 color='" + PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.status-messages").value<QColor>().name() + "'><nobr>" + TextUtil::plain2rich(statusMsg) + "</nobr></font>"; } } else { if (!statusMsg.isEmpty()) { statusMsg.replace('\n'," "); s += " (" + statusMsg + ")"; } } } if ( s != text(0) ) { setText(0, s); } } } void ContactViewItem::resetGroupName() { if ( d->groupName != text(0) ) setText(0, d->groupName); } void ContactViewItem::resetAnim() { if ( d->alerting ) { // TODO: think of how to reset animation frame } } void ContactViewItem::setAlert(const PsiIcon *icon) { bool reset = false; if ( !d->alerting ) { d->alerting = true; reset = true; } else { if ( d->lastIcon != icon ) reset = true; } if ( reset ) setIcon(icon, true); } void ContactViewItem::clearAlert() { if ( d->alerting ) { d->alerting = false; //disconnect(static_cast<ContactView*>(QListViewItem::listView())->animTimer(), SIGNAL(timeout()), this, SLOT(animate())); resetStatus(); } } void ContactViewItem::setIcon(const PsiIcon *icon, bool alert) { if ( d->lastIcon == icon ) { return; // cause less flicker. but still have to run calltree valgring skin on psi while online (mblsha). } else d->lastIcon = (PsiIcon *)icon; if ( d->icon ) { disconnect(d->icon, 0, this, 0 ); d->icon->stop(); delete d->icon; d->icon = 0; } QPixmap pix; if ( icon ) { if ( !alert ) d->icon = new PsiIcon(*icon); else d->icon = new AlertIcon(icon); if (!PsiOptions::instance()->getOption("options.ui.contactlist.temp-no-roster-animation").toBool()) { connect(d->icon, SIGNAL(pixmapChanged()), SLOT(iconUpdated())); } d->icon->activated(); pix = d->icon->pixmap(); } setPixmap(0, pix); } void ContactViewItem::iconUpdated() { setPixmap(0, d->icon ? d->icon->pixmap() : QPixmap()); } void ContactViewItem::animateNick() { d->animateNickColor = !d->animateNickColor; repaint(); if(++d->animateNickX >= 16) stopAnimateNick(); } void ContactViewItem::stopAnimateNick() { if ( !d->animatingNick ) return; disconnect(static_cast<ContactView*>(Q3ListViewItem::listView())->animTimer(), SIGNAL(timeout()), this, SLOT(animateNick())); d->animatingNick = false; repaint(); } void ContactViewItem::setAnimateNick() { stopAnimateNick(); connect(static_cast<ContactView*>(Q3ListViewItem::listView())->animTimer(), SIGNAL(timeout()), SLOT(animateNick())); d->animatingNick = true; d->animateNickX = 0; animateNick(); } void ContactViewItem::updatePosition() { ContactViewItem *par = (ContactViewItem *)Q3ListViewItem::parent(); if(!par) return; ContactViewItem *after = 0; for(Q3ListViewItem *i = par->firstChild(); i; i = i->nextSibling()) { ContactViewItem *item = (ContactViewItem *)i; // skip self if(item == this) continue; int x = compare(item, 0, true); if(x == 0) continue; if(x < 0) break; after = item; } if(after) moveItem(after); else { Q3ListViewItem *i = par->firstChild(); moveItem(i); i->moveItem(this); } } void ContactViewItem::optionsUpdate() { if(type_ == Group || type_ == Profile) { drawGroupIcon(); } else if(type_ == Contact) { if(!d->alerting) resetStatus(); else resetAnim(); } } void ContactViewItem::setContact(UserListItem *u) { int oldStatus = d->status; QString oldName = text(0); bool wasAgent = d->isAgent; //QString newName = JIDUtil::nickOrJid(u->name(),u->jid().full()); d->u = u; cacheValues(); bool needUpdate = false; if(d->status != oldStatus || d->isAgent != wasAgent || !u->presenceError().isEmpty()) { resetStatus(); needUpdate = true; } // Hack, but that's the safest way. resetName(); QString newName = text(0); if(newName != oldName) { needUpdate = true; } if(needUpdate) updatePosition(); repaint(); setup(); } bool ContactViewItem::acceptDrop(const QMimeSource *m) const { if ( type_ == Profile ) return false; else if ( type_ == Group ) { if(d->groupType != gGeneral && d->groupType != gUser) return false; } else if ( type_ == Contact ) { if ( d->u && d->u->isSelf() ) return false; ContactViewItem *par = (ContactViewItem *)Q3ListViewItem::parent(); if(par->groupType() != gGeneral && par->groupType() != gUser) return false; } // Files. Note that the QTextDrag test has to come after QUriDrag. if (type_ == Contact && Q3UriDrag::canDecode(m)) { QStringList l; if (Q3UriDrag::decodeLocalFiles(m,l) && !l.isEmpty()) return true; } if(!Q3TextDrag::canDecode(m)) return false; QString str; if(!Q3TextDrag::decode(m, str)) return false; return true; } void ContactViewItem::dragEntered() { //printf("entered\n"); } void ContactViewItem::dragLeft() { //printf("left\n"); } void ContactViewItem::dropped(QDropEvent *i) { if(!acceptDrop(i)) return; // Files if (Q3UriDrag::canDecode(i)) { QStringList l; if (Q3UriDrag::decodeLocalFiles(i,l) && !l.isEmpty()) { d->cp->dragDropFiles(l, this); return; } } // Text if(Q3TextDrag::canDecode(i)) { QString text; if(Q3TextDrag::decode(i, text)) d->cp->dragDrop(text, this); } } void ContactViewItem::cancelRename (int i) { Q3ListViewItem::cancelRename(i); resetName(); } void ContactViewItem::clearFilter() { if (d->prefilterOpen != isOpen()) { setOpen(d->prefilterOpen); // if closing group that contains selected subitem, select this group if (d->prefilterOpen == false) { bool containsSelection = false; Q3ListViewItem* i = listView()->selectedItem(); while (i) { if (i == this) { containsSelection = true; break; } i = i->parent(); } if (containsSelection) { listView()->setSelected(this, true); } } } } int ContactViewItem::rtti() const { return 5103; } #include "contactview.moc" ���������������������������������������������������������psi-0.14/src/chateditproxy.cpp����������������������������������������������������������������������0000644�0001750�0001750�00000006340�11305557613�014526� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * chateditproxy.cpp - abstraction to change ChatEdit type in runtime * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "chateditproxy.h" #include <QVBoxLayout> #include "msgmle.h" #include "psioptions.h" ChatEditProxy::ChatEditProxy(QWidget* parent) : QWidget(parent) , lineEditEnabled_(false) , textEdit_(0) , layout_(0) { layout_ = new QVBoxLayout(this); layout_->setMargin(0); layout_->setSpacing(0); connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionsChanged())); optionsChanged(); if (!textEdit_) updateLayout(); } /** * If \a enable is true, then the LineEdit is used as internal * QTextEdit. Updates internal layout if necessary. */ void ChatEditProxy::setLineEditEnabled(bool enable) { if (lineEditEnabled_ == enable) return; lineEditEnabled_ = enable; updateLayout(); } /** * Creates new QTextEdit basing on ChatEditProxy's properties. */ ChatEdit* ChatEditProxy::createTextEdit() { if (lineEditEnabled()) return new LineEdit(this); return new ChatEdit(this); } /** * Moves the QTextDocument and QTextCursor data from \a oldTextEdit * to \a newTextEdit. * * NB: Make sure that all QSyntaxHighlighters are detached prior to calling * this function. */ void ChatEditProxy::moveData(QTextEdit* newTextEdit, QTextEdit* oldTextEdit) const { QTextDocument* doc = oldTextEdit->document(); QTextCursor cursor = oldTextEdit->textCursor(); doc->setParent(newTextEdit); oldTextEdit->setDocument(0); newTextEdit->setDocument(doc); newTextEdit->setTextCursor(cursor); } /** * Creates new QTextEdit and moves data to it from the old one. * Text, selection and cursor position are left intact. */ void ChatEditProxy::updateLayout() { ChatEdit* newEdit = createTextEdit(); if (textEdit_) { // all syntaxhighlighters should be removed while we move // the documents around, and should be reattached afterwards textEdit_->setCheckSpelling(false); newEdit->setCheckSpelling(false); moveData(newEdit, textEdit_); newEdit->setCheckSpelling(ChatEdit::checkSpellingGloballyEnabled()); } delete textEdit_; textEdit_ = newEdit; layout_->addWidget(textEdit_); emit textEditCreated(textEdit_); } /** * Update ChatEdit widget according to current options. * FIXME: When PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool() finally makes it to PsiOptions, make this slot * private. */ void ChatEditProxy::optionsChanged() { setLineEditEnabled(PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool()); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/httpauthmanager.cpp��������������������������������������������������������������������0000644�0001750�0001750�00000010244�11305557613�015031� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * httpauthmanager.cpp - Classes managing incoming HTTP-Auth requests * Copyright (C) 2006 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "httpauthmanager.h" #include "psihttpauthrequest.h" #include "xmpp_xmlcommon.h" #include "xmpp_task.h" #include "xmpp_client.h" #include "xmpp_message.h" #include "xmpp_stream.h" class HttpAuthListener : public XMPP::Task { Q_OBJECT public: HttpAuthListener(XMPP::Task *); bool take(const QDomElement &); void reply(bool confirm, const PsiHttpAuthRequest &); signals: void request(const PsiHttpAuthRequest&); }; HttpAuthListener::HttpAuthListener(XMPP::Task *parent) : XMPP::Task(parent) { } bool HttpAuthListener::take(const QDomElement &e) { QDomElement c = e.elementsByTagName("confirm").item(0).toElement(); // yes, of course, we need to check namespace, too // but it is impossible before calling addCorrectNS(), // which may be time/resources consuming // while this protocol is not so commonly used, // so it probably makes sense to do a "first guess" check like this if (c.isNull()) return false; XMPP::Stanza s = client()->stream().createStanza(addCorrectNS(e)); if(s.isNull()) return false; if (s.kind() == XMPP::Stanza::IQ && s.type() != "get") return false; // now really checking (with namespace) c = s.element().elementsByTagNameNS("http://jabber.org/protocol/http-auth", "confirm").item(0).toElement(); if (c.isNull()) return false; emit request(PsiHttpAuthRequest(XMPP::HttpAuthRequest(c), s)); return true; } void HttpAuthListener::reply(bool confirm, const PsiHttpAuthRequest &req) { const XMPP::Stanza &s = req.stanza(); if (s.kind() == XMPP::Stanza::Message) { XMPP::Message m(s.from()); if (!confirm) { m.setType("error"); m.setError(XMPP::HttpAuthRequest::denyError); } m.setHttpAuthRequest(req); QDomElement t = s.element().elementsByTagNameNS(s.baseNS(), "thread").item(0).toElement(); if (!t.isNull()) { m.setThread(t.text(), true); } //FIX-ME: it doesn't make sense to create Message object just to read the thread, does it? client()->sendMessage(m); } else { QDomElement e; e = createIQ(client()->doc(), confirm ? "result" : "error", s.from().full(), s.id()); e.appendChild(req.toXml(*client()->doc())); if (!confirm) { e.appendChild(XMPP::HttpAuthRequest::denyError.toXml(*client()->doc(), client()->stream().baseNS())); } send(e); } } /*! \class HttpAuthManager \brief Manages incoming JEP-0070 requests. HttpAuthManager instance sits on your client's root task and intercepts all incoming JEP-0070 confirmation requests. When new requests arrives, 'incoming' signal is raised. Important: Because this manager needs to intercept some message stanzas, it needs to be registered before standard message handler (JT_PushMessage), which is registered by Client::start(). */ /*! Creates new manager attached to \a root task. */ HttpAuthManager::HttpAuthManager(XMPP::Task *root) { listener_ = new HttpAuthListener(root); connect(listener_,SIGNAL(request(const PsiHttpAuthRequest&)),SIGNAL(confirmationRequest(const PsiHttpAuthRequest&))); } /*! Destroys the manager. */ HttpAuthManager::~HttpAuthManager() { // listener_ is deleted by root task, don't delete it here again! } /*! Confirm the \a request. */ void HttpAuthManager::confirm(const PsiHttpAuthRequest &request) { listener_->reply(true, request); } /*! Deny the \a request. */ void HttpAuthManager::deny(const PsiHttpAuthRequest &request) { listener_->reply(false, request); } #include "httpauthmanager.moc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psiaccount.h���������������������������������������������������������������������������0000644�0001750�0001750�00000031725�11305557613�013461� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psiaccount.h - handles a Psi account * Copyright (C) 2001-2005 Justin Karneges * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIACCOUNT_H #define PSIACCOUNT_H #include <QList> #include <QUrl> #include "xmpp_rosterx.h" #include "xmpp_status.h" #include "psiactions.h" namespace XMPP { class Jid; class XData; class AdvancedConnector; class Stream; class QCATLSHandler; class PubSubItem; class PubSubRetraction; class RosterItem; class Client; //class StreamError; class Resource; class Message; }; using namespace XMPP; class PsiCon; class PsiContactList; class PsiAccount; class PsiEvent; class PsiHttpAuthRequest; class Tune; class BookmarkManager; class URLBookmark; class ConferenceBookmark; class VoiceCaller; class CapsRegistry; class UserAccount; class ContactProfile; class QWidget; class QString; class EventQueue; class UserResource; class UserListItem; class UserList; class EventDlg; class ChatDlg; class PrivacyManager; class CapsManager; class EDB; class QSSLCert; class QHostAddress; class AvatarFactory; class PEPManager; class ServerInfoManager; class TabManager; #ifdef GOOGLE_FT class GoogleFileTransfer; #endif // sick sick remove this someday please! struct GCContact; class AvCallManager; class PsiAccount : public QObject { Q_OBJECT public: PsiAccount(const UserAccount &acc, PsiContactList *parent, CapsRegistry* capsRegistry, TabManager *tabManager); ~PsiAccount(); bool enabled() const; void setEnabled(bool e = TRUE); bool isAvailable() const; bool isActive() const; bool isConnected() const; const QString &name() const; const UserAccount & userAccount() const; UserAccount accountOptions() const; void setUserAccount(const UserAccount &); const Jid & jid() const; QString nameWithJid() const; XMPP::Client *client() const; ContactProfile *contactProfile() const; EventQueue *eventQueue() const; EDB *edb() const; PsiCon *psi() const; AvatarFactory *avatarFactory() const; PrivacyManager* privacyManager() const; CapsManager* capsManager() const; VoiceCaller* voiceCaller() const; Status status() const; void setStatusDirect(const Status &, bool withPriority = false); void setStatusActual(const Status &); void login(); void logout(bool fast=false, const Status &s = Status("", "Logged out", 0, false)); bool loggedIn() const; void setNick(const QString &); QString nick() const; bool hasPGP() const; QHostAddress *localAddress() const; ChatDlg* findChatDialog(const Jid& jid) const; template<typename T> inline T findDialog(const Jid& jid = Jid(), bool compareResource = true) const { return static_cast<T>(findDialog(((T)0)->staticMetaObject, jid, compareResource)); } template<typename T> inline QList<T> findDialogs(const Jid& jid = Jid(), bool compareResource = true) const { QList<T> list; findDialogs(((T)0)->staticMetaObject, jid, compareResource, reinterpret_cast<QList<void*>*>(&list)); return list; } void dialogRegister(QWidget* w, const Jid& jid = Jid()); void dialogUnregister(QWidget* w); void modify(); void changeVCard(); void changePW(); void changeStatus(int); void doDisco(); void showXmlConsole(); void openAddUserDlg(); void openAddUserDlg(const XMPP::Jid &jid, const QString &nick, const QString &group); void openGroupChat(const Jid &, ActivationType activationType); bool groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString& pass, bool nohistory = false); void groupChatSetStatus(const QString &host, const QString &room, const Status &); void groupChatChangeNick(const QString &host, const QString &room, const QString& nick, const Status &); void groupChatLeave(const QString &host, const QString &room); UserListItem *find(const Jid &) const; QList<UserListItem*> findRelevant(const Jid &) const; UserListItem *findFirstRelevant(const Jid &) const; UserList *userList() const; bool checkConnected(QWidget *parent=0); void playSound(const QString &); QStringList hiddenChats(const Jid &) const; int sendMessageEncrypted(const Message &); // sucks sucks sucks sucks sucks sucks sucks GCContact *findGCContact(const Jid &j); QStringList groupchats() const; void toggleSecurity(const Jid &, bool); bool ensureKey(const Jid &); void tryVerify(UserListItem *, UserResource *); static void getErrorInfo(int err, AdvancedConnector *conn, Stream *stream, QCATLSHandler *tlsHandler, QString *_str, bool *_reconn); void deleteQueueFile(); void sendFiles(const Jid&, const QStringList&, bool direct = false); PEPManager* pepManager(); ServerInfoManager* serverInfoManager(); BookmarkManager* bookmarkManager(); AvCallManager *avCallManager(); enum xmlRingType {RingXmlIn, RingXmlOut, RingSysMsg}; class xmlRingElem { public: int type; QDateTime time; QString xml; }; QList< xmlRingElem > dumpRingbuf(); signals: void disconnected(); void reconnecting(); void updatedActivity(); void updatedAccount(); void queueChanged(); void updateContact(const UserListItem &); void updateContact(const Jid &); void updateContact(const Jid &, bool); void nickChanged(); void pgpKeyChanged(); void encryptedMessageSent(int, bool, int, const QString &); void enabledChanged(); void startBounce(); public slots: void setStatus(const XMPP::Status &, bool withStatus = false); void capsChanged(const Jid&); void tuneStopped(); void tunePlaying(const Tune&); void incomingVoiceCall(const Jid&); void secondsIdle(int); void openNextEvent(ActivationType activationType); int forwardPendingEvents(const Jid &jid); void autoLogin(); void showCert(); void openUri(const QUrl &uri); //dj_ originally referred to 'direct jabber', if you care void dj_sendMessage(const Message &, bool log=true); void dj_newMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread); void dj_replyMessage(const Jid &jid, const QString &body); void dj_replyMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread); void dj_addAuth(const Jid &); void dj_addAuth(const Jid &, const QString&); void dj_add(const XMPP::Jid &, const QString &, const QStringList &, bool authReq); void dj_authReq(const Jid &); void dj_auth(const Jid &); void dj_deny(const Jid &); void dj_rename(const Jid &, const QString &); void dj_remove(const Jid &); void dj_confirmHttpAuth(const PsiHttpAuthRequest &); void dj_denyHttpAuth(const PsiHttpAuthRequest &); void dj_rosterExchange(const RosterExchangeItems&); void dj_formSubmit(const XData&, const QString&, const Jid&); void dj_formCancel(const XData&, const QString&, const Jid&); void actionDefault(const Jid &); void actionRecvEvent(const Jid &); void actionRecvRosterExchange(const Jid&, const RosterExchangeItems&); void actionSendMessage(const Jid &); void actionSendMessage(const QList<XMPP::Jid> &); void actionSendUrl(const Jid &); void actionRemove(const Jid &); void actionRename(const Jid &, const QString &); void actionGroupRename(const QString &, const QString &); void actionHistory(const Jid &); void actionOpenChat(const Jid &); void actionOpenChat2(const Jid &); void actionOpenChatSpecific(const Jid &); #ifdef WHITEBOARDING void actionOpenWhiteboard(const Jid &); void actionOpenWhiteboardSpecific(const Jid &, Jid = Jid(), bool = false); #endif void actionAgentSetStatus(const Jid &, Status &s); void actionInfo(const Jid &, bool showStatusInfo=true); void actionAuth(const Jid &); void actionAuthRequest(const Jid &); void actionAuthRemove(const Jid &); void actionAdd(const Jid &); void actionGroupAdd(const Jid &, const QString &); void actionGroupRemove(const Jid &, const QString &); void actionHistoryBox(PsiEvent *); void actionRegister(const Jid &); void actionSearch(const Jid &); void actionJoin(const Jid& mucJid, const QString& password = QString()); void actionJoin(const ConferenceBookmark& bookmark, bool connectImmediately); void actionDisco(const Jid &, const QString &); void actionInvite(const Jid &, const QString &); void actionVoice(const Jid&); void actionSendFile(const Jid &); void actionSendFiles(const Jid &, const QStringList&); void actionExecuteCommand(const Jid& j, const QString& = QString()); void actionExecuteCommandSpecific(const Jid&, const QString& = QString()); void actionSetMood(); void actionSetAvatar(); void actionUnsetAvatar(); void featureActivated(QString feature, Jid jid, QString node); void actionAssignKey(const Jid &); void actionUnassignKey(const Jid &); void invokeGCMessage(const Jid &); void invokeGCChat(const Jid &); void invokeGCInfo(const Jid &); void invokeGCFile(const Jid &); private slots: void tls_handshaken(); void cs_connected(); void cs_securityLayerActivated(int); void cs_needAuthParams(bool, bool, bool); void cs_authenticated(); void cs_connectionClosed(); void cs_delayedCloseFinished(); void cs_warning(int); void cs_error(int); void client_rosterRequestFinished(bool, int, const QString &); void resolveContactName(); void client_rosterItemAdded(const RosterItem &); void client_rosterItemUpdated(const RosterItem &); void client_rosterItemRemoved(const RosterItem &); void client_resourceAvailable(const Jid &, const Resource &); void client_resourceUnavailable(const Jid &, const Resource &); void client_presenceError(const Jid &, int, const QString &); void client_messageReceived(const Message &); void client_subscription(const Jid &, const QString &, const QString&); void client_debugText(const QString &); void client_groupChatJoined(const Jid &); void client_groupChatLeft(const Jid &); void client_groupChatPresence(const Jid &, const Status &); void client_groupChatError(const Jid &, int, const QString &); #ifdef GOOGLE_FT void incomingGoogleFileTransfer(GoogleFileTransfer* ft); #endif void client_incomingFileTransfer(); void sessionStart_finished(); void serverFeaturesChanged(); void setPEPAvailable(bool); void bookmarksAvailabilityChanged(); void incomingHttpAuthRequest(const PsiHttpAuthRequest &); void reconnect(); void disconnect(); void enableNotifyOnline(); void itemPublished(const Jid&, const QString&, const PubSubItem&); void itemRetracted(const Jid&, const QString&, const PubSubRetraction&); void chatMessagesRead(const Jid &); void slotCheckVCard(); void edb_finished(); //void pgpToggled(bool); void pgpKeysUpdated(); void trySignPresence(); void pgp_signFinished(); void pgp_verifyFinished(); void pgp_encryptFinished(); void pgp_decryptFinished(); void optionsUpdate(); void processReadNext(const UserListItem &); void processReadNext(const Jid &); protected: bool validRosterExchangeItem(const RosterExchangeItem&); QString localHostName(); void publishTune(const Tune&); void setSendChatState(bool); void setRCEnabled(bool); void sessionStarted(); private slots: void eventFromXml(PsiEvent* e); private: void handleEvent(PsiEvent* e, ActivationType activationType); public: class Private; private: Private *d; void deleteAllDialogs(); void stateChanged(); void simulateContactOffline(UserListItem *); void simulateRosterOffline(); void cpUpdate(const UserListItem &, const QString &rname="", bool fromPresence=false); UserListItem* addUserListItem(const Jid& jid, const QString& nick=""); void logEvent(const Jid &, PsiEvent *); void queueEvent(PsiEvent* e, ActivationType activationType); void openNextEvent(const UserListItem &, ActivationType activationType); void updateReadNext(const Jid &); ChatDlg *ensureChatDlg(const Jid &); void lastStepLogin(); void processIncomingMessage(const Message &); void processEncryptedMessage(const Message &); void processMessageQueue(); void processEncryptedMessageNext(); void processEncryptedMessageDone(); void verifyStatus(const Jid &j, const Status &s); void processChats(const Jid &); void openChat(const Jid &, ActivationType activationType); EventDlg *ensureEventDlg(const Jid &); friend class PsiCon; bool isDisconnecting, notifyOnlineOk, doReconnect, rosterDone, presenceSent, v_isActive; void cleanupStream(); QWidget* findDialog(const QMetaObject& mo, const Jid& jid, bool compareResource) const; void findDialogs(const QMetaObject& mo, const Jid& jid, bool compareResource, QList<void*>* list) const; friend class Private; }; #endif �������������������������������������������psi-0.14/src/mcmdcompletion.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000002431�11305557613�014646� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see <http://www.gnu.org/licenses/>. * */ // tab completion helper for mini command system #include "mcmdcompletion.h" #include "minicmd.h" void MCmdTabCompletion::setup(QString str, int pos, int &start, int &end) { if (mgr_->isActive()) { mCmdList_ = mgr_->completeCommand(str, pos, start, end); } else { TabCompletion::setup(str, pos, start, end); } } QStringList MCmdTabCompletion::possibleCompletions() { if (mgr_->isActive()) { return mCmdList_; } return QStringList(); } QStringList MCmdTabCompletion::allChoices(QString &guess) { if (mgr_->isActive()) { guess = QString(); return mCmdList_; } return QStringList(); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/mucreasonseditor.h���������������������������������������������������������������������0000644�0001750�0001750�00000000674�11305557613�014676� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef MUCREASONSEDITOR_H #define MUCREASONSEDITOR_H #include <QDialog> #include "ui_mucreasonseditor.h" class MUCReasonsEditor: public QDialog { Q_OBJECT public: MUCReasonsEditor(QWidget* parent = 0); ~MUCReasonsEditor(); QString reason() const { return reason_; } private: Ui::MUCReasonsEditor ui_; QString reason_; private slots: void on_btnAdd_clicked(); void on_btnRemove_clicked(); protected slots: void accept(); }; #endif ��������������������������������������������������������������������psi-0.14/src/mcmdcompletion.h�����������������������������������������������������������������������0000644�0001750�0001750�00000002632�11305557613�014316� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see <http://www.gnu.org/licenses/>. * */ // tab completion helper for mini command system #ifndef MCMDCOMPLETION_H #define MCMDCOMPLETION_H #include "tabcompletion.h" class MCmdManagerIface; /** This class offers TabCompletion based completion support * for cases where only mini commands need to be completed */ class MCmdTabCompletion : public TabCompletion { public: /** Constructs an MCmdTabCompletion for getting completions from mini command * manager \a mgr. */ MCmdTabCompletion(MCmdManagerIface *mgr) : mgr_(mgr) {}; protected: virtual void setup(QString str, int pos, int &start, int &end); virtual QStringList possibleCompletions(); virtual QStringList allChoices(QString &guess); QStringList mCmdList_; MCmdManagerIface *mgr_; }; #endif ������������������������������������������������������������������������������������������������������psi-0.14/src/lastactivitytask.h���������������������������������������������������������������������0000644�0001750�0001750�00000002426�11305557613�014710� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * lastactivitytask.h * Copyright (C) 2006 Remko Troncon * * 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 2 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef LASTACTIVITYTASK_H #define LASTACTIVITYTASK_H #include <QDomElement> #include <QString> #include <QDateTime> #include "xmpp_task.h" #include "xmpp_jid.h" class LastActivityTask : public XMPP::Task { public: LastActivityTask(const XMPP::Jid&, Task*); void onGo(); bool take(const QDomElement &); const XMPP::Jid & jid() const; const QString& status() const; const QDateTime& time() const; private: QDomElement iq_; XMPP::Jid jid_; QDateTime last_time_; QString last_status_; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/bookmarkmanagedlg.h��������������������������������������������������������������������0000644�0001750�0001750�00000004115�11305557613�014747� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * bookmarkmanagedlg.h - manage groupchat room bookmarks * Copyright (C) 2008 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef BOOKMARKMANAGEDLG_H #define BOOKMARKMANAGEDLG_H #include <QDialog> #include "ui_bookmarkmanage.h" class PsiAccount; class QPushButton; class QStandardItemModel; class QStandardItem; class ConferenceBookmark; #include "xmpp_jid.h" class BookmarkManageDlg : public QDialog { Q_OBJECT public: BookmarkManageDlg(PsiAccount* account); ~BookmarkManageDlg(); public slots: // reimplemented void reject(); void accept(); private: enum Role { // DisplayRole / EditRole JidRole = Qt::UserRole + 0, AutoJoinRole = Qt::UserRole + 1, NickRole = Qt::UserRole + 2, PasswordRole = Qt::UserRole + 3 }; void loadBookmarks(); void saveBookmarks(); void appendItem(QStandardItem* item); XMPP::Jid jid() const; QModelIndex currentIndex() const; private slots: void addBookmark(); void removeBookmark(); void updateCurrentItem(); void joinCurrentRoom(); void closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint); void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); private: Ui::BookmarkManage ui_; PsiAccount* account_; QStandardItemModel* model_; QPushButton* addButton_; QPushButton* removeButton_; QPushButton* joinButton_; ConferenceBookmark bookmarkFor(const QModelIndex& index) const; }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/qwextend.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000011063�11305557613�013474� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "qwextend.h" #ifdef Q_WS_X11 #define protected public #define private public #include <qwidget.h> #undef protected #undef private #include <qcursor.h> #include <qobject.h> #include <qpixmap.h> #include <X11/Xlib.h> #include <X11/Xutil.h> // taken from qt/x11 (doing this sucks sucks sucks sucks sucks) void reparent_good(QWidget *that, Qt::WFlags f, bool showIt) { extern void qPRCreate( const QWidget *, Window ); extern void qt_XDestroyWindow( const QWidget *destroyer, Display *display, Window window ); extern bool qt_dnd_enable( QWidget* w, bool on ); QWidget *parent = 0; Display *dpy = that->x11Display(); QCursor oldcurs; bool setcurs = that->windowState(Qt::WState_OwnCursor); if ( setcurs ) { oldcurs = that->cursor(); that->unsetCursor(); } // dnd unregister (we will register again below) bool accept_drops = that->acceptDrops(); that->setAcceptDrops( false ); // clear mouse tracking, re-enabled below bool mouse_tracking = that->hasMouseTracking(); that->clearWState(Qt::WState_MouseTracking); QWidget* oldtlw = that->window(); QWidget *oldparent = that->parentWidget(); WId old_winid = that->winid; if ( that->windowFlags(Qt::WType_Desktop) ) old_winid = 0; that->setWinId( 0 ); // hide and reparent our own window away. Otherwise we might get // destroyed when emitting the child remove event below. See QWorkspace. XUnmapWindow( that->x11Display(), old_winid ); XReparentWindow( that->x11Display(), old_winid, RootWindow( that->x11Display(), that->x11Screen() ), 0, 0 ); if ( that->isTopLevel() ) { // input contexts are associated with toplevel widgets, so we need // destroy the context here. if we are reparenting back to toplevel, // then we will have another context created, otherwise we will // use our new toplevel's context that->destroyInputContext(); } if ( that->isTopLevel() || !parent ) // we are toplevel, or reparenting to toplevel that->topData()->parentWinId = 0; if ( parent != that->parentObj ) { if ( that->parentObj ) // remove from parent that->parentObj->removeChild( that ); if ( parent ) // insert into new parent parent->insertChild( that ); } bool enable = that->isEnabled(); // remember status Qt::FocusPolicy fp = that->focusPolicy(); QSize s = that->size(); QPixmap *bgp = (QPixmap *)that->backgroundPixmap(); QColor bgc = that->bg_col; // save colors QString capt= that->caption(); that->widget_flags = f; that->clearWState( Qt::WState_Created | Qt::WState_Visible | Qt::WState_ForceHide ); that->create(); if ( that->isTopLevel() || (!parent || parent->isVisible() ) ) that->setWState( Qt::WState_ForceHide ); // new widgets do not show up in already visible parents const QObjectList *chlist = that->children(); if ( chlist ) { // reparent children QObjectListIt it( *chlist ); QObject *obj; while ( (obj=it.current()) ) { if ( obj->isWidgetType() ) { QWidget *w = (QWidget *)obj; if ( !w->isTopLevel() ) { XReparentWindow( that->x11Display(), w->winId(), that->winId(), w->geometry().x(), w->geometry().y() ); } else if ( w->isPopup() || w->windowFlags(Qt::WStyle_DialogBorder) || w->windowFlags(Qt::WType_Dialog) || w->windowFlags(Qt::WStyle_Tool) ) { XSetTransientForHint( that->x11Display(), w->winId(), that->winId() ); } } ++it; } } qPRCreate( that, old_winid ); if ( bgp ) XSetWindowBackgroundPixmap( dpy, that->winid, bgp->handle() ); else XSetWindowBackground( dpy, that->winid, bgc.pixel(that->x11Screen()) ); // all this just to do a stupid resize instead of setGeometry //setGeometry( p.x(), p.y(), s.width(), s.height() ); that->resize(s.width(), s.height()); that->setEnabled( enable ); that->setFocusPolicy( fp ); if ( !capt.isNull() ) { that->extra->topextra->caption = QString::null; that->setWindowTitle( capt ); } if ( showIt ) that->show(); if ( old_winid ) qt_XDestroyWindow( that, dpy, old_winid ); if ( setcurs ) that->setCursor(oldcurs); that->reparentFocusWidgets( oldtlw ); // re-register dnd if (oldparent) oldparent->checkChildrenDnd(); if ( accept_drops ) that->setAcceptDrops( true ); else { that->checkChildrenDnd(); that->topData()->dnd = 0; qt_dnd_enable(that, (that->extra && that->extra->children_use_dnd)); } // re-enable mouse tracking if (mouse_tracking) that->setMouseTracking(mouse_tracking); } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/systeminfo.h���������������������������������������������������������������������������0000644�0001750�0001750�00000001145�11305557613�013502� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007-2008 Psi Development Team * Licensed under the GNU General Public License. * See the COPYING file for more information. */ #ifndef SYSTEMINFO_H #define SYSTEMINFO_H #include <QObject> #include <QString> class SystemInfo : public QObject { public: static SystemInfo* instance(); const QString& os() const { return os_str_; } int timezoneOffset() const { return timezone_offset_; } const QString& timezoneString() const { return timezone_str_; } private: SystemInfo(); static SystemInfo* instance_; int timezone_offset_; QString timezone_str_; QString os_str_; }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/textutil.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000031034�11305557613�013517� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QTextDocument> // for escape() #include "textutil.h" #include "psiiconset.h" #include "rtparse.h" // Qt::escape() doesn't escape " to " -- it sucks QString TextUtil::escape(const QString& plain) { QString rich; rich.reserve(int(plain.length() * 1.1)); for (int i = 0; i < plain.length(); ++i) { if (plain.at(i) == QLatin1Char('<')) rich += QLatin1String("<"); else if (plain.at(i) == QLatin1Char('>')) rich += QLatin1String(">"); else if (plain.at(i) == QLatin1Char('"')) rich += QLatin1String("""); else if (plain.at(i) == QLatin1Char('&')) rich += QLatin1String("&"); else rich += plain.at(i); } return rich; } QString TextUtil::unescape(const QString& escaped) { QString plain = escaped; plain.replace("<", "<"); plain.replace(">", ">"); plain.replace(""", "\""); plain.replace("&", "&"); return plain; } QString TextUtil::quote(const QString &toquote, int width, bool quoteEmpty) { int ql = 0, col = 0, atstart = 1, ls=0; QString quoted = "> "+toquote; // quote first line QString rxs = quoteEmpty ? "\n" : "\n(?!\\s*\n)"; QRegExp rx(rxs); // quote following lines quoted.replace(rx, "\n> "); rx.setPattern("> +>"); // compress > > > > quotes to >>>> quoted.replace(rx, ">>"); quoted.replace(rx, ">>"); quoted.replace(QRegExp(" +\n"), "\n"); // remove trailing spaces if (!quoteEmpty) { quoted.replace(QRegExp("^>+\n"), "\n\n"); // unquote empty lines quoted.replace(QRegExp("\n>+\n"), "\n\n"); } for (int i=0;i<(int) quoted.length();i++) { col++; if (atstart && quoted[i] == '>') ql++; else atstart=0; switch(quoted[i].toLatin1()) { case '\n': ql = col = 0; atstart = 1; break; case ' ': case '\t': ls = i; break; } if (quoted[i]=='\n') { ql=0; atstart = 1; } if (col > width) { if ((ls+width) < i) { ls = i; i = quoted.length(); while ((ls<i) && !quoted[ls].isSpace()) ls++; i = ls; } if ((i<(int)quoted.length()) && (quoted[ls] != '\n')) { quoted.insert(ls, '\n'); ++ls; quoted.insert(ls, QString().fill('>', ql)); i += ql+1; col = 0; } } } quoted += "\n\n";// add two empty lines to quoted text - the cursor // will be positioned at the end of those. return quoted; } QString TextUtil::plain2rich(const QString &plain) { QString rich; int col = 0; for(int i = 0; i < (int)plain.length(); ++i) { #ifdef Q_OS_WIN if(plain[i] == '\r' && i+1 < (int)plain.length() && plain[i+1] == '\n') ++i; // Qt/Win sees \r\n as two new line chars #endif if(plain[i] == '\n') { rich += "<br>"; col = 0; } else if(plain[i] == '<') rich += "<"; else if(plain[i] == '>') rich += ">"; else if(plain[i] == '\"') rich += """; else if(plain[i] == '\'') rich += "'"; else if(plain[i] == '&') rich += "&"; else rich += plain[i]; ++col; } return "<span style='white-space: pre-wrap'>" + rich + "</span>"; } QString TextUtil::rich2plain(const QString &in) { QString out; for(int i = 0; i < (int)in.length(); ++i) { // tag? if(in[i] == '<') { // find end of tag ++i; int n = in.indexOf('>', i); if(n == -1) break; QString str = in.mid(i, (n-i)); i = n; QString tagName; n = str.indexOf(' '); if(n != -1) tagName = str.mid(0, n); else tagName = str; if(tagName == "br") out += '\n'; // handle output of Qt::convertFromPlainText() correctly if((tagName == "p" || tagName == "/p") && out.length() > 0) out += '\n'; } // entity? else if(in[i] == '&') { // find a semicolon ++i; int n = in.indexOf(';', i); if(n == -1) break; QString type = in.mid(i, (n-i)); i = n; // should be n+1, but we'll let the loop increment do it if(type == "amp") out += '&'; else if(type == "lt") out += '<'; else if(type == "gt") out += '>'; else if(type == "quot") out += '\"'; else if(type == "apos") out += '\''; } else if(in[i].isSpace()) { if(in[i] == QChar::Nbsp) out += ' '; else if(in[i] != '\n') { if(i == 0 || out.length() == 0) out += ' '; else { QChar last = out.at(out.length()-1); bool ok = true; if(last.isSpace() && last != '\n') ok = false; if(ok) out += ' '; } } } else { out += in[i]; } } return out; } QString TextUtil::resolveEntities(const QString &in) { QString out; for(int i = 0; i < (int)in.length(); ++i) { if(in[i] == '&') { // find a semicolon ++i; int n = in.indexOf(';', i); if(n == -1) break; QString type = in.mid(i, (n-i)); i = n; // should be n+1, but we'll let the loop increment do it if(type == "amp") out += '&'; else if(type == "lt") out += '<'; else if(type == "gt") out += '>'; else if(type == "quot") out += '\"'; else if(type == "apos") out += '\''; } else { out += in[i]; } } return out; } static bool linkify_pmatch(const QString &str1, int at, const QString &str2) { if(str2.length() > (str1.length()-at)) return false; for(int n = 0; n < (int)str2.length(); ++n) { if(str1.at(n+at).toLower() != str2.at(n).toLower()) return false; } return true; } static bool linkify_isOneOf(const QChar &c, const QString &charlist) { for(int i = 0; i < (int)charlist.length(); ++i) { if(c == charlist.at(i)) return true; } return false; } // encodes a few dangerous html characters static QString linkify_htmlsafe(const QString &in) { QString out; for(int n = 0; n < in.length(); ++n) { if(linkify_isOneOf(in.at(n), "\"\'`<>")) { // hex encode QString hex; hex.sprintf("%%%02X", in.at(n).toLatin1()); out.append(hex); } else { out.append(in.at(n)); } } return out; } static bool linkify_okUrl(const QString &url) { if(url.at(url.length()-1) == '.') return false; return true; } static bool linkify_okEmail(const QString &addy) { // this makes sure that there is an '@' and a '.' after it, and that there is // at least one char for each of the three sections int n = addy.indexOf('@'); if(n == -1 || n == 0) return false; int d = addy.indexOf('.', n+1); if(d == -1 || d == 0) return false; if((addy.length()-1) - d <= 0) return false; if(addy.indexOf("..") != -1) return false; return true; } /** * takes a richtext string and heuristically adds links for uris of common protocols * @return a richtext string with link markup added */ QString TextUtil::linkify(const QString &in) { QString out = in; int x1, x2; bool isUrl, isEmail; QString linked, link, href; for(int n = 0; n < (int)out.length(); ++n) { isUrl = false; isEmail = false; x1 = n; if(linkify_pmatch(out, n, "xmpp:")) { n += 5; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "http://")) { n += 7; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "https://")) { n += 8; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "ftp://")) { n += 6; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "news://")) { n += 7; isUrl = true; href = ""; } else if (linkify_pmatch(out, n, "ed2k://")) { n += 7; isUrl = true; href = ""; } else if(linkify_pmatch(out, n, "www.")) { isUrl = true; href = "http://"; } else if(linkify_pmatch(out, n, "ftp.")) { isUrl = true; href = "ftp://"; } else if(linkify_pmatch(out, n, "@")) { isEmail = true; href = "mailto:"; } if(isUrl) { // make sure the previous char is not alphanumeric if(x1 > 0 && out.at(x1-1).isLetterOrNumber()) continue; // find whitespace (or end) QMap<QChar, int> brackets; brackets['('] = brackets[')'] = brackets['['] = brackets[']'] = brackets['{'] = brackets['}'] = 0; QMap<QChar, QChar> openingBracket; openingBracket[')'] = '('; openingBracket[']'] = '['; openingBracket['}'] = '{'; for(x2 = n; x2 < (int)out.length(); ++x2) { if(out.at(x2).isSpace() || linkify_isOneOf(out.at(x2), "\"\'`<>") || linkify_pmatch(out, x2, """) || linkify_pmatch(out, x2, "'") || linkify_pmatch(out, x2, ">") || linkify_pmatch(out, x2, "<") ) { break; } if(brackets.keys().contains(out.at(x2))) { ++brackets[out.at(x2)]; } } int len = x2-x1; QString pre = resolveEntities(out.mid(x1, x2-x1)); // go backward hacking off unwanted punctuation int cutoff; for(cutoff = pre.length()-1; cutoff >= 0; --cutoff) { if(!linkify_isOneOf(pre.at(cutoff), "!?,.()[]{}<>\"")) break; if(linkify_isOneOf(pre.at(cutoff), ")]}") && brackets[pre.at(cutoff)] - brackets[openingBracket[pre.at(cutoff)]] <= 0 ) { break; // in theory, there could be == above, but these are urls, not math ;) } if(brackets.keys().contains(pre.at(cutoff))) { --brackets[pre.at(cutoff)]; } } ++cutoff; //++x2; link = pre.mid(0, cutoff); if(!linkify_okUrl(link)) { n = x1 + link.length(); continue; } href += link; // attributes need to be encoded too. href = Qt::escape(href); href = linkify_htmlsafe(href); //printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1()); linked = QString("<a href=\"%1\">").arg(href) + Qt::escape(link) + "</a>" + Qt::escape(pre.mid(cutoff)); out.replace(x1, len, linked); n = x1 + linked.length() - 1; } else if(isEmail) { // go backward till we find the beginning if(x1 == 0) continue; --x1; for(; x1 >= 0; --x1) { if(!linkify_isOneOf(out.at(x1), "_.-") && !out.at(x1).isLetterOrNumber()) break; } ++x1; // go forward till we find the end x2 = n + 1; for(; x2 < (int)out.length(); ++x2) { if(!linkify_isOneOf(out.at(x2), "_.-") && !out.at(x2).isLetterOrNumber()) break; } int len = x2-x1; link = out.mid(x1, len); //link = resolveEntities(link); if(!linkify_okEmail(link)) { n = x1 + link.length(); continue; } href += link; //printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1()); linked = QString("<a href=\"%1\">").arg(href) + link + "</a>"; out.replace(x1, len, linked); n = x1 + linked.length() - 1; } } return out; } // sickening QString TextUtil::emoticonify(const QString &in) { RTParse p(in); while ( !p.atEnd() ) { // returns us the first chunk as a plaintext string QString str = p.next(); int i = 0; while ( i >= 0 ) { // find closest emoticon int ePos = -1; PsiIcon *closest = 0; int foundPos = -1, foundLen = -1; foreach(const Iconset* iconset, PsiIconset::instance()->emoticons) { QListIterator<PsiIcon*> it = iconset->iterator(); while ( it.hasNext()) { PsiIcon *icon = it.next(); if ( icon->regExp().isEmpty() ) continue; // some hackery int iii = i; bool searchAgain; do { searchAgain = false; // find the closest match const QRegExp &rx = icon->regExp(); int n = rx.indexIn(str, iii); if ( n == -1 ) continue; if(ePos == -1 || n < ePos || (rx.matchedLength() > foundLen && n < ePos + foundLen)) { bool leftSpace = n == 0 || (n > 0 && str[n-1].isSpace()); bool rightSpace = (n+rx.matchedLength() == (int)str.length()) || (n+rx.matchedLength() < (int)str.length() && str[n+rx.matchedLength()].isSpace()); // there must be whitespace at least on one side of the emoticon if (leftSpace || rightSpace) { ePos = n; closest = icon; foundPos = n; foundLen = rx.matchedLength(); break; } searchAgain = true; } iii = n + rx.matchedLength(); } while ( searchAgain ); } } QString s; if(ePos == -1) s = str.mid(i); else s = str.mid(i, ePos-i); p.putPlain(s); if ( !closest ) break; p.putRich( QString("<icon name=\"%1\" text=\"%2\">").arg(TextUtil::escape(closest->name())).arg(TextUtil::escape(str.mid(foundPos, foundLen))) ); i = foundPos + foundLen; } } QString out = p.output(); return out; } QString TextUtil::legacyFormat(const QString& in) { //enable *bold* stuff // //old code //out=out.replace(QRegExp("(^[^<>\\s]*|\\s[^<>\\s]*)\\*(\\S+)\\*([^<>\\s]*\\s|[^<>\\s]*$)"),"\\1<b>*\\2*</b>\\3"); //out=out.replace(QRegExp("(^[^<>\\s\\/]*|\\s[^<>\\s\\/]*)\\/([^\\/\\s]+)\\/([^<>\\s\\/]*\\s|[^<>\\s\\/]*$)"),"\\1<i>/\\2/</i>\\3"); //out=out.replace(QRegExp("(^[^<>\\s]*|\\s[^<>\\s]*)_(\\S+)_([^<>\\s]*\\s|[^<>\\s]*$)"),"\\1<u>_\\2_</u>\\3"); QString out=in; out=out.replace(QRegExp("(^|\\s|>)_(\\S+)_(<|\\s|$)"),"\\1<u>_\\2_</u>\\3"); out=out.replace(QRegExp("(^|\\s|>)\\*(\\S+)\\*(<|\\s|$)"),"\\1<b>*\\2*</b>\\3"); out=out.replace(QRegExp("(^|\\s|>)\\/(\\S+)\\/(<|\\s|$)"),"\\1<i>/\\2/</i>\\3"); return out; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/ahcservermanager.h���������������������������������������������������������������������0000644�0001750�0001750�00000003123�11305557613�014615� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ahcservermanager.h - Server implementation of JEP-50 (Ad-Hoc Commands) * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHCSERVERMANAGER_H #define AHCSERVERMANAGER_H #include <QList> class AHCommandServer; class AHCommand; class JT_AHCServer; class PsiAccount; class QString; namespace XMPP { class Jid; } class AHCServerManager { public: AHCServerManager(PsiAccount* pa); void addServer(AHCommandServer*); void removeServer(AHCommandServer*); typedef QList<AHCommandServer*> ServerList; ServerList commands(const XMPP::Jid&) const; void execute(const AHCommand& command, const XMPP::Jid& requester, QString id); PsiAccount* account() const { return pa_; } bool hasServer(const QString& node, const XMPP::Jid&) const; protected: AHCommandServer* findServer(const QString& node) const; private: PsiAccount* pa_; JT_AHCServer* server_task_; ServerList servers_; }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/rtparse.cpp����������������������������������������������������������������������������0000644�0001750�0001750�00000004310�11305557613�013312� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** rtparse.cpp - class for manipulating richtext ** Copyright (C) 2001, 2002 Justin Karneges ** ** 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 2 ** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA. ** ****************************************************************************/ #include "rtparse.h" #include "textutil.h" #include <QTextDocument> // for Qt::escape() RTParse::RTParse(const QString &_in) { in = _in; v_atEnd = in.length() == 0; v_at = 0; //printf("rtparse:\n"); } const QString &RTParse::output() const { //printf("final: [%s]\n", out.latin1()); return out; } QString RTParse::next() { if(v_atEnd) return ""; // if we're at a tag, append it to the output if(in.at(v_at) == '<') { QString s; int n = in.indexOf('>', v_at); if(n == -1) { s = in.mid(v_at); } else { ++n; s = in.mid(v_at, n-v_at); } v_at += s.length(); out += s; } // now find the next tag, and grab the text in between QString s; int x = in.indexOf('<', v_at); if(x == -1) { s = in.mid(v_at); v_atEnd = true; } else { s = in.mid(v_at, x-v_at); } v_at += s.length(); //printf("chunk = '%s'\n", s.latin1()); s = TextUtil::resolveEntities(s); //printf("resolved = '%s'\n", s.latin1()); return s; } bool RTParse::atEnd() const { return v_atEnd; } void RTParse::putPlain(const QString &s) { //printf("got this: [%s]\n", s.latin1()); out += Qt::escape(s); //printf("changed to this: [%s]\n", expandEntities(s).latin1()); } void RTParse::putRich(const QString &s) { out += s; //printf("+ '%s'\n", s.latin1()); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pgpkeydlg.cpp��������������������������������������������������������������������������0000644�0001750�0001750�00000013716�11305557613�013632� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * pgpkeydlg.h * Copyright (C) 2001-2009 Justin Karneges, Michail Pishchagin * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "pgpkeydlg.h" #include <QString> #include <QMessageBox> #include <QPushButton> #include <QStandardItemModel> #include <QSortFilterProxyModel> #include <QKeyEvent> #include <QHeaderView> #include <pgputil.h> #include "common.h" #include "showtextdlg.h" class KeyViewItem : public QStandardItem { public: KeyViewItem(const QCA::KeyStoreEntry& entry, const QString& name) : QStandardItem() , entry_(entry) { setText(name); } QCA::KeyStoreEntry entry() const { return entry_; } private: QCA::KeyStoreEntry entry_; }; class KeyViewProxyModel : public QSortFilterProxyModel { public: KeyViewProxyModel(QObject* parent) : QSortFilterProxyModel(parent) { setFilterCaseSensitivity(Qt::CaseInsensitive); } virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { for (int column = 0; column <= 1; ++column) { QModelIndex index = sourceModel()->index(sourceRow, column, sourceParent); if (index.data(Qt::DisplayRole).toString().contains(filterRegExp())) return true; } return false; } }; PGPKeyDlg::PGPKeyDlg(Type t, const QString& defaultKeyID, QWidget *parent) : QDialog(parent) , model_(0) { ui_.setupUi(this); setModal(true); pb_dtext_ = ui_.buttonBox->addButton(tr("&Diagnostics"), QDialogButtonBox::ActionRole); model_ = new QStandardItemModel(this); model_->setHorizontalHeaderLabels(QStringList() << tr("Key ID") << tr("User ID") ); proxy_ = new KeyViewProxyModel(this); proxy_->setSourceModel(model_); ui_.lv_keys->setModel(proxy_); ui_.lv_keys->header()->setResizeMode(QHeaderView::ResizeToContents); connect(ui_.lv_keys, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(doubleClicked(const QModelIndex&))); connect(ui_.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(do_accept())); connect(ui_.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), SLOT(reject())); connect(pb_dtext_, SIGNAL(clicked()), SLOT(show_ksm_dtext())); connect(ui_.le_filter, SIGNAL(textChanged(const QString&)), this, SLOT(filterTextChanged())); ui_.le_filter->installEventFilter(this); KeyViewItem* firstItem = 0; KeyViewItem* selectedItem = 0; int row = 0; foreach(QCA::KeyStore *ks, PGPUtil::instance().keystores_) { if (ks->type() == QCA::KeyStore::PGPKeyring && ks->holdsIdentities()) { foreach(QCA::KeyStoreEntry ke, ks->entryList()) { bool publicKey = (t == Public && ke.type() == QCA::KeyStoreEntry::TypePGPPublicKey) || (ke.type() == QCA::KeyStoreEntry::TypePGPSecretKey); bool secretKey = t == Secret && ke.type() == QCA::KeyStoreEntry::TypePGPSecretKey; if (publicKey || secretKey) { KeyViewItem *i = new KeyViewItem(ke, ke.id().right(8)); KeyViewItem *i2 = new KeyViewItem(ke, ke.name()); QStandardItem* root = model_->invisibleRootItem(); root->setChild(row, 0, i); root->setChild(row, 1, i2); ++row; QString keyId; if (publicKey) keyId = ke.pgpPublicKey().keyId(); else keyId = ke.pgpSecretKey().keyId(); if (!defaultKeyID.isEmpty() && keyId == defaultKeyID) { selectedItem = i; } if (!firstItem) { firstItem = i; } } } } } if (selectedItem) { firstItem = selectedItem; } if (firstItem) { QModelIndex realIndex = model_->indexFromItem(firstItem); QModelIndex fakeIndex = proxy_->mapFromSource(realIndex); ui_.lv_keys->setCurrentIndex(fakeIndex); ui_.lv_keys->scrollTo(fakeIndex); } // adjustSize(); } const QCA::KeyStoreEntry& PGPKeyDlg::keyStoreEntry() const { return entry_; } bool PGPKeyDlg::eventFilter(QObject* watched, QEvent* event) { if (watched == ui_.le_filter && event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast<QKeyEvent*>(event); if (ke->key() == Qt::Key_Up || ke->key() == Qt::Key_Down || ke->key() == Qt::Key_PageUp || ke->key() == Qt::Key_PageDown || ke->key() == Qt::Key_Home || ke->key() == Qt::Key_End) { QCoreApplication::instance()->sendEvent(ui_.lv_keys, event); return true; } } return QDialog::eventFilter(watched, event); } void PGPKeyDlg::filterTextChanged() { proxy_->setFilterWildcard(ui_.le_filter->text()); } void PGPKeyDlg::doubleClicked(const QModelIndex& index) { ui_.lv_keys->setCurrentIndex(index); do_accept(); } void PGPKeyDlg::do_accept() { QModelIndex fakeIndex = ui_.lv_keys->currentIndex(); QModelIndex realIndex = proxy_->mapToSource(fakeIndex); QStandardItem* item = model_->itemFromIndex(realIndex); KeyViewItem *i = dynamic_cast<KeyViewItem*>(item); if(!i) { QMessageBox::information(this, tr("Error"), tr("Please select a key.")); return; } entry_ = i->entry(); accept(); } void PGPKeyDlg::show_ksm_dtext() { QString dtext = QCA::KeyStoreManager::diagnosticText(); ShowTextDlg *w = new ShowTextDlg(dtext, true, false, this); w->setWindowTitle(CAP(tr("Key Storage Diagnostic Text"))); w->resize(560, 240); w->show(); } ��������������������������������������������������psi-0.14/src/accountmanagedlg.cpp�������������������������������������������������������������������0000644�0001750�0001750�00000023254�11305557613�015136� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * accountmanagedlg.cpp - dialogs for manipulating PsiAccounts * Copyright (C) 2001-2009 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QtCrypto> #include <QInputDialog> #include <QMessageBox> #include <QPushButton> #include <QLineEdit> #include <QLabel> #include <QPointer> #include <QTimer> #include <QHeaderView> #include "psicon.h" #include "psiaccount.h" #include "common.h" #include "xmpp_tasks.h" #include "pgputil.h" #include "proxy.h" #include "miniclient.h" #include "accountadddlg.h" #include "accountmanagedlg.h" #include "ui_accountremove.h" #include "psicontactlist.h" using namespace XMPP; //---------------------------------------------------------------------------- // AccountRemoveDlg //---------------------------------------------------------------------------- class AccountRemoveDlg : public QDialog, public Ui::AccountRemove { Q_OBJECT public: AccountRemoveDlg(ProxyManager *, const UserAccount &, QWidget *parent=0); ~AccountRemoveDlg(); protected: // reimplemented //void closeEvent(QCloseEvent *); public slots: void done(int); private slots: void remove(); void bg_clicked(int); void client_handshaken(); void client_error(); void client_disconnected(); void unreg_finished(); private: class Private; Private *d; MiniClient *client; QPushButton* pb_close_; QPushButton* pb_remove_; }; class AccountRemoveDlg::Private { public: Private() {} UserAccount acc; QButtonGroup *bg; ProxyManager *proxyman; }; AccountRemoveDlg::AccountRemoveDlg(ProxyManager *proxyman, const UserAccount &acc, QWidget *parent) :QDialog(parent) { setupUi(this); setModal(false); d = new Private; d->acc = acc; d->proxyman = proxyman; setWindowTitle(CAP(windowTitle())); pb_close_ = buttonBox->button(QDialogButtonBox::Cancel); pb_close_->setDefault(true); pb_remove_ = buttonBox->addButton(tr("&Remove"), QDialogButtonBox::DestructiveRole); connect(pb_close_, SIGNAL(clicked()), SLOT(close())); connect(pb_remove_, SIGNAL(clicked()), SLOT(remove())); d->bg = new QButtonGroup(0); d->bg->addButton(rb_remove, 0); d->bg->addButton(rb_removeAndUnreg, 1); connect(d->bg, SIGNAL(buttonClicked(int)), SLOT(bg_clicked(int))); rb_remove->setChecked(true); bg_clicked(0); client = new MiniClient; connect(client, SIGNAL(handshaken()), SLOT(client_handshaken())); connect(client, SIGNAL(error()), SLOT(client_error())); connect(client, SIGNAL(disconnected()), SLOT(client_disconnected())); adjustSize(); } AccountRemoveDlg::~AccountRemoveDlg() { delete client; delete d->bg; delete d; } /*void AccountRemoveDlg::closeEvent(QCloseEvent *e) { e->ignore(); reject(); }*/ void AccountRemoveDlg::done(int r) { if(busy->isActive()) { int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel the unregistration?"), tr("&Yes"), tr("&No")); if(n != 0) return; } QDialog::done(r); } void AccountRemoveDlg::bg_clicked(int x) { if(x == 0) { lb_pass->setEnabled(false); le_pass->setEnabled(false); } else if(x == 1) { lb_pass->setEnabled(true); le_pass->setEnabled(true); le_pass->setFocus(); } } void AccountRemoveDlg::remove() { bool unreg = rb_removeAndUnreg->isChecked(); if(unreg) { if(!d->acc.pass.isEmpty() && le_pass->text() != d->acc.pass) { QMessageBox::information(this, tr("Error"), tr("Password does not match account. Please try again.")); le_pass->setFocus(); return; } } int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to remove <b>%1</b> ?").arg(d->acc.name), tr("&Yes"), tr("&No")); if(n != 0) return; if(!unreg) { accept(); return; } busy->start(); gb_account->setEnabled(false); pb_remove_->setEnabled(false); QString pass = le_pass->text(); Jid j(Jid(d->acc.jid).withResource(d->acc.resource)); client->connectToServer(j, d->acc.legacy_ssl_probe, d->acc.ssl == UserAccount::SSL_Legacy, d->acc.ssl == UserAccount::SSL_Yes, d->acc.opt_host ? d->acc.host : QString(), d->acc.port, d->proxyman, d->acc.proxyID, &pass); } void AccountRemoveDlg::client_handshaken() { // Workaround for servers that do not send a response to the remove request client->setErrorOnDisconnect(false); // try to unregister an account JT_Register *reg = new JT_Register(client->client()->rootTask()); connect(reg, SIGNAL(finished()), SLOT(unreg_finished())); reg->unreg(); reg->go(true); } void AccountRemoveDlg::client_error() { busy->stop(); gb_account->setEnabled(true); pb_remove_->setEnabled(true); } void AccountRemoveDlg::unreg_finished() { JT_Register *reg = (JT_Register *)sender(); client->close(); busy->stop(); if(reg->success()) { QMessageBox::information(this, tr("Success"), tr("The account was unregistered successfully.")); accept(); return; } else if(reg->statusCode() != Task::ErrDisc) { gb_account->setEnabled(true); pb_remove_->setEnabled(true); QMessageBox::critical(this, tr("Error"), QString(tr("There was an error unregistering the account.\nReason: %1")).arg(reg->statusString())); } } void AccountRemoveDlg::client_disconnected() { // Workaround for servers that do not send a response to the remove request busy->stop(); QMessageBox::information(this, tr("Success"), tr("The account was unregistered successfully.")); accept(); } //---------------------------------------------------------------------------- // AccountManageDlg //---------------------------------------------------------------------------- class AccountManageItem : public QObject, public QTreeWidgetItem { Q_OBJECT public: QPointer<PsiAccount> pa; public: AccountManageItem(QTreeWidget *par, PsiAccount *_pa) :QTreeWidgetItem(par) { pa = _pa; Q_ASSERT(!pa.isNull()); connect(pa, SIGNAL(updatedActivity()), SLOT(updateInfo())); connect(pa, SIGNAL(updatedAccount()), SLOT(updateInfo())); updateInfo(); } void setData (int column, int role, const QVariant& value) { bool oldChecked = checkState(0) == Qt::Checked; QTreeWidgetItem::setData(column, role, value); bool checked = checkState(0) == Qt::Checked; if (oldChecked != checked && role == Qt::CheckStateRole) { if (pa->enabled() != checked) pa->setEnabled(checked); QTimer::singleShot(0, this, SLOT(updateInfo())); } } private slots: void updateInfo() { UserAccount acc = pa->accountOptions(); Jid j = acc.jid; setText(0, pa->name()); setText(1, acc.opt_host && acc.host.length() ? acc.host : j.domain()); setText(2, pa->isActive() ? AccountManageDlg::tr("Active") : AccountManageDlg::tr("Not active")); setCheckState(0, pa->enabled() ? Qt::Checked : Qt::Unchecked); } }; AccountManageDlg::AccountManageDlg(PsiCon *_psi) :QDialog(0) { setupUi(this); setModal(false); psi = _psi; psi->dialogRegister(this); setWindowTitle(CAP(windowTitle())); // setup signals connect(pb_add, SIGNAL(clicked()), SLOT(add())); connect(pb_modify, SIGNAL(clicked()), SLOT(modify())); connect(pb_remove, SIGNAL(clicked()), SLOT(remove())); connect(lv_accs, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), SLOT(modify(QTreeWidgetItem *))); connect(lv_accs, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(qlv_selectionChanged(QTreeWidgetItem *, QTreeWidgetItem *))); connect(psi, SIGNAL(accountAdded(PsiAccount *)), SLOT(accountAdded(PsiAccount *))); connect(psi, SIGNAL(accountRemoved(PsiAccount *)), SLOT(accountRemoved(PsiAccount *))); lv_accs->header()->setResizeMode(QHeaderView::ResizeToContents); foreach(PsiAccount* pa, psi->contactList()->accounts()) new AccountManageItem(lv_accs, pa); if (lv_accs->topLevelItemCount()) lv_accs->setCurrentItem(lv_accs->topLevelItem(0)); //adjustSize(); } AccountManageDlg::~AccountManageDlg() { psi->dialogUnregister(this); } void AccountManageDlg::qlv_selectionChanged(QTreeWidgetItem *lvi, QTreeWidgetItem *) { AccountManageItem *i = (AccountManageItem *)lvi; bool ok = i ? true: false; pb_modify->setEnabled(ok); pb_remove->setEnabled(ok); } void AccountManageDlg::add() { AccountAddDlg *w = new AccountAddDlg(psi, 0); w->show(); } void AccountManageDlg::modify() { modify(lv_accs->currentItem()); } void AccountManageDlg::modify(QTreeWidgetItem *lvi) { AccountManageItem *i = (AccountManageItem *)lvi; if(!i) return; i->pa->modify(); } void AccountManageDlg::remove() { AccountManageItem *i = (AccountManageItem *)lv_accs->currentItem(); if(!i) return; if(i->pa->isActive()) { QMessageBox::information(this, tr("Error"), tr("Unable to remove the account, as it is currently active.")); return; } AccountRemoveDlg *w = new AccountRemoveDlg(psi->proxy(), i->pa->userAccount()); int n = w->exec(); if(n != QDialog::Accepted) { delete w; return; } delete w; psi->removeAccount(i->pa); } void AccountManageDlg::accountAdded(PsiAccount *pa) { new AccountManageItem(lv_accs, pa); } void AccountManageDlg::accountRemoved(PsiAccount *pa) { for (int index = 0; index < lv_accs->topLevelItemCount(); ++index) { AccountManageItem* i = static_cast<AccountManageItem*>(lv_accs->topLevelItem(index)); if(i->pa == pa) { delete i; qlv_selectionChanged(lv_accs->currentItem(), 0); break; } } } #include "accountmanagedlg.moc" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�013007� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/unittest.pri������������������������������������������������������������������0000644�0001750�0001750�00000000043�11305557613�015377� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SOURCES += \ $$PWD/commontest.cpp ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/psiiconset/�������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�015167� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/psiiconset/testpsiiconset.cpp�������������������������������������������������0000644�0001750�0001750�00000003176�11305557613�020762� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QtTest/QtTest> #include <QStringList> #include <Q3PtrList> #include "iconset.h" #include "psiiconset.h" class TestPsiIconset: public QObject { Q_OBJECT private: PsiIconset *is; private slots: void initTestCase() { is = new PsiIconset(); g.pathBase = "../../tools/iconset/unittest"; g.pathHome = getHomeDir(); g.pathProfiles = g.pathHome + "/profiles"; } void cleanupTestCase() { delete is; } void testLoadSystem() { QVERIFY(is->loadSystem()); } // this mustn't produce any valgrind errors, so // it's pretty safe to generate suppressions // from this test: just run "./testpsiiconset testLoadImage" void testLoadImage() { QImage *img = new QImage(":iconsets/system/default/psimain.png"); delete img; } void testLoadAll() { // checking for memory leaks this way for (int i = 0; i < 3; i++) QVERIFY(is->loadAll()); } void testBasePath() { Iconset *iconset = new Iconset(); QVERIFY(iconset->load(g.pathBase + "/iconsets/roster/default.jisp")); delete iconset; } void testChangeOptions() { Options oldOptions = option; option.systemIconset = "crystal_system.jisp"; option.emoticons = (QStringList() << "puz.jisp"); option.defaultRosterIconset = "default.jisp"; QVERIFY(is->optionsChanged(&oldOptions)); QCOMPARE(is->system().name(), QString("Crystal (System)")); QCOMPARE(is->system().description(), QString("Crystal System Iconset")); QCOMPARE(is->system().version(), QString("0.3")); QCOMPARE(is->emoticons.first()->name(), QString("puzazBox")); option = oldOptions; } }; QTEST_MAIN(TestPsiIconset) #include "testpsiiconset.moc" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/psiiconset/testpsiiconset.pro�������������������������������������������������0000644�0001750�0001750�00000000122�11305557613�020764� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TARGET = testpsiiconset SOURCES += testpsiiconset.cpp include(../half_of_psi.pri)����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/unittest.pro������������������������������������������������������������������0000644�0001750�0001750�00000000620�11305557613�015406� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include(unittest.pri) # FIXME: Horrible set of dependencies, due to common being a pile of # unrelated stuff include($$IRIS_XMPP_JID_MODULE) include($$PSI_TOOLS_OPTIONSTREE_MODULE) include($$PSI_TOOLS_ATOMICXMLFILE_MODULE) QT += gui xml INCLUDEPATH += .. ../../iris/src/xmpp/xmpp-im DEPENDPATH += .. SOURCES += \ $$PWD/../common.cpp ����������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/half_of_psi.pri���������������������������������������������������������������0000644�0001750�0001750�00000000541�11305557613�015774� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Yay! Almost all Psi sources are here! PSI_CPP = $$PWD/.. include($$PSI_CPP/src.pri) # linking half of psi :-/ INCLUDEPATH += $$PSI_CPP # iconsets RESOURCES += $$PSI_CPP/../iconsets.qrc CONFIG += unittest crypto QT += gui network xml DEFINES += UNIT_TEST # unittest helpers TESTBASEDIR = $$PSI_CPP/../unittest include($$TESTBASEDIR/unittest.pri) ���������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/psipopup/���������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�014666� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/psipopup/testpsipopup.pro�����������������������������������������������������0000644�0001750�0001750�00000000116�11305557613�020165� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TARGET = testpsipopup SOURCES += testpsipopup.cpp include(../half_of_psi.pri)��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/psipopup/testpsipopup.cpp�����������������������������������������������������0000644�0001750�0001750�00000003274�11305557613�020157� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QtTest/QtTest> #include <QApplication> #include <QTimer> #include <QtCrypto> #include "psipopup.h" #include "iconset.h" #include "psicon.h" // for PsiCon #include "psiaccount.h" // for PsiAccount #include "profiles.h" // for UserAccount #include "im.h" // for Jid #include "userlist.h" // for UserListItem #include "mainwin.h" class TestPsiPopup: public QObject { Q_OBJECT private: PsiCon *psi; PsiAccount *account; bool timeout; QCA::Initializer *qca_init; void delay(int msecs) { timeout = false; QTimer::singleShot(msecs, this, SLOT(timedOut())); while (!timeout) qApp->processEvents(); } protected slots: void timedOut() { timeout = true; } private slots: void initTestCase() { // initialize the minimal amount of stuff necessary // to show PsiPopups on screen // is = new PsiIconset(); // QVERIFY(is->loadAll()); qca_init = new QCA::Initializer(); QCA::keyStoreManager()->start(); QCA::keyStoreManager()->waitForBusyFinished(); psi = new PsiCon(); psi->init(); UserAccount userAccount; account = new PsiAccount(userAccount, psi); } void cleanupTestCase() { delete psi; QCA::unloadAllPlugins(); delete qca_init; } void testPsiPopup() { // Q3MainWindow window; // window.show(); delay(10000); option.ppHideTime = 10 * 1000; // 10 seconds option.ppBorderColor = Qt::blue; option.ppIsOn = true; PsiPopup *popup = new PsiPopup(PsiPopup::AlertChat, account); Jid jid("mblsha@jabber.ru"); Resource resource("PowerBook"); UserListItem userListItem; MessageEvent psiEvent(account); popup->setData(jid, resource, &userListItem, &psiEvent); delay(15000); } }; QTEST_MAIN(TestPsiPopup) #include "testpsipopup.moc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/unittest/commontest.cpp����������������������������������������������������������������0000644�0001750�0001750�00000001557�11305557613�015713� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * Copyright (C) 2007, Remko Troncon */ #include <QObject> #include <QtTest/QtTest> #include "qttestutil/qttestutil.h" #include "common.h" int versionStringToInt(const char* version); class CommonTest : public QObject { Q_OBJECT private slots: void testVersionStringToInt() { QCOMPARE(versionStringToInt("4.3.0"), 0x00040300); } void testVersionStringToInt_TooManyParts() { QCOMPARE(versionStringToInt("4.3.0.1"), 0); } void testVersionStringToInt_TooFewParts() { QCOMPARE(versionStringToInt("4.3"), 0); } void testVersionStringToInt_NonNumericPart() { QCOMPARE(versionStringToInt("4.A.3"), 0); } void testVersionStringToInt_TooBigPart() { QCOMPARE(versionStringToInt("4.256.4"), 0); } void testVersionStringToInt_TooSmallPart() { QCOMPARE(versionStringToInt("4.-1.4"), 0); } }; QTTESTUTIL_REGISTER_TEST(CommonTest); �������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/translationmanager.cpp�����������������������������������������������������������������0000644�0001750�0001750�00000011067�11305557613�015532� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * translationmanager.cpp * Copyright (C) 2006 Remko Troncon, Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QTranslator> #include <QCoreApplication> #include <QFile> #include <QDir> #include <QLibraryInfo> #include "translationmanager.h" #include "applicationinfo.h" #include "varlist.h" TranslationManager::TranslationManager() { // Initialize currentLanguage_ = "en"; QString currentLanguageName = QT_TR_NOOP("language_name"); // The application translator translator_ = new QTranslator(0); // The qt translator qt_translator_ = new QTranslator(0); // Self-destruct connect(QCoreApplication::instance(),SIGNAL(aboutToQuit()),SLOT(deleteLater())); } TranslationManager::~TranslationManager() { QCoreApplication::instance()->removeTranslator(translator_); delete translator_; translator_ = 0; QCoreApplication::instance()->removeTranslator(qt_translator_); delete qt_translator_; qt_translator_ = 0; } TranslationManager* TranslationManager::instance() { if (!instance_) { instance_ = new TranslationManager(); } return instance_; } const QString& TranslationManager::currentLanguage() const { return currentLanguage_; } QString TranslationManager::currentXMLLanguage() const { QString xmllang = currentLanguage_; xmllang.replace('_',"-"); int at_index = xmllang.indexOf('@'); if (at_index > 0) xmllang = xmllang.left(at_index); return xmllang; } static bool loadQtTranslationHelper(const QString& language, const QString& dir, QTranslator* qt_translator) { return qt_translator->load("qt_" + language, dir); } bool TranslationManager::loadQtTranslation(const QString& language) { foreach(QString dir, translationDirs()) { if (loadQtTranslationHelper(language, dir, qt_translator_)) { return true; } } return loadQtTranslationHelper(language, QLibraryInfo::location(QLibraryInfo::TranslationsPath), qt_translator_); } void TranslationManager::loadTranslation(const QString& language) { // The default translation if(language == "en") { currentLanguage_ = language; //currentLanguageName_ = "English"; QCoreApplication::instance()->removeTranslator(translator_); QCoreApplication::instance()->removeTranslator(qt_translator_); return; } // Try loading the translation file foreach(QString dir, translationDirs()) { if(!QFile::exists(dir)) continue; if (translator_->load("psi_" + language, dir)) { loadQtTranslation(language); if (currentLanguage_ == "en") { QCoreApplication::instance()->installTranslator(translator_); QCoreApplication::instance()->installTranslator(qt_translator_); } currentLanguage_ = language; break; } } } VarList TranslationManager::availableTranslations() { VarList langs; // We always support english langs.set("en", "English"); // Search the paths foreach(QString dirName, translationDirs()) { if(!QFile::exists(dirName)) continue; QDir d(dirName); foreach(QString str, d.entryList()) { // verify that it is a language file if(str.left(4) != "psi_") continue; int n = str.indexOf('.', 4); if(n == -1) continue; if(str.mid(n) != ".qm") continue; QString lang = str.mid(4, n-4); //printf("found [%s], lang=[%s]\n", str.latin1(), lang.latin1()); // get the language_name QString name = QString("[") + str + "]"; QTranslator t(0); if(!t.load(str, dirName)) continue; //Is translate equivalent to the old findMessage? I hope so //Qt4 conversion QString s = t.translate("@default", "language_name"); if(!s.isEmpty()) name = s; langs.set(lang, name); } } return langs; } QStringList TranslationManager::translationDirs() const { QStringList dirs; QString subdir = ""; dirs += "." + subdir; dirs += ApplicationInfo::homeDir() + subdir; dirs += ApplicationInfo::resourcesDir() + subdir; return dirs; } TranslationManager* TranslationManager::instance_ = NULL; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/avatars.cpp����������������������������������������������������������������������������0000644�0001750�0001750�00000044541�11305557613�013305� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * avatars.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * TODO: * - Be more efficient about storing avatars in memory * - Move ovotorChanged() to Avatar, and only listen to the active avatars * being changed. */ #include <QDomElement> #include <QtCrypto> #include <QPixmap> #include <QDateTime> #include <QDir> #include <QFileInfo> #include <QFile> #include <QBuffer> #include <QPainter> #include <qca_basic.h> #include "xmpp_xmlcommon.h" #include "xmpp_vcard.h" #include "xmpp_client.h" #include "xmpp_resource.h" #include "xmpp_pubsubitem.h" #include "avatars.h" #include "applicationinfo.h" #include "psiaccount.h" #include "profiles.h" #include "vcardfactory.h" #include "pepmanager.h" #include "pixmaputil.h" #define MAX_AVATAR_SIZE 96 #define MAX_AVATAR_DISPLAY_SIZE 64 using namespace QCA; //------------------------------------------------------------------------------ static QByteArray scaleAvatar(const QByteArray& b) { //int maxSize = (LEGOPTS.avatarsSize > MAX_AVATAR_SIZE ? MAX_AVATAR_SIZE : LEGOPTS.avatarsSize); int maxSize = AvatarFactory::maxAvatarSize(); QImage i = QImage::fromData(b); if (i.isNull()) { qWarning("AvatarFactory::scaleAvatar(): Null image (unrecognized format?)"); return QByteArray(); } else if (i.width() > maxSize || i.height() > maxSize) { QImage image = i.scaled(maxSize,maxSize,Qt::KeepAspectRatio,Qt::SmoothTransformation); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); image.save(&buffer, "PNG"); return ba; } else { return b; } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Avatar: Base class for avatars. //------------------------------------------------------------------------------ Avatar::Avatar(AvatarFactory* factory) : QObject(factory), factory_(factory) { } Avatar::~Avatar() { } void Avatar::setImage(const QImage& i) { if (i.width() > MAX_AVATAR_DISPLAY_SIZE || i.height() > MAX_AVATAR_DISPLAY_SIZE) pixmap_ = QPixmap::fromImage(i.scaled(MAX_AVATAR_DISPLAY_SIZE,MAX_AVATAR_DISPLAY_SIZE,Qt::KeepAspectRatio,Qt::SmoothTransformation)); else pixmap_ = QPixmap::fromImage(i); } void Avatar::setImage(const QByteArray& ba) { setImage(QImage::fromData(ba)); } void Avatar::setImage(const QPixmap& p) { if (p.width() > MAX_AVATAR_DISPLAY_SIZE || p.height() > MAX_AVATAR_DISPLAY_SIZE) pixmap_ = p.scaled(MAX_AVATAR_DISPLAY_SIZE,MAX_AVATAR_DISPLAY_SIZE,Qt::KeepAspectRatio,Qt::SmoothTransformation); else pixmap_ = p; } void Avatar::resetImage() { pixmap_ = QPixmap(); } AvatarFactory* Avatar::factory() const { return factory_; } //------------------------------------------------------------------------------ // CachedAvatar: Base class for avatars which are requested and are to be cached //------------------------------------------------------------------------------ class CachedAvatar : public Avatar { public: CachedAvatar(AvatarFactory* factory) : Avatar(factory) { }; virtual void updateHash(const QString& h); protected: virtual const QString& hash() const { return hash_; } virtual void requestAvatar() { } virtual void avatarUpdated() { } virtual bool isCached(const QString& hash); virtual void loadFromCache(const QString& hash); virtual void saveToCache(const QByteArray& data); private: QString hash_; }; void CachedAvatar::updateHash(const QString& h) { if (hash_ != h) { hash_ = h; if (h.isEmpty()) { hash_ = ""; resetImage(); avatarUpdated(); } else if (isCached(h)) { loadFromCache(h); avatarUpdated(); } else { resetImage(); avatarUpdated(); requestAvatar(); } } } bool CachedAvatar::isCached(const QString& h) { return QDir(AvatarFactory::getCacheDir()).exists(h); } void CachedAvatar::loadFromCache(const QString& h) { // printf("Loading avatar from cache\n"); hash_ = h; setImage(QImage(QDir(AvatarFactory::getCacheDir()).filePath(h))); if (pixmap().isNull()) { qWarning("CachedAvatar::loadFromCache(): Null pixmap. Unsupported format ?"); } } void CachedAvatar::saveToCache(const QByteArray& data) { QString hash = QCA::Hash("sha1").hashToString(data); // printf("Saving %s to cache.\n",hash.latin1()); QString fn = QDir(AvatarFactory::getCacheDir()).filePath(hash); QFile f(fn); if (f.open(QIODevice::WriteOnly)) { f.write(data); f.close(); } else printf("Error opening %s for writing.\n", qPrintable(f.fileName())); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // PEPAvatar: PEP Avatars //------------------------------------------------------------------------------ class PEPAvatar : public CachedAvatar { Q_OBJECT public: PEPAvatar(AvatarFactory* factory, const Jid& jid) : CachedAvatar(factory), jid_(jid) { }; void setData(const QString& h, const QString& data) { if (h == hash()) { QByteArray ba = Base64().stringToArray(data).toByteArray(); if (!ba.isEmpty()) { saveToCache(ba); setImage(ba); if (pixmap().isNull()) { qWarning("PEPAvatar::setData(): Null pixmap. Unsupported format ?"); } emit avatarChanged(jid_); } else qWarning("PEPAvatar::setData(): Received data is empty. Bad encoding ?"); } } signals: void avatarChanged(const Jid&); protected: void requestAvatar() { factory()->account()->pepManager()->get(jid_,"http://www.xmpp.org/extensions/xep-0084.html#ns-data",hash()); } void avatarUpdated() { emit avatarChanged(jid_); } private: Jid jid_; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // VCardAvatar: Avatars coming from VCards of contacts. //------------------------------------------------------------------------------ class VCardAvatar : public CachedAvatar { Q_OBJECT public: VCardAvatar(AvatarFactory* factory, const Jid& jid); signals: void avatarChanged(const Jid&); public slots: void receivedVCard(); protected: void requestAvatar(); void avatarUpdated() { emit avatarChanged(jid_); } private: Jid jid_; }; VCardAvatar::VCardAvatar(AvatarFactory* factory, const Jid& jid) : CachedAvatar(factory), jid_(jid) { } void VCardAvatar::requestAvatar() { VCardFactory::instance()->getVCard(jid_.bare(), factory()->account()->client()->rootTask(), this, SLOT(receivedVCard())); } void VCardAvatar::receivedVCard() { const VCard* vcard = VCardFactory::instance()->vcard(jid_); if (vcard) { saveToCache(vcard->photo()); setImage(vcard->photo()); emit avatarChanged(jid_); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // VCardStaticAvatar: VCard static photo avatar (not published through presence) //------------------------------------------------------------------------------ class VCardStaticAvatar : public Avatar { Q_OBJECT public: VCardStaticAvatar(AvatarFactory* factory, const Jid& j); public slots: void vcardChanged(const Jid&); signals: void avatarChanged(const Jid&); private: Jid jid_; }; VCardStaticAvatar::VCardStaticAvatar(AvatarFactory* factory, const Jid& j) : Avatar(factory), jid_(j.bare()) { const VCard* vcard = VCardFactory::instance()->vcard(jid_); if (vcard && !vcard->photo().isEmpty()) setImage(vcard->photo()); connect(VCardFactory::instance(),SIGNAL(vcardChanged(const Jid&)),SLOT(vcardChanged(const Jid&))); } void VCardStaticAvatar::vcardChanged(const Jid& j) { if (j.compare(jid_,false)) { const VCard* vcard = VCardFactory::instance()->vcard(jid_); if (vcard && !vcard->photo().isEmpty()) setImage(vcard->photo()); else resetImage(); emit avatarChanged(jid_); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // FileAvatar: Avatars coming from local files. //------------------------------------------------------------------------------ class FileAvatar : public Avatar { public: FileAvatar(AvatarFactory* factory, const Jid& jid); void import(const QString& file); void removeFromDisk(); bool exists(); QPixmap getPixmap(); const Jid& getJid() const { return jid_; } protected: bool isDirty() const; QString getFileName() const; void refresh(); QDateTime lastModified() const { return lastModified_; } private: QDateTime lastModified_; Jid jid_; }; FileAvatar::FileAvatar(AvatarFactory* factory, const Jid& jid) : Avatar(factory), jid_(jid) { } void FileAvatar::import(const QString& file) { if (QFileInfo(file).exists()) { QFile source_file(file); QFile target_file(getFileName()); if (source_file.open(QIODevice::ReadOnly) && target_file.open(QIODevice::WriteOnly)) { QByteArray ba = source_file.readAll(); QByteArray data = scaleAvatar(ba); target_file.write(data); } } } void FileAvatar::removeFromDisk() { QFile f(getFileName()); f.remove(); } bool FileAvatar::exists() { return QFileInfo(getFileName()).exists(); } QPixmap FileAvatar::getPixmap() { refresh(); return pixmap(); } void FileAvatar::refresh() { if (isDirty()) { if (QFileInfo(getFileName()).exists()) { QImage img(getFileName()); setImage(QImage(getFileName())); } else resetImage(); } } QString FileAvatar::getFileName() const { QString f = getJid().bare(); f.replace('@',"_at_"); return QDir(AvatarFactory::getManualDir()).filePath(f); } bool FileAvatar::isDirty() const { return (pixmap().isNull() || !QFileInfo(getFileName()).exists() || QFileInfo(getFileName()).lastModified() > lastModified()); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Avatar factory //------------------------------------------------------------------------------ AvatarFactory::AvatarFactory(PsiAccount* pa) : pa_(pa) { // Register iconset iconset_.addToFactory(); // Connect signals connect(VCardFactory::instance(),SIGNAL(vcardChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&))); connect(pa_->client(), SIGNAL(resourceAvailable(const Jid &, const Resource &)), SLOT(resourceAvailable(const Jid &, const Resource &))); // PEP connect(pa_->pepManager(),SIGNAL(itemPublished(const Jid&, const QString&, const PubSubItem&)),SLOT(itemPublished(const Jid&, const QString&, const PubSubItem&))); connect(pa_->pepManager(),SIGNAL(publish_success(const QString&, const PubSubItem&)),SLOT(publish_success(const QString&,const PubSubItem&))); } PsiAccount* AvatarFactory::account() const { return pa_; } inline static QPixmap ensureSquareAvatar(const QPixmap& original) { if (original.isNull() || original.width() == original.height()) return original; int size = qMax(original.width(), original.height()); QPixmap square = PixmapUtil::createTransparentPixmap(size, size); QPainter p(&square); p.drawPixmap((size - original.width()) / 2, (size - original.height()) / 2, original); return square; } QPixmap AvatarFactory::getAvatar(const Jid& _jid) { // protect from race condition when caller gets // deleted as result of avatarChanged() signal Jid jid = _jid; // Compute the avatar of the user Avatar* av = retrieveAvatar(jid); // If the avatar changed since the previous request, notify everybody of this if (av != active_avatars_[jid.full()]) { active_avatars_[jid.full()] = av; active_avatars_[jid.bare()] = av; emit avatarChanged(jid); } QPixmap pm = (av ? av->getPixmap() : QPixmap()); pm = ensureSquareAvatar(pm); // Update iconset PsiIcon icon; icon.setImpix(pm); iconset_.setIcon(QString("avatars/%1").arg(jid.bare()),icon); return pm; } Avatar* AvatarFactory::retrieveAvatar(const Jid& jid) { //printf("Retrieving avatar of %s\n", jid.full().latin1()); // Try finding a file avatar. //printf("File avatar\n"); if (!file_avatars_.contains(jid.bare())) { //printf("File avatar not yet loaded\n"); file_avatars_[jid.bare()] = new FileAvatar(this, jid); } //printf("Trying file avatar\n"); if (!file_avatars_[jid.bare()]->isEmpty()) return file_avatars_[jid.bare()]; //printf("PEP avatar\n"); if (pep_avatars_.contains(jid.bare()) && !pep_avatars_[jid.bare()]->isEmpty()) { return pep_avatars_[jid.bare()]; } // Try finding a vcard avatar //printf("VCard avatar\n"); if (vcard_avatars_.contains(jid.bare()) && !vcard_avatars_[jid.bare()]->isEmpty()) { return vcard_avatars_[jid.bare()]; } // Try finding a static vcard avatar //printf("Static VCard avatar\n"); if (!vcard_static_avatars_.contains(jid.bare())) { //printf("Static vcard avatar not yet loaded\n"); vcard_static_avatars_[jid.bare()] = new VCardStaticAvatar(this, jid); connect(vcard_static_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&))); } if (!vcard_static_avatars_[jid.bare()]->isEmpty()) { return vcard_static_avatars_[jid.bare()]; } return 0; } void AvatarFactory::setSelfAvatar(const QString& fileName) { if (!fileName.isEmpty()) { QFile avatar_file(fileName); if (!avatar_file.open(QIODevice::ReadOnly)) return; QByteArray avatar_data = scaleAvatar(avatar_file.readAll()); QImage avatar_image = QImage::fromData(avatar_data); if(!avatar_image.isNull()) { // Publish data QDomDocument* doc = account()->client()->doc(); QString hash = Hash("sha1").hashToString(avatar_data); QDomElement el = doc->createElement("data"); el.setAttribute("xmlns","http://www.xmpp.org/extensions/xep-0084.html#ns-data "); el.appendChild(doc->createTextNode(Base64().arrayToString(avatar_data))); selfAvatarData_ = avatar_data; selfAvatarHash_ = hash; account()->pepManager()->publish("http://www.xmpp.org/extensions/xep-0084.html#ns-data",PubSubItem(hash,el)); } } else { QDomDocument* doc = account()->client()->doc(); QDomElement meta_el = doc->createElement("metadata"); meta_el.setAttribute("xmlns","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); meta_el.appendChild(doc->createElement("stop")); account()->pepManager()->publish("http://www.xmpp.org/extensions/xep-0084.html#ns-metadata",PubSubItem("current",meta_el)); } } void AvatarFactory::updateAvatar(const Jid& j) { getAvatar(j); // FIXME: This signal might be emitted twice (first time from getAvatar()). emit avatarChanged(j); } void AvatarFactory::importManualAvatar(const Jid& j, const QString& fileName) { FileAvatar(this, j).import(fileName); emit avatarChanged(j); } void AvatarFactory::removeManualAvatar(const Jid& j) { FileAvatar(this, j).removeFromDisk(); // TODO: Remove from caches. Maybe create a clearManualAvatar() which // removes the file but doesn't remove the avatar from caches (since it'll // be created again whenever the FileAvatar is requested) emit avatarChanged(j); } bool AvatarFactory::hasManualAvatar(const Jid& j) { return FileAvatar(this, j).exists(); } void AvatarFactory::resourceAvailable(const Jid& jid, const Resource& r) { if (r.status().hasPhotoHash()) { QString hash = r.status().photoHash(); if (!vcard_avatars_.contains(jid.bare())) { vcard_avatars_[jid.bare()] = new VCardAvatar(this, jid); connect(vcard_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&))); } vcard_avatars_[jid.bare()]->updateHash(hash); } } QString AvatarFactory::getManualDir() { QDir avatars(pathToProfile(activeProfile) + "/pictures"); if (!avatars.exists()) { QDir profile(pathToProfile(activeProfile)); profile.mkdir("pictures"); } return avatars.path(); } QString AvatarFactory::getCacheDir() { QDir avatars(ApplicationInfo::homeDir() + "/avatars"); if (!avatars.exists()) { QDir home(ApplicationInfo::homeDir()); home.mkdir("avatars"); } return avatars.path(); } int AvatarFactory::maxAvatarSize() { return MAX_AVATAR_SIZE; } void AvatarFactory::itemPublished(const Jid& jid, const QString& n, const PubSubItem& item) { if (n == "http://www.xmpp.org/extensions/xep-0084.html#ns-data") { if (item.payload().tagName() == "data") { if (pep_avatars_.contains(jid.bare())) { pep_avatars_[jid.bare()]->setData(item.id(),item.payload().text()); } } else { qWarning("avatars.cpp: Unexpected item payload"); } } else if (n == "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata") { if (!pep_avatars_.contains(jid.bare())) { pep_avatars_[jid.bare()] = new PEPAvatar(this, jid.bare()); connect(pep_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this, SLOT(updateAvatar(const Jid&))); } QDomElement e; bool found; e = findSubTag(item.payload(), "stop", &found); if (found) { pep_avatars_[jid.bare()]->updateHash(""); } else { pep_avatars_[jid.bare()]->updateHash(item.id()); } } } void AvatarFactory::publish_success(const QString& n, const PubSubItem& item) { if (n == "http://www.xmpp.org/extensions/xep-0084.html#ns-data" && item.id() == selfAvatarHash_) { // Publish metadata QDomDocument* doc = account()->client()->doc(); QImage avatar_image = QImage::fromData(selfAvatarData_); QDomElement meta_el = doc->createElement("metadata"); meta_el.setAttribute("xmlns","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); QDomElement info_el = doc->createElement("info"); info_el.setAttribute("id",selfAvatarHash_); info_el.setAttribute("bytes",avatar_image.numBytes()); info_el.setAttribute("height",avatar_image.height()); info_el.setAttribute("width",avatar_image.width()); info_el.setAttribute("type",image2type(selfAvatarData_)); meta_el.appendChild(info_el); account()->pepManager()->publish("http://www.xmpp.org/extensions/xep-0084.html#ns-metadata",PubSubItem(selfAvatarHash_,meta_el)); } } //------------------------------------------------------------------------------ #include "avatars.moc" ���������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/fileutil.h�����������������������������������������������������������������������������0000644�0001750�0001750�00000002773�11305557613�013127� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * fileutil.h - common file dialogs * Copyright (C) 2008 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef FILEUTIL_H #define FILEUTIL_H #include <QObject> class QWidget; class FileUtil : public QObject { Q_OBJECT public: static QString lastUsedOpenPath(); static void setLastUsedOpenPath(const QString& path); static QString lastUsedSavePath(); static void setLastUsedSavePath(const QString& path); static QString getImageFileName(QWidget* parent); static QString getOpenFileName(QWidget* parent = 0, const QString& caption = QString(), const QString& filter = QString(), QString* selectedFilter = 0); static QString getSaveFileName(QWidget* parent = 0, const QString& caption = QString(), const QString& defaultFileName = QString(), const QString& filter = QString(), QString* selectedFilter = 0); }; #endif �����psi-0.14/src/moodcatalog.h��������������������������������������������������������������������������0000644�0001750�0001750�00000003002�11305557613�013565� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * moodcatalog.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MOODCATALOG_H #define MOODCATALOG_H #include <QList> #include <QObject> #include "mood.h" class QString; class MoodCatalog : public QObject { public: class Entry { public: Entry(); Entry(Mood::Type, const QString&, const QString&); Mood::Type type() const; const QString& value() const; const QString& text() const; bool isNull() const; private: Mood::Type type_; QString value_; QString text_; }; static MoodCatalog* instance(); Entry findEntryByType(Mood::Type) const; Entry findEntryByValue(const QString&) const; Entry findEntryByText(const QString& text) const; const QList<Entry>& entries() const; private: MoodCatalog(); QList<Entry> entries_; static MoodCatalog* instance_; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/applicationinfo.cpp��������������������������������������������������������������������0000644�0001750�0001750�00000013416�11305560074�015013� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QString> #include <QDir> #include <QFile> #ifdef Q_WS_X11 #include <sys/stat.h> // chmod #endif #ifdef Q_WS_WIN #include <windows.h> #endif #ifdef Q_WS_MAC #include <sys/stat.h> // chmod #include <CoreServices/CoreServices.h> #endif #include "applicationinfo.h" #include "profiles.h" #ifdef HAVE_CONFIG #include "config.h" #endif // Constants. These should be moved to a more 'dynamically changeable' // place (like an external file loaded through the resources system) // Should also be overridable through an optional file. #define PROG_NAME "Psi" //#define PROG_VERSION "0.14-dev" " (" __DATE__ ")"; //CVS Builds are dated #define PROG_VERSION "0.14"; #define PROG_CAPS_NODE "http://psi-im.org/caps"; #define PROG_CAPS_VERSION "caps-b75d8d2b25"; #define PROG_IPC_NAME "org.psi-im.Psi" // must not contain '\\' character on Windows #define PROG_OPTIONS_NS "http://psi-im.org/options"; #define PROG_STORAGE_NS "http://psi-im.org/storage"; #ifdef Q_WS_MAC #define PROG_APPCAST_URL "http://psi-im.org/appcast/psi-mac.xml"; #else #define PROG_APPCAST_URL ""; #endif #if defined(Q_WS_X11) && !defined(PSI_DATADIR) #define PSI_DATADIR "/usr/local/share/psi" #endif QString ApplicationInfo::name() { return PROG_NAME; } QString ApplicationInfo::version() { return PROG_VERSION; } QString ApplicationInfo::capsNode() { return PROG_CAPS_NODE; } QString ApplicationInfo::capsVersion() { return PROG_CAPS_VERSION; } QString ApplicationInfo::IPCName() { return PROG_IPC_NAME; } QString ApplicationInfo::getAppCastURL() { return PROG_APPCAST_URL; } QString ApplicationInfo::optionsNS() { return PROG_OPTIONS_NS; } QString ApplicationInfo::storageNS() { return PROG_STORAGE_NS; } QStringList ApplicationInfo::getCertificateStoreDirs() { QStringList l; l += ApplicationInfo::resourcesDir() + "/certs"; l += ApplicationInfo::homeDir() + "/certs"; return l; } QString ApplicationInfo::getCertificateStoreSaveDir() { QDir certsave(homeDir() + "/certs"); if(!certsave.exists()) { QDir home(homeDir()); home.mkdir("certs"); } return certsave.path(); } QString ApplicationInfo::resourcesDir() { #if defined(Q_WS_X11) return PSI_DATADIR; #elif defined(Q_WS_WIN) return qApp->applicationDirPath(); #elif defined(Q_WS_MAC) // FIXME: Clean this up (remko) // System routine locates resource files. We "know" that Psi.icns is // in the Resources directory. QString resourcePath; CFBundleRef mainBundle = CFBundleGetMainBundle(); CFStringRef resourceCFStringRef = CFStringCreateWithCString( NULL, "application.icns", kCFStringEncodingASCII ); CFURLRef resourceURLRef = CFBundleCopyResourceURL( mainBundle, resourceCFStringRef, NULL, NULL ); if ( resourceURLRef ) { CFStringRef resourcePathStringRef = CFURLCopyFileSystemPath( resourceURLRef, kCFURLPOSIXPathStyle ); const char* resourcePathCString = CFStringGetCStringPtr( resourcePathStringRef, kCFStringEncodingASCII ); if ( resourcePathCString ) { resourcePath = resourcePathCString; } else { // CFStringGetCStringPtr failed; use fallback conversion CFIndex bufferLength = CFStringGetLength( resourcePathStringRef ) + 1; char* resourcePathCString = new char[ bufferLength ]; Boolean conversionSuccess = CFStringGetCString( resourcePathStringRef, resourcePathCString, bufferLength, kCFStringEncodingASCII ); if ( conversionSuccess ) { resourcePath = resourcePathCString; } delete [] resourcePathCString; // I own this } CFRelease( resourcePathStringRef ); // I own this } // Remove the tail component of the path if ( ! resourcePath.isNull() ) { QFileInfo fileInfo( resourcePath ); resourcePath = fileInfo.absolutePath(); } return resourcePath; #endif } QString ApplicationInfo::libDir() { #if defined(Q_OS_UNIX) return PSI_LIBDIR; #else return QString(); #endif } /** \brief return psi's private read write data directory * unix+mac: $HOME/.psi * environment variable "PSIDATADIR" overrides */ QString ApplicationInfo::homeDir() { // Try the environment override first char *p = getenv("PSIDATADIR"); if(p) return p; #if defined(Q_WS_X11) QDir proghome(QDir::homePath() + "/.psi"); if(!proghome.exists()) { QDir home = QDir::home(); home.mkdir(".psi"); chmod(QFile::encodeName(proghome.path()), 0700); } return proghome.path(); #elif defined(Q_WS_WIN) QString base; // Windows 9x if(QDir::homePath() == QDir::rootPath()) base = "."; // Windows NT/2K/XP variant else base = QDir::homePath(); // no trailing slash if(base.at(base.length()-1) == '/') base.truncate(base.length()-1); QDir proghome(base + "/PsiData"); if(!proghome.exists()) { QDir home(base); home.mkdir("PsiData"); } return proghome.path(); #elif defined(Q_WS_MAC) QDir proghome(QDir::homePath() + "/.psi"); if(!proghome.exists()) { QDir home = QDir::home(); home.mkdir(".psi"); chmod(QFile::encodeName(proghome.path()), 0700); } return proghome.path(); #endif } QString ApplicationInfo::historyDir() { QDir history(pathToProfile(activeProfile) + "/history"); if (!history.exists()) { QDir profile(pathToProfile(activeProfile)); profile.mkdir("history"); } return history.path(); } QString ApplicationInfo::vCardDir() { QDir vcard(pathToProfile(activeProfile) + "/vcard"); if (!vcard.exists()) { QDir profile(pathToProfile(activeProfile)); profile.mkdir("vcard"); } return vcard.path(); } QString ApplicationInfo::profilesDir() { QString profiles_dir(homeDir() + "/profiles"); QDir d(profiles_dir); if(!d.exists()) { QDir d(homeDir()); d.mkdir("profiles"); } return profiles_dir; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/discodlg.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000110422�11305557613�013424� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * discodlg.cpp - main dialog for the Service Discovery protocol * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "discodlg.h" #include <QTreeWidget> #include <QHeaderView> #include <QMenu> #include <QComboBox> #include <QCheckBox> #include <QMessageBox> #include <QAction> #include <QSignalMapper> #include <QPushButton> #include <QToolButton> #include <QToolBar> #include <QScrollBar> #include <QActionGroup> #include <QEvent> #include <QList> #include <QContextMenuEvent> #include "xmpp_tasks.h" #include "tasklist.h" #include "psiaccount.h" #include "psicon.h" #include "busywidget.h" #include "iconaction.h" #include "psiiconset.h" #include "psitooltip.h" #include "stretchwidget.h" #include "psioptions.h" #include "accountlabel.h" //---------------------------------------------------------------------------- PsiIcon category2icon(const QString &category, const QString &type, int status=STATUS_ONLINE) { // TODO: update this to http://www.jabber.org/registrar/disco-categories.html#gateway // still have to add more options... if ( category == "service" || category == "gateway" ) { QString trans; if (type == "aim") trans = "aim"; else if (type == "icq") trans = "icq"; else if (type == "msn") trans = "msn"; else if (type == "yahoo") trans = "yahoo"; else if (type == "gadu-gadu" || type == "x-gadugadu") trans = "gadugadu"; else if (type == "sms") trans = "sms"; else trans = "transport"; return PsiIconset::instance()->transportStatus(trans, status); // irc // jud // pager // jabber // serverlist // smtp } else if ( category == "conference" ) { if (type == "public" || type == "private" || type == "text" || type == "irc") return IconsetFactory::icon("psi/groupChat"); else if (type == "url") return IconsetFactory::icon("psi/www"); // irc // list // topic } else if ( category == "validate" ) { if (type == "xml") return IconsetFactory::icon("psi/xml"); // grammar // spell } else if ( category == "user" || category == "client" ) { // client // forward // inbox // portable // voice return PsiIconset::instance()->status(STATUS_ONLINE); } // application // bot // calendar // editor // fileserver // game // whiteboard // headline // logger // notice // rss // stock // keyword // dictionary // dns // software // thesaurus // web // whois // render // en2ru // ??2?? // tts return PsiIcon(); } //---------------------------------------------------------------------------- // DiscoData -- a shared data struct //---------------------------------------------------------------------------- class DiscoListItem; class DiscoConnector : public QObject { Q_OBJECT public: DiscoConnector(QObject *parent) : QObject(parent) {} signals: void itemUpdated(QTreeWidgetItem *); private: friend class DiscoListItem; }; struct DiscoData { PsiAccount *pa; TaskList *tasks; DiscoConnector *d; enum Protocol { Auto, Disco, Browse, Agents }; Protocol protocol; }; //---------------------------------------------------------------------------- // DiscoListItem //---------------------------------------------------------------------------- class DiscoListItem : public QObject, public QTreeWidgetItem { Q_OBJECT public: DiscoListItem(DiscoItem it, DiscoData *d, QTreeWidget *parent); DiscoListItem(DiscoItem it, DiscoData *d, QTreeWidgetItem *parent); ~DiscoListItem(); void setExpanded(bool expand); const DiscoItem &item() const; void itemSelected(); public slots: // the two are used internally by class, and also called by DiscoDlg::Private::refresh() void updateInfo(); void updateItems(bool parentAutoItems = false); QString getErrorInfo() const; private slots: void discoItemsFinished(); void discoInfoFinished(); void doBrowse(bool parentAutoItems = false); void doAgents(bool parentAutoItems = false); void browseFinished(); void agentsFinished(); private: DiscoItem di; DiscoData *d; bool isRoot; bool alreadyItems, alreadyInfo; bool autoItems; // used in updateItemsFinished bool autoInfo; QString errorInfo; void copyItem(const DiscoItem &); void updateInfo(const DiscoItem &); void updateItemsFinished(const DiscoList &); void autoItemsChildren() const; // automatically call disco#items for children :-) QString hash() { return computeHash( item().jid().full(), item().node() ); } QString computeHash( QString jid, QString node ); // helper functions void init(DiscoItem it, DiscoData *dd); void hideChildIndicator(); bool autoItemsEnabled() const; bool autoInfoEnabled() const; DiscoDlg *dlg() const; }; DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, QTreeWidget *parent) : QTreeWidgetItem (parent) { isRoot = true; init(it, _d); } DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, QTreeWidgetItem *parent) : QTreeWidgetItem (parent) { isRoot = false; init(it, _d); } DiscoListItem::~DiscoListItem() { } void DiscoListItem::init(DiscoItem _item, DiscoData *_d) { d = _d; di = _item; copyItem(_item); alreadyItems = alreadyInfo = false; if ( !autoItemsEnabled() ) setChildIndicatorPolicy(ShowIndicator); autoInfo = false; if ( autoInfoEnabled() || isRoot ) { updateInfo(); if ( !isRoot ) autoInfo = true; } } void DiscoListItem::copyItem(const DiscoItem &it) { if ( !(!di.jid().full().isEmpty() && it.jid().full().isEmpty()) ) di.setJid ( it.jid() ); if ( !(!di.node().isEmpty() && it.node().isEmpty()) ) di.setNode ( it.node() ); if ( !(!di.name().isEmpty() && it.name().isEmpty()) ) di.setName ( it.name() ); if ( di.name().isEmpty() && !di.jid().full().isEmpty() ) // use JID in the Name column di.setName ( di.jid().full() ); di.setAction ( it.action() ); if ( !(!di.features().list().isEmpty() && it.features().list().isEmpty()) ) di.setFeatures ( it.features() ); if ( !(!di.identities().isEmpty() && it.identities().isEmpty()) ) di.setIdentities ( it.identities() ); if ( di.jid().bare().left(4) == "jud." || di.jid().bare().left(6) == "users." ) { // nasty hack for the nasty (and outdated) JUD service :-/ if ( !di.features().canSearch() ) { QStringList features = di.features().list(); features << "jabber:iq:search"; di.setFeatures( features ); } bool found = false; DiscoItem::Identities::ConstIterator it = di.identities().begin(); for ( ; it != di.identities().end(); ++it) { if ( (*it).category == "service" && (*it).type == "jud" ) { found = true; break; } } if ( !found ) { DiscoItem::Identity id; id.category = "service"; id.type = "jud"; DiscoItem::Identities ids; ids << id; di.setIdentities( ids ); } } setText(0, di.name().simplified()); setText(1, di.jid().full()); setText(2, di.node().simplified()); bool iconOk = false; if ( !di.identities().isEmpty() ) { DiscoItem::Identity id = di.identities().first(); if ( !id.category.isEmpty() ) { QIcon icon = category2icon(id.category, id.type).icon(); if ( !icon.isNull() ) { setIcon(0, icon); iconOk = true; } } } if ( !iconOk ) setIcon(0, PsiIconset::instance()->status(di.jid(), STATUS_ONLINE).icon()); if ( isSelected() ) // update actions emit d->d->itemUpdated( this ); } QString DiscoListItem::getErrorInfo() const { return errorInfo; } const DiscoItem &DiscoListItem::item() const { return di; } DiscoDlg *DiscoListItem::dlg() const { return (DiscoDlg *)treeWidget()->parent(); } bool DiscoListItem::autoItemsEnabled() const { return dlg()->ck_autoItems->isChecked(); } bool DiscoListItem::autoInfoEnabled() const { return dlg()->ck_autoInfo->isChecked(); } void DiscoListItem::setExpanded (bool expand) { if ( expand ) { if ( !alreadyItems ) updateItems(); else autoItemsChildren(); } QTreeWidgetItem::setExpanded(expand); } void DiscoListItem::itemSelected() { if ( !alreadyInfo ) updateInfo(); } void DiscoListItem::updateItems(bool parentAutoItems) { if ( parentAutoItems ) { // save traffic if ( alreadyItems ) return; // FIXME: currently, JUD doesn't seem to answer to browsing requests if ( item().identities().size() ) { DiscoItem::Identity id = item().identities().first(); if ( id.category == "service" && id.type == "jud" ) return; } QString j = item().jid().domain(); // just another method to discover if we're gonna to browse JUD if ( item().jid().node().isEmpty() && (j.left(4) == "jud." || j.left(6) == "users.") ) return; } autoItems = !parentAutoItems; if ( !autoItemsEnabled() ) autoItems = false; if ( d->protocol == DiscoData::Auto || d->protocol == DiscoData::Disco ) { JT_DiscoItems *jt = new JT_DiscoItems(d->pa->client()->rootTask()); connect(jt, SIGNAL(finished()), SLOT(discoItemsFinished())); jt->get(di.jid(), di.node()); jt->go(true); d->tasks->append(jt); } else if ( d->protocol == DiscoData::Browse ) doBrowse(parentAutoItems); else if ( d->protocol == DiscoData::Agents ) doAgents(parentAutoItems); } void DiscoListItem::discoItemsFinished() { JT_DiscoItems *jt = (JT_DiscoItems *)sender(); if ( jt->success() ) { updateItemsFinished(jt->items()); } else if ( d->protocol == DiscoData::Auto ) { doBrowse(); return; } else if ( !autoItems ) { QString error = jt->statusString(); QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting items for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error).replace('\n', "<br>"))); } alreadyItems = true; } void DiscoListItem::doBrowse(bool parentAutoItems) { if ( parentAutoItems ) { // save traffic if ( alreadyItems ) return; if ( item().identities().size() ) { DiscoItem::Identity id = item().identities().first(); if ( id.category == "service" && id.type == "jud" ) return; } } autoItems = !parentAutoItems; if ( !autoItemsEnabled() ) autoItems = false; JT_Browse *jt = new JT_Browse(d->pa->client()->rootTask()); connect(jt, SIGNAL(finished()), SLOT(browseFinished())); jt->get(di.jid()); jt->go(true); d->tasks->append(jt); } void DiscoListItem::browseFinished() { JT_Browse *jt = (JT_Browse *)sender(); if ( jt->success() ) { // update info DiscoItem root; root.fromAgentItem( jt->root() ); updateInfo(root); alreadyInfo = true; autoInfo = false; // update items AgentList from = jt->agents(); DiscoList to; AgentList::Iterator it = from.begin(); for ( ; it != from.end(); ++it) { DiscoItem item; item.fromAgentItem( *it ); to.append( item ); } updateItemsFinished(to); } else if ( d->protocol == DiscoData::Auto ) { doAgents(); return; } else if ( !autoItems ) { QString error = jt->statusString(); QMessageBox::critical(dlg(), tr("Error"), tr("There was an error browsing items for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error).replace('\n', "<br>"))); } alreadyItems = true; } void DiscoListItem::doAgents(bool parentAutoItems) { if ( parentAutoItems ) { // save traffic if ( alreadyItems ) return; if ( item().identities().size() ) { DiscoItem::Identity id = item().identities().first(); if ( id.category == "service" && id.type == "jud" ) return; } } autoItems = !parentAutoItems; if ( !autoItemsEnabled() ) autoItems = false; JT_GetServices *jt = new JT_GetServices(d->pa->client()->rootTask()); connect(jt, SIGNAL(finished()), SLOT(agentsFinished())); jt->get(di.jid()); jt->go(true); d->tasks->append(jt); } void DiscoListItem::agentsFinished() { JT_GetServices *jt = (JT_GetServices *)sender(); if ( jt->success() ) { // update info DiscoItem root; DiscoItem::Identity id; id.name = tr("Jabber Service"); id.category = "service"; id.type = "jabber"; DiscoItem::Identities ids; ids.append(id); root.setIdentities(ids); updateInfo(root); alreadyInfo = true; autoInfo = false; // update items AgentList from = jt->agents(); DiscoList to; AgentList::Iterator it = from.begin(); for ( ; it != from.end(); ++it) { DiscoItem item; item.fromAgentItem( *it ); to.append( item ); } updateItemsFinished(to); } else if ( !autoItems ) { QString error = jt->statusString(); QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting agents for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error).replace('\n', "<br>"))); } alreadyItems = true; } QString DiscoListItem::computeHash( QString jid, QString node ) { QString ret = jid.replace( '@', "\\@" ); ret += "@"; ret += node.replace( '@', "\\@" ); return ret; } void DiscoListItem::hideChildIndicator() { setChildIndicatorPolicy(DontShowIndicator); #if QT_VERSION >= 0x040500 emitDataChanged(); #else Qt::ItemFlags tmp = flags(); setFlags(0); setFlags(tmp); #endif } void DiscoListItem::updateItemsFinished(const DiscoList &list) { treeWidget()->setUpdatesEnabled(false); QHash<QString, DiscoListItem*> children; DiscoListItem *child = (DiscoListItem *)QTreeWidgetItem::child(0); for ( int i = 1; child; ++i ) { children.insert( child->hash(), child ); child = (DiscoListItem *)QTreeWidgetItem::child(i); } // add/update items for(DiscoList::ConstIterator it = list.begin(); it != list.end(); ++it) { const DiscoItem a = *it; QString key = computeHash(a.jid().full(), a.node()); child = children[ key ]; if ( child ) { child->copyItem ( a ); children.remove( key ); } else { new DiscoListItem (a, d, this); } } // remove all items that are not on new DiscoList qDeleteAll(children); children.clear(); if ( autoItems && isExpanded() ) autoItemsChildren(); if (list.isEmpty()) { hideChildIndicator(); } // root item is initially hidden if ( isRoot && isHidden() ) setHidden(false); treeWidget()->setUpdatesEnabled(true); } void DiscoListItem::autoItemsChildren() const { if ( !autoItemsEnabled() ) return; DiscoListItem *child = (DiscoListItem *)QTreeWidgetItem::child(0); for ( int i = 1; child; ++i ) { child->updateItems(true); child = (DiscoListItem *)QTreeWidgetItem::child(i); } } void DiscoListItem::updateInfo() { if ( d->protocol != DiscoData::Auto && d->protocol != DiscoData::Disco ) return; JT_DiscoInfo *jt = new JT_DiscoInfo(d->pa->client()->rootTask()); connect(jt, SIGNAL(finished()), SLOT(discoInfoFinished())); jt->get(di.jid(), di.node()); jt->go(true); d->tasks->append(jt); } void DiscoListItem::discoInfoFinished() { JT_DiscoInfo *jt = (JT_DiscoInfo *)sender(); if ( jt->success() ) { updateInfo( jt->item() ); } else { QString error_str = jt->statusString(); int error_code = jt->statusCode(); hideChildIndicator(); // we change the icon for the items with disco#info returning type=="cancel" || type=="wait" error codes // based on http://www.jabber.org/jeps/jep-0086.html // FIXME: use another method for checking XMPP error-types when Iris will provide one if ( error_code==400 || error_code==404 || error_code==405 || error_code==409 || error_code==500 || error_code==501 || error_code==503 || error_code==504 ) { bool iconOk = false; if ( !di.identities().isEmpty() ) { DiscoItem::Identity id = di.identities().first(); if ( !id.category.isEmpty() ) { QIcon icon = category2icon(id.category, id.type, STATUS_ERROR).icon(); if ( !icon.isNull() ) { setIcon (0, icon); iconOk = true; } } } if ( !iconOk ) setIcon(0, PsiIconset::instance()->status(di.jid(), STATUS_ERROR).icon()); } errorInfo=QString("%1").arg(QString(error_str).replace('\n', "<br>")); if ( !autoInfo && d->protocol != DiscoData::Auto ) { QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting item's info for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error_str).replace('\n', "<br>"))); } } alreadyInfo = true; autoInfo = false; } void DiscoListItem::updateInfo(const DiscoItem &item) { copyItem( item ); if ( isRoot && isHidden() ) setHidden(false); } //---------------------------------------------------------------------------- // DiscoList //---------------------------------------------------------------------------- class DiscoListView : public QTreeWidget { Q_OBJECT public: DiscoListView(QWidget *parent); protected: bool maybeTip(const QPoint &); // reimplemented bool eventFilter(QObject* o, QEvent* e); void resizeEvent(QResizeEvent*); }; DiscoListView::DiscoListView(QWidget *parent) : QTreeWidget(parent) { installEventFilter(this); setHeaderLabels( QStringList() << tr( "Name" ) << tr( "JID" ) << tr( "Node" ) ); // header()->setResizeMode(0, QHeaderView::Stretch); // header()->setResizeMode(1, QHeaderView::ResizeToContents); // header()->setResizeMode(2, QHeaderView::ResizeToContents); header()->setStretchLastSection(false); setRootIsDecorated(false); } void DiscoListView::resizeEvent(QResizeEvent* e) { QTreeWidget::resizeEvent(e); QHeaderView* h = header(); h->resizeSection(2, h->fontMetrics().width(headerItem()->text(2)) * 2); float remainingWidth = viewport()->width() - h->sectionSize(2); h->resizeSection(1, int(remainingWidth * 0.3)); h->resizeSection(0, int(remainingWidth * 0.7)); //h->adjustHeaderSize(); } /** * \param pos should be in global coordinate system. */ bool DiscoListView::maybeTip(const QPoint &pos) { DiscoListItem* i = (DiscoListItem*)itemAt(viewport()->mapFromGlobal(pos)); if(!i) return false; // NAME <JID> (Node "NODE") // // Identities: // (icon) NAME (Category "CATEGORY"; Type "TYPE") // (icon) NAME (Category "CATEGORY"; Type "TYPE") // // Features: // NAME (http://jabber.org/feature) // NAME (http://jabber.org/feature) // top row QString text = "<qt><nobr>"; DiscoItem item = i->item(); if ( item.name()!=item.jid().full() ) text += item.name() + " "; text += "<" + item.jid().full() + ">"; if ( !item.node().isEmpty() ) text += " (" + tr("Node") + " \"" + item.node() + "\")"; text += "</nobr>"; if ( !item.identities().isEmpty() || !item.features().list().isEmpty() ) text += "<br>\n"; // identities if ( !item.identities().isEmpty() ) { text += "<br>\n<b>" + tr("Identities:") + "</b>\n"; DiscoItem::Identities::ConstIterator it = item.identities().begin(); for ( ; it != item.identities().end(); ++it) { text += "<br>"; PsiIcon icon( category2icon((*it).category, (*it).type) ); if ( !icon.name().isEmpty() ) text += "<icon name=\"" + icon.name() + "\"> "; text += (*it).name; text += " (" + tr("Category") + " \"" + (*it).category + "\"; " + tr("Type") + " \"" + (*it).type + "\")\n"; } if ( !item.features().list().isEmpty() ) text += "<br>\n"; } // features if ( !item.features().list().isEmpty() ) { text += "<br>\n<b>" + tr("Features:") + "</b>\n"; QStringList features = item.features().list(); QStringList::ConstIterator it = features.begin(); for ( ; it != features.end(); ++it) { Features f( *it ); text += "\n<br>"; if ( f.id() > Features::FID_None ) text += f.name() + " ("; text += *it; if ( f.id() > Features::FID_None ) text += ")"; } } QString errorInfo=i->getErrorInfo(); if ( !errorInfo.isEmpty() ) { text += "<br>\n<br>\n<b>" + tr("Error:") + "</b>\n"; text += errorInfo; } text += "</qt>"; QRect r( visualItemRect(i) ); PsiToolTip::showText(pos, text, this); return true; } bool DiscoListView::eventFilter(QObject* o, QEvent* e) { if (e->type() == QEvent::ToolTip && o->isWidgetType()) { QWidget* w = static_cast<QWidget*>(o); QHelpEvent* he = static_cast<QHelpEvent*>(e); maybeTip(w->mapToGlobal(he->pos())); return true; } return QTreeWidget::eventFilter(o, e); } //---------------------------------------------------------------------------- // DiscoDlg::Private //---------------------------------------------------------------------------- class DiscoDlg::Private : public QObject { Q_OBJECT private: class ProtocolAction : public QAction { public: ProtocolAction(QString text, QString toolTip, QObject *parent, QSignalMapper *sm, int parm) : QAction(text, parent) { setText(text); setIconText(text); setCheckable(true); setToolTip(toolTip); connect(this, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(this, parm); } }; // helper class to store browser history class History { public: History(const XMPP::Jid& _jid, const QString& _node) : jid(_jid) , node(_node) {} XMPP::Jid jid; QString node; }; public: // data DiscoDlg *dlg; Jid jid; QString node; DiscoData data; QToolBar *toolBar; IconAction *actBrowse, *actBack, *actForward, *actRefresh, *actStop; // custom actions, that will be added to toolbar and context menu IconAction *actRegister, *actSearch, *actJoin, *actAHCommand, *actVCard, *actAdd; typedef QList<History*> HistoryList; HistoryList backHistory, forwardHistory; BusyWidget *busy; public: // functions Private(DiscoDlg *parent, PsiAccount *pa); ~Private(); public slots: void doDisco(QString host = QString::null, QString node = QString::null, bool doHistory = true); void actionStop(); void actionRefresh(); void actionBrowse(); void actionBack(); void actionForward(); void updateBackForward(); void updateComboBoxes(Jid j, QString node); void itemUpdateStarted(); void itemUpdateFinished(); void disableButtons(); void enableButtons(const DiscoItem &); void itemSelected (QTreeWidgetItem *); void itemExpanded (QTreeWidgetItem *); void itemDoubleclicked (QTreeWidgetItem *); bool eventFilter (QObject *, QEvent *); void setProtocol(int); // features... void actionActivated(int); void objectDestroyed(QObject *); private: friend class DiscoListItem; }; DiscoDlg::Private::Private(DiscoDlg *parent, PsiAccount *pa) { dlg = parent; data.pa = pa; data.tasks = new TaskList; connect(data.tasks, SIGNAL(started()), SLOT(itemUpdateStarted())); connect(data.tasks, SIGNAL(finished()), SLOT(itemUpdateFinished())); data.d = new DiscoConnector(this); connect(data.d, SIGNAL(itemUpdated(QTreeWidgetItem *)), SLOT(itemSelected (QTreeWidgetItem *))); data.protocol = DiscoData::Auto; // mess with widgets busy = parent->busy; connect(busy, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *))); QTreeWidget *lv_discoOld = dlg->lv_disco; dlg->lv_disco = new DiscoListView(dlg); replaceWidget(lv_discoOld, dlg->lv_disco); dlg->lv_disco->installEventFilter (this); connect(dlg->lv_disco, SIGNAL(currentItemChanged (QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(itemSelected (QTreeWidgetItem *)));; connect(dlg->lv_disco, SIGNAL(itemExpanded (QTreeWidgetItem *)), SLOT(itemExpanded (QTreeWidgetItem *))); connect(dlg->lv_disco, SIGNAL(itemDoubleClicked (QTreeWidgetItem *, int)), SLOT(itemDoubleclicked (QTreeWidgetItem *)));; // protocol actions QSignalMapper *pm = new QSignalMapper(this); connect(pm, SIGNAL(mapped(int)), SLOT(setProtocol(int))); QActionGroup *protocolActions = new QActionGroup (this); protocolActions->setExclusive(true); ProtocolAction *autoProtocol = NULL, *discoProtocol = NULL, *browseProtocol = NULL, *agentsProtocol = NULL; if (PsiOptions::instance()->getOption("options.ui.show-deprecated.service-discovery.protocol-selector").toBool()) { autoProtocol = new ProtocolAction (tr("Auto"), tr("Automatically determine protocol"), protocolActions, pm, DiscoData::Auto); discoProtocol = new ProtocolAction ("D", tr("Service Discovery"), protocolActions, pm, DiscoData::Disco); browseProtocol = new ProtocolAction ("B", tr("Browse Services"), protocolActions, pm, DiscoData::Browse); agentsProtocol = new ProtocolAction ("A", tr("Browse Agents"), protocolActions, pm, DiscoData::Agents); autoProtocol->setChecked(true); } // create actions actBrowse = new IconAction (tr("Browse"), "psi/jabber", tr("&Browse"), 0, dlg); connect (actBrowse, SIGNAL(activated()), SLOT(actionBrowse())); actRefresh = new IconAction (tr("Refresh Item"), "psi/reload", tr("&Refresh Item"), 0, dlg); connect (actRefresh, SIGNAL(activated()), SLOT(actionRefresh())); actStop = new IconAction (tr("Stop"), "psi/stop", tr("Sto&p"), 0, dlg); connect (actStop, SIGNAL(activated()), SLOT(actionStop())); actBack = new IconAction (tr("Back"), "psi/arrowLeft", tr("&Back"), 0, dlg); connect (actBack, SIGNAL(activated()), SLOT(actionBack())); actForward = new IconAction (tr("Forward"), "psi/arrowRight", tr("&Forward"), 0, dlg); connect (actForward, SIGNAL(activated()), SLOT(actionForward())); // custom actions QSignalMapper *sm = new QSignalMapper(this); connect(sm, SIGNAL(mapped(int)), SLOT(actionActivated(int))); actRegister = new IconAction (tr("Register"), "psi/register", tr("&Register"), 0, dlg); connect (actRegister, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(actRegister, Features::FID_Register); actSearch = new IconAction (tr("Search"), "psi/search", tr("&Search"), 0, dlg); connect (actSearch, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(actSearch, Features::FID_Search); actJoin = new IconAction (tr("Join"), "psi/groupChat", tr("&Join"), 0, dlg); connect (actJoin, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(actJoin, Features::FID_Groupchat); actAHCommand = new IconAction (tr("Execute command"), "psi/command", tr("&Execute command"), 0, dlg); connect (actAHCommand, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(actAHCommand, Features::FID_AHCommand); actVCard = new IconAction (tr("vCard"), "psi/vCard", tr("&vCard"), 0, dlg); connect (actVCard, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(actVCard, Features::FID_VCard); actAdd = new IconAction (tr("Add to roster"), "psi/addContact", tr("&Add to roster"), 0, dlg); connect (actAdd, SIGNAL(activated()), sm, SLOT(map())); sm->setMapping(actAdd, Features::FID_Add); // create toolbar toolBar = new QToolBar(tr("Service Discovery toolbar"), dlg); toolBar->setIconSize(QSize(16,16)); toolBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); replaceWidget(dlg->toolBarPlaceholder, toolBar); toolBar->addAction(actBack); toolBar->addAction(actBrowse); toolBar->addAction(actForward); toolBar->addSeparator(); toolBar->addAction(actRefresh); toolBar->addAction(actStop); // custom actions toolBar->addSeparator(); toolBar->addAction(actRegister); toolBar->addAction(actSearch); toolBar->addAction(actJoin); toolBar->addSeparator(); toolBar->addAction(actAdd); toolBar->addAction(actVCard); toolBar->addAction(actAHCommand); // select protocol if (PsiOptions::instance()->getOption("options.ui.show-deprecated.service-discovery.protocol-selector").toBool()) { toolBar->addSeparator(); toolBar->addAction(autoProtocol); toolBar->addAction(discoProtocol); toolBar->addAction(browseProtocol); toolBar->addAction(agentsProtocol); } toolBar->addWidget(new StretchWidget(toolBar)); AccountLabel* lb_ident = new AccountLabel(toolBar); lb_ident->setAccount(pa); lb_ident->setShowJid(false); toolBar->addWidget(lb_ident); // misc stuff disableButtons(); actStop->setEnabled(false); // stop action is not handled by disableButtons() updateBackForward(); // same applies to back & forward } DiscoDlg::Private::~Private() { qDeleteAll(backHistory); qDeleteAll(forwardHistory); delete data.tasks; } void DiscoDlg::Private::doDisco(QString _host, QString _node, bool doHistory) { PsiAccount *pa = data.pa; if ( !pa->checkConnected(dlg) ) return; // Strip whitespace Jid j; QString host = _host; if ( host.isEmpty() ) host = dlg->cb_address->currentText(); j = host.trimmed(); if ( !j.isValid() ) return; QString n = _node.trimmed(); if ( n.isEmpty() ) n = dlg->cb_node->currentText().trimmed(); // check, whether we need to update history if ( (jid.full() != j.full()) || (node != n) ) { if (doHistory) { backHistory.append(new History(jid, node)); qDeleteAll(forwardHistory); forwardHistory.clear(); } } jid = j; node = n; updateComboBoxes(jid, node); data.tasks->clear(); // also will call all all necessary functions disableButtons(); updateBackForward(); dlg->lv_disco->clear(); // create new root item DiscoItem di; di.setJid( jid ); di.setNode( node ); DiscoListItem *root = new DiscoListItem (di, &data, dlg->lv_disco); root->setHidden (false); // don't confuse users with empty root root->setExpanded(true); // begin browsing } void DiscoDlg::Private::updateComboBoxes(Jid j, QString n) { data.pa->psi()->recentBrowseAdd( j.full() ); dlg->cb_address->clear(); dlg->cb_address->addItems(data.pa->psi()->recentBrowseList()); data.pa->psi()->recentNodeAdd( n ); dlg->cb_node->clear(); dlg->cb_node->addItems(data.pa->psi()->recentNodeList()); } void DiscoDlg::Private::actionStop() { data.tasks->clear(); } void DiscoDlg::Private::actionRefresh() { DiscoListItem *it = (DiscoListItem *)dlg->lv_disco->currentItem(); if ( !it ) return; it->updateItems(); it->updateInfo(); } void DiscoDlg::Private::actionBrowse() { DiscoListItem *it = (DiscoListItem *)dlg->lv_disco->currentItem(); if ( !it ) return; doDisco(it->item().jid().full(), it->item().node()); } void DiscoDlg::Private::actionBack() { forwardHistory.append(new History(jid, node)); History *h = backHistory.takeLast(); doDisco(h->jid.full(), h->node, false); delete h; } void DiscoDlg::Private::actionForward() { backHistory.append(new History(jid, node)); History *h = forwardHistory.takeLast(); doDisco(h->jid.full(), h->node, false); delete h; } void DiscoDlg::Private::updateBackForward() { actBack->setEnabled ( !backHistory.isEmpty() ); actForward->setEnabled ( !forwardHistory.isEmpty() ); } void DiscoDlg::Private::itemUpdateStarted() { actStop->setEnabled(true); if ( busy ) busy->start(); } void DiscoDlg::Private::itemUpdateFinished() { actStop->setEnabled(false); if ( busy ) busy->stop(); } void DiscoDlg::Private::disableButtons() { DiscoItem di; enableButtons ( di ); } void DiscoDlg::Private::enableButtons(const DiscoItem &it) { bool itemSelected = !it.jid().full().isEmpty(); actRefresh->setEnabled( itemSelected ); actBrowse->setEnabled( itemSelected ); // custom actions Features f = it.features(); actRegister->setEnabled( f.canRegister() ); actSearch->setEnabled( f.canSearch() ); actJoin->setEnabled( f.canGroupchat() ); actAdd->setEnabled( itemSelected ); actVCard->setEnabled( f.haveVCard() ); actAHCommand->setEnabled( f.canCommand() ); } void DiscoDlg::Private::itemSelected (QTreeWidgetItem *item) { DiscoListItem *it = (DiscoListItem *)item; if ( !it ) { disableButtons(); return; } it->itemSelected(); const DiscoItem di = it->item(); enableButtons ( di ); } void DiscoDlg::Private::itemExpanded (QTreeWidgetItem *item) { DiscoListItem *it = (DiscoListItem *)item; if (it) it->setExpanded(true); } void DiscoDlg::Private::itemDoubleclicked (QTreeWidgetItem *item) { DiscoListItem *it = (DiscoListItem *)item; if ( !it ) return; const DiscoItem d = it->item(); const Features &f = d.features(); // set the prior state of item // FIXME: causes minor flickering long id = 0; // trigger default action if (f.canCommand() ) { id = Features::FID_AHCommand; } if (!d.identities().isEmpty()) { // FIXME: check the category and type for JUD! DiscoItem::Identity ident = d.identities().first(); bool searchFirst = ident.category == "service" && ident.type == "jud"; if ( searchFirst && f.canSearch() ) { id = Features::FID_Search; } else if ( ident.category == "conference" && f.canGroupchat() ) { id = Features::FID_Groupchat; } else if ( f.canRegister() ) { id = Features::FID_Register; } } if ( id > 0 ) { if ( !it->isExpanded() ) { if ( it->childCount() ) it->setExpanded( true ); } else { it->setExpanded( false ); } emit dlg->featureActivated( Features::feature(id), d.jid(), d.node() ); } } bool DiscoDlg::Private::eventFilter (QObject *object, QEvent *event) { if ( object == dlg->lv_disco ) { if ( event->type() == QEvent::ContextMenu ) { QContextMenuEvent *e = (QContextMenuEvent *)event; DiscoListItem *it = (DiscoListItem *)dlg->lv_disco->currentItem(); if ( !it ) return true; // prepare features list QList<long> idFeatures; QStringList features = it->item().features().list(); { // convert all features to their IDs QStringList::Iterator it = features.begin(); for ( ; it != features.end(); ++it) { Features f( *it ); if ( f.id() > Features::FID_None ) idFeatures.append( Features::id(*it) ); } //qHeapSort(idFeatures); } QList<long> ids; { // ensure, that there's in no duplicated IDs inside. FIXME: optimize this, anyone? long id = 0, count = 0; QList<long>::Iterator it; while ( count < (long)idFeatures.count() ) { bool found = false; for (it = idFeatures.begin(); it != idFeatures.end(); ++it) { if ( id == *it ) { if ( !found ) { found = true; ids.append( id ); } count++; } } id++; } } // prepare popup menu QMenu p; actBrowse->addTo (&p); actRefresh->addTo (&p); actStop->addTo (&p); // custom actions p.addSeparator(); actRegister->addTo(&p); actSearch->addTo(&p); actJoin->addTo(&p); p.addSeparator(); actAdd->addTo(&p); actVCard->addTo(&p); actAHCommand->addTo(&p); // popup with all available features QMenu *fm = new QMenu(&p); QHash<QAction*, int> actions; { QList<long>::Iterator it = ids.begin(); for ( ; it != ids.end(); ++it) actions.insert(fm->addAction(Features::name(*it)), *it + 10000); // TODO: add pixmap } //p.insertSeparator(); //int menuId = p.insertItem(tr("Activate &Feature"), fm); //p.setItemEnabled(menuId, !ids.isEmpty()); // display popup e->accept(); int r = actions.value(p.exec ( e->globalPos() )); if ( r > 10000 ) actionActivated(r-10000); return true; } } return false; } void DiscoDlg::Private::actionActivated(int id) { DiscoListItem *it = (DiscoListItem *)dlg->lv_disco->currentItem(); if ( !it ) return; emit dlg->featureActivated(Features::feature(id), it->item().jid(), it->item().node()); } void DiscoDlg::Private::objectDestroyed(QObject *obj) { if ( obj == busy ) busy = 0; } void DiscoDlg::Private::setProtocol(int p) { data.protocol = (DiscoData::Protocol)p; } //---------------------------------------------------------------------------- // DiscoDlg //---------------------------------------------------------------------------- DiscoDlg::DiscoDlg(PsiAccount *pa, const Jid &jid, const QString &node) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); setupUi(this); // restore options ck_autoItems->setChecked(PsiOptions::instance()->getOption("options.ui.service-discovery.automatically-get-items").toBool()); ck_autoInfo->setChecked(PsiOptions::instance()->getOption("options.ui.service-discovery.automatically-get-info").toBool()); // initialize d = new Private(this, pa); d->jid = jid; d->node = node; d->data.pa->dialogRegister(this); //setWindowTitle(CAP(caption())); setWindowIcon(PsiIconset::instance()->transportStatus("transport", STATUS_ONLINE).icon()); X11WM_CLASS("disco"); connect (pb_browse, SIGNAL(clicked()), d, SLOT(doDisco())); pb_browse->setDefault(false); pb_browse->setAutoDefault(false); connect(pb_close, SIGNAL(clicked()), this, SLOT(close())); pb_close->setDefault(false); pb_close->setAutoDefault(false); cb_address->addItems(pa->psi()->recentBrowseList()); // FIXME cb_address->setFocus(); connect(cb_address, SIGNAL(activated(const QString &)), d, SLOT(doDisco())); cb_address->setEditText(d->jid.full()); cb_node->addItems(pa->psi()->recentNodeList()); connect(cb_node, SIGNAL(activated(const QString &)), d, SLOT(doDisco())); cb_node->setCurrentIndex(cb_node->findText(node)); if ( pa->loggedIn() ) doDisco(); } DiscoDlg::~DiscoDlg() { d->data.pa->dialogUnregister(this); delete d; // save options PsiOptions::instance()->setOption("options.ui.service-discovery.automatically-get-items", (bool) ck_autoItems->isChecked()); PsiOptions::instance()->setOption("options.ui.service-discovery.automatically-get-info", (bool) ck_autoInfo->isChecked()); } void DiscoDlg::doDisco(QString host, QString node) { d->doDisco(host, node); } #include "discodlg.moc" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pongserver.h���������������������������������������������������������������������������0000644�0001750�0001750�00000001737�11305557613�013503� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * pongserver.h - XMPP Ping server * Copyright (C) 2007 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PONGSERVER_H #define PONGSERVER_H #include "xmpp_task.h" class PongServer : public XMPP::Task { Q_OBJECT public: PongServer(Task*); bool take(const QDomElement&); }; #endif ���������������������������������psi-0.14/src/mainwin.cpp����������������������������������������������������������������������������0000644�0001750�0001750�00000110146�11305557613�013301� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * mainwin.cpp - the main window. holds contactlist and buttons. * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "mainwin.h" #include <qmessagebox.h> #include <qicon.h> #include <qapplication.h> #include <qtimer.h> #include <qobject.h> #include <qpainter.h> #include <qsignalmapper.h> #include <qmenubar.h> #include <QPixmap> #include <QCloseEvent> #include <QKeyEvent> #include <QEvent> #include <QVBoxLayout> #include <QMenu> #include <QMenuItem> #include <QtAlgorithms> #include <QShortcut> #ifdef Q_WS_WIN #include <windows.h> #endif #include "common.h" #include "showtextdlg.h" #include "psicon.h" #include "contactview.h" #include "psiiconset.h" #include "serverinfomanager.h" #include "applicationinfo.h" #include "psiaccount.h" #include "psitrayicon.h" #include "psitoolbar.h" #include "aboutdlg.h" #include "psitoolbar.h" #include "psipopup.h" #include "psioptions.h" #include "tipdlg.h" #include "mucjoindlg.h" #include "psicontactlist.h" #include "desktoputil.h" #include "mainwin_p.h" #include "psimedia/psimedia.h" #include "avcall/avcall.h" using namespace XMPP; // FIXME: this is a really corny way of getting the GStreamer version... QString extract_gst_version(const QString &in) { int start = in.indexOf("GStreamer "); if(start == -1) return QString(); start += 10; int end = in.indexOf(",", start); if(end == -1) return QString(); return in.mid(start, end - start); } //---------------------------------------------------------------------------- // MainWin::Private //---------------------------------------------------------------------------- class MainWin::Private { public: Private(PsiCon *, MainWin *); ~Private(); QVBoxLayout* vb_main; bool onTop, asTool; QMenu* mainMenu, *statusMenu, *optionsMenu, *toolsMenu; int sbState; QString nickname; PsiTrayIcon* tray; QMenu* trayMenu; QString statusTip; PopupAction* optionsButton, *statusButton; IconActionGroup* statusGroup; EventNotifierAction* eventNotifier; PsiCon* psi; MainWin* mainWin; QLineEdit* searchText; QToolButton* searchPb; QWidget* searchWidget; QSignalMapper* statusMapper; PsiIcon* nextAnim; int nextAmount; QMap<QAction *, int> statusActions; int lastStatus; bool filterActive, prefilterShowOffline, prefilterShowAway; void registerActions(); IconAction* getAction( QString name ); void updateMenu(QStringList actions, QMenu* menu); }; MainWin::Private::Private(PsiCon* _psi, MainWin* _mainWin) : psi(_psi), mainWin(_mainWin) { statusGroup = (IconActionGroup *)getAction("status_all"); eventNotifier = (EventNotifierAction *)getAction("event_notifier"); optionsButton = (PopupAction *)getAction("button_options"); statusButton = (PopupAction *)getAction("button_status"); statusMapper = new QSignalMapper(mainWin); mainWin->connect(statusMapper, SIGNAL(mapped(int)), mainWin, SLOT(activatedStatusAction(int))); filterActive = false; prefilterShowOffline = false; prefilterShowAway = false; } MainWin::Private::~Private() { } void MainWin::Private::registerActions() { struct { const char* name; int id; } statuslist[] = { { "status_chat", STATUS_CHAT }, { "status_online", STATUS_ONLINE }, { "status_away", STATUS_AWAY }, { "status_xa", STATUS_XA }, { "status_dnd", STATUS_DND }, { "status_invisible", STATUS_INVISIBLE }, { "status_offline", STATUS_OFFLINE }, { "", 0 } }; int i; QString aName; for ( i = 0; !(aName = QString(statuslist[i].name)).isEmpty(); i++ ) { IconAction* action = getAction( aName ); connect (action, SIGNAL(triggered()), statusMapper, SLOT(map())); statusMapper->setMapping(action, statuslist[i].id); statusActions[action] = statuslist[i].id; } // register all actions PsiActionList::ActionsType type = PsiActionList::ActionsType( PsiActionList::Actions_MainWin | PsiActionList::Actions_Common ); ActionList actions = psi->actionList()->suitableActions( type ); QStringList names = actions.actions(); QStringList::Iterator it = names.begin(); for ( ; it != names.end(); ++it ) { IconAction* action = actions.action( *it ); if ( action ) { mainWin->registerAction( action ); } } } IconAction* MainWin::Private::getAction( QString name ) { PsiActionList::ActionsType type = PsiActionList::ActionsType( PsiActionList::Actions_MainWin | PsiActionList::Actions_Common ); ActionList actions = psi->actionList()->suitableActions( type ); IconAction* action = actions.action( name ); if ( !action ) { qWarning("MainWin::Private::getAction(): action %s not found!", qPrintable(name)); } //else // mainWin->registerAction( action ); return action; } void MainWin::Private::updateMenu(QStringList actions, QMenu* menu) { menu->clear(); IconAction* action; foreach (QString name, actions) { // workind around Qt/X11 bug, which displays // actions's text and the separator bar in Qt 4.1.1 if ( name == "separator" ) { menu->addSeparator(); continue; } if ( name == "diagnostics" ) { QMenu* diagMenu = new QMenu(tr("Diagnostics"), mainWin); getAction("help_diag_qcaplugin")->addTo(diagMenu); getAction("help_diag_qcakeystore")->addTo(diagMenu); menu->addMenu(diagMenu); continue; } if ( (action = getAction(name)) ) { action->addTo(menu); } } } //---------------------------------------------------------------------------- // MainWin //---------------------------------------------------------------------------- //#ifdef Q_WS_X11 //#define TOOLW_FLAGS WStyle_Customize //#else //#define TOOLW_FLAGS ((Qt::WFlags) 0) //#endif #ifdef Q_WS_WIN #define TOOLW_FLAGS (Qt::WindowMinimizeButtonHint) #else #define TOOLW_FLAGS ((Qt::WFlags) 0) #endif MainWin::MainWin(bool _onTop, bool _asTool, PsiCon* psi) :AdvancedWidget<QMainWindow>(0, (_onTop ? Qt::WindowStaysOnTopHint : Qt::Widget) | (_asTool ? (Qt::Tool |TOOLW_FLAGS) : Qt::Widget)) { setAttribute(Qt::WA_AlwaysShowToolTips); d = new Private(psi, this); setWindowIcon(PsiIconset::instance()->status(STATUS_OFFLINE).impix()); d->onTop = _onTop; d->asTool = _asTool; // sbState: // -1 : connect // >= 0 : STATUS_* d->sbState = STATUS_OFFLINE; d->lastStatus = -2; d->nextAmount = 0; d->nextAnim = 0; d->tray = 0; d->trayMenu = 0; d->statusTip = ""; d->nickname = ""; QWidget* center = new QWidget (this); setCentralWidget ( center ); d->vb_main = new QVBoxLayout(center); cvlist = new ContactView(center); int layoutMargin = 2; #ifdef Q_WS_MAC layoutMargin = 0; cvlist->setFrameShape(QFrame::NoFrame); #endif d->vb_main->setMargin(layoutMargin); d->vb_main->setSpacing(layoutMargin); // create search bar d->searchWidget = new QWidget(centralWidget()); d->vb_main->addWidget(d->searchWidget); QHBoxLayout* searchLayout = new QHBoxLayout(d->searchWidget); searchLayout->setMargin(0); searchLayout->setSpacing(0); d->searchText = new QLineEdit(d->searchWidget); connect(d->searchText,SIGNAL(textEdited(const QString&)),SLOT(searchTextEntered(const QString&))); searchLayout->addWidget(d->searchText); d->searchPb = new QToolButton(d->searchWidget); d->searchPb->setText("X"); connect(d->searchPb,SIGNAL(clicked()),SLOT(searchClearClicked())); connect(cvlist, SIGNAL(searchInput(const QString&)), SLOT(searchTextStarted(const QString&))); searchLayout->addWidget(d->searchPb); d->searchWidget->setVisible(false); //add contact view d->vb_main->addWidget(cvlist); #ifdef Q_WS_MAC // Disable the empty vertical scrollbar: // it's here because of weird code in q3scrollview.cpp // Q3ScrollView::updateScrollBars() around line 877 d->vb_main->addSpacing(4); #endif d->statusMenu = new QMenu(tr("Status"), this); d->optionsMenu = new QMenu(tr("General"), this); #ifdef Q_WS_MAC d->trayMenu = d->statusMenu; #else d->trayMenu = new QMenu(this); buildTrayMenu(); connect(d->trayMenu, SIGNAL(aboutToShow()), SLOT(buildTrayMenu())); #endif buildStatusMenu(); buildOptionsMenu(); connect(d->optionsMenu, SIGNAL(aboutToShow()), SLOT(buildOptionsMenu())); X11WM_CLASS("main"); connect(d->psi, SIGNAL(accountCountChanged()), SLOT(numAccountsChanged())); numAccountsChanged(); updateCaption(); d->registerActions(); connect(d->psi->contactList(), SIGNAL(accountFeaturesChanged()), SLOT(accountFeaturesChanged())); accountFeaturesChanged(); decorateButton(STATUS_OFFLINE); // Mac-only menus #ifdef Q_WS_MAC QMenu* mainMenu = new QMenu(tr("Menu"), this); mainMenuBar()->addMenu(mainMenu); d->getAction("menu_options")->addTo(mainMenu); d->getAction("menu_quit")->addTo(mainMenu); d->getAction("help_about")->addTo(mainMenu); d->getAction("help_about_qt")->addTo(mainMenu); d->mainMenu = new QMenu(tr("General"), this); mainMenuBar()->addMenu(d->mainMenu); connect(d->mainMenu, SIGNAL(aboutToShow()), SLOT(buildMainMenu())); #else mainMenuBar()->addMenu(d->optionsMenu); #endif mainMenuBar()->addMenu(d->statusMenu); QMenu* viewMenu = new QMenu(tr("View"), this); mainMenuBar()->addMenu(viewMenu); d->getAction("show_offline")->addTo(viewMenu); if (PsiOptions::instance()->getOption("options.ui.menu.view.show-away").toBool()) { d->getAction("show_away")->addTo(viewMenu); } d->getAction("show_hidden")->addTo(viewMenu); d->getAction("show_agents")->addTo(viewMenu); d->getAction("show_self")->addTo(viewMenu); viewMenu->addSeparator(); d->getAction("show_statusmsg")->addTo(viewMenu); // Mac-only menus #ifdef Q_WS_MAC d->toolsMenu = new QMenu(tr("Tools"), this); mainMenuBar()->addMenu(d->toolsMenu); connect(d->toolsMenu, SIGNAL(aboutToShow()), SLOT(buildToolsMenu())); QMenu* helpMenu = new QMenu(tr("Help"), this); mainMenuBar()->addMenu(helpMenu); d->getAction("help_readme")->addTo (helpMenu); d->getAction("help_tip")->addTo (helpMenu); helpMenu->addSeparator(); d->getAction("help_online_help")->addTo (helpMenu); d->getAction("help_online_wiki")->addTo (helpMenu); d->getAction("help_online_home")->addTo (helpMenu); d->getAction("help_online_forum")->addTo (helpMenu); d->getAction("help_psi_muc")->addTo (helpMenu); d->getAction("help_report_bug")->addTo (helpMenu); QMenu* diagMenu = new QMenu(tr("Diagnostics"), this); helpMenu->addMenu(diagMenu); d->getAction("help_diag_qcaplugin")->addTo (diagMenu); d->getAction("help_diag_qcakeystore")->addTo (diagMenu); if(AvCallManager::isSupported()) { helpMenu->addSeparator(); d->getAction("help_about_psimedia")->addTo (helpMenu); } #else if (!PsiOptions::instance()->getOption("options.ui.contactlist.show-menubar").toBool()) { mainMenuBar()->hide(); } //else // mainMenuBar()->show(); #endif d->optionsButton->setMenu( d->optionsMenu ); d->statusButton->setMenu( d->statusMenu ); buildToolbars(); // setUnifiedTitleAndToolBarOnMac(true); connect(qApp, SIGNAL(dockActivated()), SLOT(dockActivated())); connect(psi, SIGNAL(emitOptionsUpdate()), SLOT(optionsUpdate())); optionsUpdate(); /*QShortcut *sp_ss = new QShortcut(QKeySequence(tr("Ctrl+Shift+N")), this); connect(sp_ss, SIGNAL(triggered()), SLOT(avcallConfig()));*/ } MainWin::~MainWin() { PsiPopup::deleteAll(); if(d->tray) { delete d->tray; d->tray = 0; } saveToolbarsState(); delete d; } void MainWin::registerAction( IconAction* action ) { const char *activated = SIGNAL( triggered() ); const char *toggled = SIGNAL( toggled(bool) ); const char *setChecked = SLOT( setChecked(bool) ); struct { const char* name; const char* signal; QObject* receiver; const char* slot; } actionlist[] = { { "show_offline", toggled, cvlist, SLOT( setShowOffline(bool) ) }, { "show_away", toggled, cvlist, SLOT( setShowAway(bool) ) }, { "show_hidden", toggled, cvlist, SLOT( setShowHidden(bool) ) }, { "show_agents", toggled, cvlist, SLOT( setShowAgents(bool) ) }, { "show_self", toggled, cvlist, SLOT( setShowSelf(bool) ) }, { "show_statusmsg", toggled, cvlist, SLOT( setShowStatusMsg(bool) ) }, { "button_options", activated, this, SIGNAL( doOptions() ) }, { "menu_disco", SIGNAL( activated(PsiAccount *, int) ), this, SLOT( activatedAccOption(PsiAccount*, int) ) }, { "menu_add_contact", SIGNAL( activated(PsiAccount *, int) ), this, SLOT( activatedAccOption(PsiAccount*, int) ) }, { "menu_xml_console", SIGNAL( activated(PsiAccount *, int) ), this, SLOT( activatedAccOption(PsiAccount*, int) ) }, { "menu_new_message", activated, this, SIGNAL( blankMessage() ) }, { "menu_join_groupchat", activated, this, SIGNAL( doGroupChat() ) }, { "menu_account_setup", activated, this, SIGNAL( doManageAccounts() ) }, { "menu_options", activated, this, SIGNAL( doOptions() ) }, { "menu_file_transfer", activated, this, SIGNAL( doFileTransDlg() ) }, { "menu_toolbars", activated, this, SIGNAL( doToolbars() ) }, { "menu_change_profile", activated, this, SIGNAL( changeProfile() ) }, { "menu_quit", activated, this, SLOT( try2tryCloseProgram() ) }, { "menu_play_sounds", toggled, this, SLOT( actPlaySoundsActivated(bool) ) }, #ifdef USE_PEP { "publish_tune", toggled, this, SLOT( actPublishTuneActivated(bool) ) }, #endif { "event_notifier", SIGNAL( clicked(int) ), this, SLOT( statusClicked(int) ) }, { "event_notifier", activated, this, SLOT( doRecvNextEvent() ) }, { "help_readme", activated, this, SLOT( actReadmeActivated() ) }, { "help_tip", activated, this, SLOT( actTipActivated() ) }, { "help_online_help", activated, this, SLOT( actOnlineHelpActivated() ) }, { "help_online_wiki", activated, this, SLOT( actOnlineWikiActivated() ) }, { "help_online_home", activated, this, SLOT( actOnlineHomeActivated() ) }, { "help_online_forum", activated, this, SLOT( actOnlineForumActivated() ) }, { "help_psi_muc", activated, this, SLOT( actJoinPsiMUCActivated() ) }, { "help_report_bug", activated, this, SLOT( actBugReportActivated() ) }, { "help_about", activated, this, SLOT( actAboutActivated() ) }, { "help_about_qt", activated, this, SLOT( actAboutQtActivated() ) }, { "help_about_psimedia", activated, this, SLOT( actAboutPsiMediaActivated() ) }, { "help_diag_qcaplugin", activated, this, SLOT( actDiagQCAPluginActivated() ) }, { "help_diag_qcakeystore", activated, this, SLOT( actDiagQCAKeyStoreActivated() ) }, { "", 0, 0, 0 } }; int i; QString aName; for ( i = 0; !(aName = QString(actionlist[i].name)).isEmpty(); i++ ) { if ( aName == action->objectName() ) { #ifdef USE_PEP // Check before connecting, otherwise we get a loop if ( aName == "publish_tune") { action->setChecked( PsiOptions::instance()->getOption("options.extended-presence.tune.publish").toBool() ); } #endif disconnect( action, actionlist[i].signal, actionlist[i].receiver, actionlist[i].slot ); // for safety connect( action, actionlist[i].signal, actionlist[i].receiver, actionlist[i].slot ); // special cases if ( aName == "menu_play_sounds" ) { action->setChecked(PsiOptions::instance()->getOption("options.ui.notifications.sounds.enable").toBool()); } //else if ( aName == "foobar" ) // ; } } struct { const char* name; QObject* sender; const char* signal; const char* slot; bool checked; } reverseactionlist[] = { { "show_away", cvlist, SIGNAL( showAway(bool) ), setChecked, cvlist->isShowAway()}, { "show_hidden", cvlist, SIGNAL( showHidden(bool) ), setChecked, cvlist->isShowHidden()}, { "show_offline", cvlist, SIGNAL( showOffline(bool) ), setChecked, cvlist->isShowOffline()}, { "show_self", cvlist, SIGNAL( showSelf(bool) ), setChecked, cvlist->isShowSelf()}, { "show_agents", cvlist, SIGNAL( showAgents(bool) ), setChecked, cvlist->isShowAgents()}, { "show_statusmsg", cvlist, SIGNAL( showStatusMsg(bool) ), setChecked, cvlist->isShowStatusMsg()}, { "", 0, 0, 0, false } }; for ( i = 0; !(aName = QString(reverseactionlist[i].name)).isEmpty(); i++ ) { if ( aName == action->objectName() ) { disconnect( reverseactionlist[i].sender, reverseactionlist[i].signal, action, reverseactionlist[i].slot ); // for safety connect( reverseactionlist[i].sender, reverseactionlist[i].signal, action, reverseactionlist[i].slot ); if (aName == "show_statusmsg") { action->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.status-messages.show").toBool() ); } else action->setChecked( reverseactionlist[i].checked ); } } } PsiCon* MainWin::psiCon() const { return d->psi; } void MainWin::setWindowOpts(bool _onTop, bool _asTool) { if(_onTop == d->onTop && _asTool == d->asTool) { return; } d->onTop = _onTop; d->asTool = _asTool; Qt::WFlags flags = 0; if(d->onTop) { flags |= Qt::WindowStaysOnTopHint; } if(d->asTool) { flags |= Qt::Tool | TOOLW_FLAGS; } setWindowFlags(flags); show(); } void MainWin::setUseDock(bool use) { if (use == (d->tray != 0)) { return; } if (d->tray) { delete d->tray; d->tray = 0; } Q_ASSERT(!d->tray); if (use) { d->tray = new PsiTrayIcon("Psi", d->trayMenu); connect(d->tray, SIGNAL(clicked(const QPoint &, int)), SLOT(trayClicked(const QPoint &, int))); connect(d->tray, SIGNAL(doubleClicked(const QPoint &)), SLOT(trayDoubleClicked())); d->tray->setIcon(PsiIconset::instance()->statusPtr(STATUS_OFFLINE)); d->tray->setToolTip(ApplicationInfo::name()); updateReadNext(d->nextAnim, d->nextAmount); d->tray->show(); } } void MainWin::buildStatusMenu() { d->statusMenu->clear(); d->getAction("status_online")->addTo(d->statusMenu); if (PsiOptions::instance()->getOption("options.ui.menu.status.chat").toBool()) { d->getAction("status_chat")->addTo(d->statusMenu); } d->statusMenu->addSeparator(); d->getAction("status_away")->addTo(d->statusMenu); if (PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()) { d->getAction("status_xa")->addTo(d->statusMenu); } d->getAction("status_dnd")->addTo(d->statusMenu); if (PsiOptions::instance()->getOption("options.ui.menu.status.invisible").toBool()) { d->statusMenu->addSeparator(); d->getAction("status_invisible")->addTo(d->statusMenu); } d->statusMenu->addSeparator(); d->getAction("status_offline")->addTo(d->statusMenu); #ifdef USE_PEP d->statusMenu->addSeparator(); d->getAction("publish_tune")->addTo(d->statusMenu); #endif } void MainWin::activatedStatusAction(int id) { QList<IconAction*> l = d->statusGroup->findChildren<IconAction*>(); foreach(IconAction* action, l) { action->setChecked ( d->statusActions[action] == id ); } statusChanged(id); } QMenuBar* MainWin::mainMenuBar() const { #ifdef Q_WS_MAC return psiCon()->defaultMenuBar(); #else return menuBar(); #endif } const QString toolbarsStateOptionPath = "options.ui.contactlist.toolbars-state"; void MainWin::saveToolbarsState() { PsiOptions::instance()->setOption(toolbarsStateOptionPath, saveState()); } void MainWin::loadToolbarsState() { restoreState(PsiOptions::instance()->getOption(toolbarsStateOptionPath).toByteArray()); } void MainWin::buildToolbars() { setUpdatesEnabled(false); if (toolbars_.count() > 0) { saveToolbarsState(); } qDeleteAll(toolbars_); toolbars_.clear(); foreach(QString base, PsiOptions::instance()->getChildOptionNames("options.ui.contactlist.toolbars", true, true)) { PsiToolBar* tb = new PsiToolBar(base, this, d->psi->actionList()); tb->initialize(); connect(tb, SIGNAL(customize()), d->psi, SLOT(doToolbars())); toolbars_ << tb; } loadToolbarsState(); // loadToolbarsState also restores correct toolbar visibility, // we might want to override that foreach(PsiToolBar* tb, toolbars_) { tb->updateVisibility(); } // d->eventNotifier->updateVisibility(); setUpdatesEnabled(true); // in case we have floating toolbars, they have inherited the 'no updates enabled' // state. now we need to explicitly re-enable updates. foreach(PsiToolBar* tb, toolbars_) { tb->setUpdatesEnabled(true); } } bool MainWin::showDockMenu(const QPoint &) { return false; } void MainWin::buildOptionsMenu() { // help menu QMenu* helpMenu = new QMenu(tr("&Help"), d->optionsMenu); helpMenu->setIcon(IconsetFactory::icon("psi/help").icon()); QStringList actions; actions << "help_readme" << "help_tip" << "separator" << "help_online_help" << "help_online_wiki" << "help_online_home" << "help_online_forum" << "help_psi_muc" << "help_report_bug" << "diagnostics" << "separator" << "help_about" << "help_about_qt"; if(AvCallManager::isSupported()) actions << "help_about_psimedia"; d->updateMenu(actions, helpMenu); buildGeneralMenu( d->optionsMenu ); d->optionsMenu->addSeparator(); d->optionsMenu->addMenu(helpMenu); d->getAction("menu_quit")->addTo( d->optionsMenu ); } void MainWin::buildMainMenu() { // main menu QStringList actions; actions << "menu_add_contact"; if (PsiOptions::instance()->getOption("options.ui.message.enabled").toBool()) { actions << "menu_new_message"; } actions << "menu_disco" << "menu_join_groupchat" << "separator" << "menu_account_setup"; if (PsiOptions::instance()->getOption("options.ui.menu.main.change-profile").toBool()) { actions << "menu_change_profile"; } actions << "menu_play_sounds"; d->updateMenu(actions, d->mainMenu); } void MainWin::buildToolsMenu() { QStringList actions; actions << "menu_file_transfer" << "separator" << "menu_xml_console"; d->updateMenu(actions, d->toolsMenu); } void MainWin::buildGeneralMenu(QMenu* menu) { // options menu QStringList actions; actions << "menu_add_contact"; if (PsiOptions::instance()->getOption("options.ui.message.enabled").toBool()) { actions << "menu_new_message"; } actions << "menu_disco" << "menu_join_groupchat" << "menu_account_setup" << "menu_options" << "menu_file_transfer"; if (PsiOptions::instance()->getOption("options.ui.menu.main.change-profile").toBool()) { actions << "menu_change_profile"; } actions << "menu_play_sounds"; d->updateMenu(actions, menu); } void MainWin::actReadmeActivated () { ShowTextDlg* w = new ShowTextDlg(":/README"); w->setWindowTitle(CAP(tr("ReadMe"))); w->show(); } void MainWin::actOnlineHelpActivated () { DesktopUtil::openUrl("http://psi-im.org/wiki/User_Guide"); } void MainWin::actOnlineWikiActivated () { DesktopUtil::openUrl("http://psi-im.org/wiki"); } void MainWin::actOnlineHomeActivated () { DesktopUtil::openUrl("http://psi-im.org"); } void MainWin::actOnlineForumActivated () { DesktopUtil::openUrl("http://forum.psi-im.org"); } void MainWin::actJoinPsiMUCActivated() { PsiAccount* account = d->psi->contactList()->defaultAccount(); if(!account) { return; } account->actionJoin("psi@conference.psi-im.org"); } void MainWin::actBugReportActivated () { DesktopUtil::openUrl("http://forum.psi-im.org/forum/2"); } void MainWin::actAboutActivated () { AboutDlg* about = new AboutDlg(); about->show(); } void MainWin::actTipActivated () { TipDlg::show(d->psi); } void MainWin::actAboutQtActivated () { QMessageBox::aboutQt(this); } void MainWin::actAboutPsiMediaActivated () { QString creditText = PsiMedia::creditText(); QString gstVersion = extract_gst_version(creditText); QString str; QPixmap pix; if(!gstVersion.isEmpty()) { str = tr( "This application uses GStreamer %1, a comprehensive " "open-source and cross-platform multimedia framework." " For more information, see " "<a href=\"http://www.gstreamer.net/\">http://www.gstreamer.net/</a>").arg(gstVersion); pix = IconsetFactory::icon("psi/gst_logo").pixmap(); } else str = creditText; QDialog aboutGst; QVBoxLayout *vb = new QVBoxLayout(&aboutGst); aboutGst.setWindowTitle(tr("About GStreamer")); QHBoxLayout *hb = new QHBoxLayout; vb->addLayout(hb); if(!pix.isNull()) { QLabel *la = new QLabel(&aboutGst); la->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); la->setPixmap(pix); hb->addWidget(la); } QLabel *lb = new QLabel(&aboutGst); lb->setText(str); lb->setTextFormat(Qt::RichText); lb->setWordWrap(true); lb->setOpenExternalLinks(true); hb->addWidget(lb); QDialogButtonBox *buttonBox = new QDialogButtonBox(&aboutGst); buttonBox->addButton(QDialogButtonBox::Ok); aboutGst.connect(buttonBox, SIGNAL(accepted()), SLOT(accept())); vb->addWidget(buttonBox); if(!pix.isNull()) { int w = pix.width() * 4; aboutGst.resize(w, aboutGst.heightForWidth(w)); } aboutGst.exec(); //QMessageBox::about(this, tr("About GStreamer"), str); } void MainWin::actDiagQCAPluginActivated() { QString dtext = QCA::pluginDiagnosticText(); ShowTextDlg* w = new ShowTextDlg(dtext, true, false, this); w->setWindowTitle(CAP(tr("Security Plugins Diagnostic Text"))); w->resize(560, 240); w->show(); } void MainWin::actDiagQCAKeyStoreActivated() { QString dtext = QCA::KeyStoreManager::diagnosticText(); ShowTextDlg* w = new ShowTextDlg(dtext, true, false, this); w->setWindowTitle(CAP(tr("Key Storage Diagnostic Text"))); w->resize(560, 240); w->show(); } void MainWin::actPlaySoundsActivated (bool state) { PsiOptions::instance()->setOption("options.ui.notifications.sounds.enable", state); } void MainWin::actPublishTuneActivated (bool state) { PsiOptions::instance()->setOption("options.extended-presence.tune.publish",state); } void MainWin::activatedAccOption(PsiAccount* pa, int x) { if(x == 0) { pa->openAddUserDlg(); } else if(x == 2) { pa->showXmlConsole(); } else if(x == 3) { pa->doDisco(); } } void MainWin::buildTrayMenu() { #ifndef Q_WS_MAC d->trayMenu->clear(); if(d->nextAmount > 0) { d->trayMenu->addAction(tr("Receive next event"), this, SLOT(doRecvNextEvent())); d->trayMenu->addSeparator(); } if(isHidden()) { d->trayMenu->addAction(tr("Un&hide"), this, SLOT(trayShow())); } else { d->trayMenu->addAction(tr("&Hide"), this, SLOT(trayHide())); } d->optionsButton->addTo(d->trayMenu); d->trayMenu->addMenu(d->statusMenu); d->trayMenu->addSeparator(); // TODO! d->getAction("menu_quit")->addTo(d->trayMenu); #endif } void MainWin::setTrayToolTip(int status) { if (!d->tray) { return; } d->tray->setToolTip(QString("Psi - " + status2txt(status))); } void MainWin::decorateButton(int status) { // update the 'change status' buttons QList<IconAction*> l = d->statusGroup->findChildren<IconAction*>(); foreach(IconAction* action, l) { action->setChecked ( d->statusActions[action] == status ); } if(d->lastStatus == status) { return; } d->lastStatus = status; if(status == -1) { d->statusButton->setText(tr("Connecting")); if (PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() != "no") { d->statusButton->setAlert(IconsetFactory::iconPtr("psi/connect")); d->statusGroup->setPsiIcon(IconsetFactory::iconPtr("psi/connect")); } else { d->statusButton->setIcon(PsiIconset::instance()->statusPtr(STATUS_OFFLINE)); d->statusGroup->setPsiIcon(PsiIconset::instance()->statusPtr(STATUS_OFFLINE)); } setWindowIcon(PsiIconset::instance()->status(STATUS_OFFLINE).impix()); } else { d->statusButton->setText(status2txt(status)); d->statusButton->setIcon(PsiIconset::instance()->statusPtr(status)); d->statusGroup->setPsiIcon(PsiIconset::instance()->statusPtr(status)); setWindowIcon(PsiIconset::instance()->status(status).impix()); } updateTray(); } bool MainWin::askQuit() { return true; } void MainWin::try2tryCloseProgram() { QTimer::singleShot(0, this, SLOT(tryCloseProgram())); } void MainWin::tryCloseProgram() { if(askQuit()) { closeProgram(); } } void MainWin::closeEvent(QCloseEvent* e) { #ifdef Q_WS_MAC trayHide(); e->accept(); #else if(d->tray) { trayHide(); e->accept(); return; } if(!askQuit()) { return; } closeProgram(); e->accept(); #endif } void MainWin::keyPressEvent(QKeyEvent* e) { #ifdef Q_WS_MAC bool allowed = true; #else bool allowed = d->tray ? true: false; #endif bool closekey = false; if(e->key() == Qt::Key_Escape) { if (d->searchWidget->isVisible()) { searchClearClicked(); } else { closekey = true; } } #ifdef Q_WS_MAC else if(e->key() == Qt::Key_W && e->modifiers() & Qt::ControlModifier) { closekey = true; } #endif if(allowed && closekey) { close(); e->accept(); return; } QWidget::keyPressEvent(e); } #ifdef Q_WS_WIN #include <windows.h> bool MainWin::winEvent(MSG* msg, long* result) { if (d->asTool && msg->message == WM_SYSCOMMAND && msg->wParam == SC_MINIMIZE) { hide(); // minimized toolwindows look bad on Windows, so let's just hide it instead // plus we cannot do this in changeEvent(), because it's called too late *result = 0; return true; // don't let Qt process this event } return false; } #endif void MainWin::updateCaption() { QString str = ""; if(d->nextAmount > 0) { str += "* "; } if(d->nickname.isEmpty()) { str += ApplicationInfo::name(); } else { str += d->nickname; } if(str == windowTitle()) { return; } setWindowTitle(str); } void MainWin::optionsUpdate() { int status = d->lastStatus; d->lastStatus = -2; decorateButton(status); #ifndef Q_WS_MAC if (!PsiOptions::instance()->getOption("options.ui.contactlist.show-menubar").toBool()) { mainMenuBar()->hide(); } else { mainMenuBar()->show(); } #endif setWindowOpacity(double(qMax(MINIMUM_OPACITY,PsiOptions::instance()->getOption("options.ui.contactlist.opacity").toInt()))/100); buildStatusMenu(); updateTray(); } void MainWin::toggleVisible() { if(!isHidden()) { trayHide(); } else { trayShow(); } } void MainWin::setTrayToolTip(const Status& status, bool) { if (!d->tray) { return; } QString s = "Psi"; QString show = status.show(); if(!show.isEmpty()) { show[0] = show[0].toUpper(); s += " - "+show; } QString text = status.status(); if(!text.isEmpty()) { s += ": "+text; } d->tray->setToolTip(s); } void MainWin::trayClicked(const QPoint &, int button) { if(PsiOptions::instance()->getOption("options.ui.systemtray.use-double-click").toBool()) { return; } if(button == Qt::MidButton) { doRecvNextEvent(); return; } if(!isHidden()) { trayHide(); } else { trayShow(); } } void MainWin::trayDoubleClicked() { if(!PsiOptions::instance()->getOption("options.ui.systemtray.use-double-click").toBool()) { return; } if(d->nextAmount > 0) { doRecvNextEvent(); return; } if(!isHidden()) { trayHide(); } else { trayShow(); } } void MainWin::trayShow() { bringToFront(this); } void MainWin::trayHide() { hide(); } void MainWin::updateReadNext(PsiIcon* anim, int amount) { d->nextAnim = anim; if(anim == 0) { d->nextAmount = 0; } else { d->nextAmount = amount; } if(d->nextAmount <= 0) { d->eventNotifier->hide(); d->eventNotifier->setMessage(""); } else { d->eventNotifier->setMessage(QString("<b>") + numEventsString(d->nextAmount) + "</b>"); d->eventNotifier->show(); // make sure it shows //qApp->processEvents(); } updateTray(); updateCaption(); } QString MainWin::numEventsString(int x) const { QString s; if(x <= 0) { s = ""; } else if(x == 1) { s = tr("1 event received"); } else { s = tr("%1 events received").arg(x); } return s; } void MainWin::updateTray() { if(!d->tray) { return; } if ( d->nextAmount > 0 ) { d->tray->setAlert(d->nextAnim); } else if ( d->lastStatus == -1 ) { d->tray->setAlert(IconsetFactory::iconPtr("psi/connect")); } else { d->tray->setIcon(PsiIconset::instance()->statusPtr(d->lastStatus)); } buildTrayMenu(); d->tray->setContextMenu(d->trayMenu); } void MainWin::doRecvNextEvent() { recvNextEvent(); } void MainWin::statusClicked(int x) { if(x == Qt::MidButton) { recvNextEvent(); } } void MainWin::numAccountsChanged() { d->statusButton->setEnabled(d->psi->contactList()->haveEnabledAccounts()); } void MainWin::accountFeaturesChanged() { bool have_pep = false; foreach(PsiAccount* account, d->psi->contactList()->enabledAccounts()) { if (account->serverInfoManager()->hasPEP()) { have_pep = true; break; } } #ifdef USE_PEP d->getAction("publish_tune")->setEnabled(have_pep); #endif } void MainWin::dockActivated() { if(isHidden()) { show(); } } /** * Called when the cancel is clicked or the search becomes empty. * Cancels the search. */ void MainWin::searchClearClicked() { d->searchWidget->setVisible(false); d->searchText->clear(); cvlist->clearFilter(); if (d->filterActive) { d->getAction("show_offline")->setChecked(d->prefilterShowOffline); d->getAction("show_away")->setChecked(d->prefilterShowAway); } d->filterActive=false; } /** * Called when the contactview has a keypress. * Starts the search/filter process */ void MainWin::searchTextStarted(QString const& text) { d->searchWidget->setVisible(true); d->searchText->setText(d->searchText->text() + text); searchTextEntered(d->searchText->text()); d->searchText->setFocus(); } /** * Called when the search input is changed. * Updates the search. */ void MainWin::searchTextEntered(QString const& text) { if (!d->filterActive) { d->filterActive = true; d->prefilterShowOffline = d->getAction("show_offline")->isChecked(); d->prefilterShowAway = d->getAction("show_away")->isChecked(); d->getAction("show_offline")->setChecked(true); d->getAction("show_away")->setChecked(true); } if (text.isEmpty()) { searchClearClicked(); } else { cvlist->setFilter(text); } } #ifdef Q_WS_MAC void MainWin::setWindowIcon(const QPixmap&) { } #else void MainWin::setWindowIcon(const QPixmap& p) { QMainWindow::setWindowIcon(p); } #endif #if 0 #if defined(Q_WS_WIN) #include <windows.h> void MainWin::showNoFocus() { clearWState( WState_ForceHide ); if ( testWState(WState_Visible) ) { SetWindowPos(winId(),HWND_TOPMOST,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); if(!d->onTop) SetWindowPos(winId(),HWND_NOTOPMOST,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); return; // nothing to do } if ( isTopLevel() && !testWState( WState_Resized ) ) { // do this before sending the posted resize events. Otherwise // the layout would catch the resize event and may expand the // minimum size. QSize s = sizeHint(); QSizePolicy::ExpandData exp; #ifndef QT_NO_LAYOUT if ( layout() ) { if ( layout()->hasHeightForWidth() ) s.setHeight( layout()->totalHeightForWidth( s.width() ) ); exp = layout()->expanding(); } else #endif { if ( sizePolicy().hasHeightForWidth() ) s.setHeight( heightForWidth( s.width() ) ); exp = sizePolicy().expanding(); } if ( exp & QSizePolicy::Horizontally ) s.setWidth( QMAX( s.width(), 200 ) ); if ( exp & QSizePolicy::Vertically ) s.setHeight( QMAX( s.height(), 150 ) ); QRect screen = QApplication::desktop()->screenGeometry( QApplication::desktop()->screenNumber( pos() ) ); s.setWidth( QMIN( s.width(), screen.width()*2/3 ) ); s.setHeight( QMIN( s.height(), screen.height()*2/3 ) ); if ( !s.isEmpty() ) resize( s ); } QApplication::sendPostedEvents( this, QEvent::Move ); QApplication::sendPostedEvents( this, QEvent::Resize ); setWState( WState_Visible ); if ( testWFlags(Qt::WStyle_Tool) || isPopup() ) { raise(); } else if ( testWFlags(Qt::WType_TopLevel) ) { while ( QApplication::activePopupWidget() ) QApplication::activePopupWidget()->close(); } if ( !testWState(WState_Polished) ) polish(); if ( children() ) { QObjectListIt it(*children()); register QObject* object; QWidget* widget; while ( it ) { // show all widget children object = it.current(); // (except popups and other toplevels) ++it; if ( object->isWidgetType() ) { widget = (QWidget*)object; if ( !widget->isHidden() && !widget->isTopLevel() ) widget->show(); } } } #if defined(QT_ACCESSIBILITY_SUPPORT) QAccessible::updateAccessibility( this, 0, QAccessible::ObjectShow ); #endif SetWindowPos(winId(),HWND_TOP,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW); UpdateWindow(winId()); } #else #endif #endif void MainWin::showNoFocus() { bringToFront(this); } void MainWin::avcallConfig() { if (AvCallManager::isSupported()) AvCallManager::config(); } //#endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/xdata_widget.h�������������������������������������������������������������������������0000644�0001750�0001750�00000002725�11305557613�013753� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * xdata_widget.h - a class for displaying jabber:x:data forms * Copyright (C) 2003-2004 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XDATAWIDGET_H #define XDATAWIDGET_H #include <QWidget> #include <QList> #include <QString> #include <QVBoxLayout> #include "xmpp_xdata.h" class XDataField; class XDataWidget : public QWidget { Q_OBJECT public: XDataWidget(QWidget *parent = 0, const char *name = 0); ~XDataWidget(); void setForm(const XMPP::XData&); XMPP::XData::FieldList fields() const; void setFields(const XMPP::XData::FieldList &); void setInstructions(const QString&); protected slots: void linkActivated(const QString&); private: typedef QList<XDataField*> XDataFieldList; XDataFieldList fields_; QString instructions_; QVBoxLayout* layout_; }; #endif �������������������������������������������psi-0.14/src/moodcatalog.cpp������������������������������������������������������������������������0000644�0001750�0001750�00000014516�11305557613�014134� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * moodcatalog.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QString> #include <QObject> #include <QCoreApplication> #include "mood.h" #include "moodcatalog.h" MoodCatalog::Entry::Entry() { } MoodCatalog::Entry::Entry(Mood::Type type, const QString& value, const QString& text) : type_(type), value_(value), text_(text) { } Mood::Type MoodCatalog::Entry::type() const { return type_; } const QString& MoodCatalog::Entry::value() const { return value_; } const QString& MoodCatalog::Entry::text() const { return text_; } bool MoodCatalog::Entry::isNull() const { return type_ == Mood::Unknown && text_.isNull() && value_.isNull(); } MoodCatalog::MoodCatalog() : QObject(QCoreApplication::instance()) { entries_ += Entry(Mood::Afraid, "afraid", QObject::tr("Afraid")); entries_ += Entry(Mood::Amazed, "amazed", QObject::tr("Amazed")); entries_ += Entry(Mood::Angry, "angry", QObject::tr("Angry")); entries_ += Entry(Mood::Annoyed, "annoyed", QObject::tr("Annoyed")); entries_ += Entry(Mood::Anxious, "anxious", QObject::tr("Anxious")); entries_ += Entry(Mood::Aroused, "aroused", QObject::tr("Aroused")); entries_ += Entry(Mood::Ashamed, "ashamed", QObject::tr("Ashamed")); entries_ += Entry(Mood::Bored, "bored", QObject::tr("Bored")); entries_ += Entry(Mood::Brave, "brave", QObject::tr("Brave")); entries_ += Entry(Mood::Calm, "calm", QObject::tr("Calm")); entries_ += Entry(Mood::Cold, "cold", QObject::tr("Cold")); entries_ += Entry(Mood::Confused, "confused", QObject::tr("Confused")); entries_ += Entry(Mood::Contented, "contented", QObject::tr("Contented")); entries_ += Entry(Mood::Cranky, "cranky", QObject::tr("Cranky")); entries_ += Entry(Mood::Curious, "curious", QObject::tr("Curious")); entries_ += Entry(Mood::Depressed, "depressed", QObject::tr("Depressed")); entries_ += Entry(Mood::Disappointed, "disappointed", QObject::tr("Disappointed")); entries_ += Entry(Mood::Disgusted, "disgusted", QObject::tr("Disgusted")); entries_ += Entry(Mood::Distracted, "distracted", QObject::tr("Distracted")); entries_ += Entry(Mood::Embarrassed, "embarrassed", QObject::tr("Embarrassed")); entries_ += Entry(Mood::Excited, "excited", QObject::tr("Excited")); entries_ += Entry(Mood::Flirtatious, "flirtatious", QObject::tr("Flirtatious")); entries_ += Entry(Mood::Frustrated, "frustrated", QObject::tr("Frustrated")); entries_ += Entry(Mood::Grumpy, "grumpy", QObject::tr("Grumpy")); entries_ += Entry(Mood::Guilty, "guilty", QObject::tr("Guilty")); entries_ += Entry(Mood::Happy, "happy", QObject::tr("Happy")); entries_ += Entry(Mood::Hot, "hot", QObject::tr("Hot")); entries_ += Entry(Mood::Humbled, "humbled", QObject::tr("Humbled")); entries_ += Entry(Mood::Humiliated, "humiliated", QObject::tr("Humiliated")); entries_ += Entry(Mood::Hungry, "hungry", QObject::tr("Hungry")); entries_ += Entry(Mood::Hurt, "hurt", QObject::tr("Hurt")); entries_ += Entry(Mood::Impressed, "impressed", QObject::tr("Impressed")); entries_ += Entry(Mood::In_awe, "in_awe", QObject::tr("In Awe")); entries_ += Entry(Mood::In_love, "in_love", QObject::tr("In Love")); entries_ += Entry(Mood::Indignant, "indignant", QObject::tr("Indignant")); entries_ += Entry(Mood::Interested, "interested", QObject::tr("Interested")); entries_ += Entry(Mood::Intoxicated, "intoxicated", QObject::tr("Intoxicated")); entries_ += Entry(Mood::Invincible, "invincible", QObject::tr("Invincible")); entries_ += Entry(Mood::Jealous, "jealous", QObject::tr("Jealous")); entries_ += Entry(Mood::Lonely, "lonely", QObject::tr("Lonely")); entries_ += Entry(Mood::Mean, "mean", QObject::tr("Mean")); entries_ += Entry(Mood::Moody, "moody", QObject::tr("Moody")); entries_ += Entry(Mood::Nervous, "nervous", QObject::tr("Nervous")); entries_ += Entry(Mood::Neutral, "neutral", QObject::tr("Neutral")); entries_ += Entry(Mood::Offended, "offended", QObject::tr("Offended")); entries_ += Entry(Mood::Playful, "playful", QObject::tr("Playful")); entries_ += Entry(Mood::Proud, "proud", QObject::tr("Proud")); entries_ += Entry(Mood::Relieved, "relieved", QObject::tr("Relieved")); entries_ += Entry(Mood::Remorseful, "remorseful", QObject::tr("Remorseful")); entries_ += Entry(Mood::Restless, "restless", QObject::tr("Restless")); entries_ += Entry(Mood::Sad, "sad", QObject::tr("Sad")); entries_ += Entry(Mood::Sarcastic, "sarcastic", QObject::tr("Sarcastic")); entries_ += Entry(Mood::Serious, "serious", QObject::tr("Serious")); entries_ += Entry(Mood::Shocked, "shocked", QObject::tr("Shocked")); entries_ += Entry(Mood::Shy, "shy", QObject::tr("Shy")); entries_ += Entry(Mood::Sick, "sick", QObject::tr("Sick")); entries_ += Entry(Mood::Sleepy, "sleepy", QObject::tr("Sleepy")); entries_ += Entry(Mood::Stressed, "stressed", QObject::tr("Stressed")); entries_ += Entry(Mood::Surprised, "surprised", QObject::tr("Surprised")); entries_ += Entry(Mood::Thirsty, "thirsty", QObject::tr("Thirsty")); entries_ += Entry(Mood::Worried, "worried", QObject::tr("Worried")); } MoodCatalog* MoodCatalog::instance() { if (!instance_) instance_ = new MoodCatalog(); return instance_; } MoodCatalog::Entry MoodCatalog::findEntryByType(Mood::Type type) const { foreach(Entry e, entries_) { if (e.type() == type) return e; } return Entry(); } MoodCatalog::Entry MoodCatalog::findEntryByValue(const QString& value) const { foreach(Entry e, entries_) { if (e.value() == value) return e; } return Entry(); } MoodCatalog::Entry MoodCatalog::findEntryByText(const QString& text) const { foreach(Entry e, entries_) { if (e.text() == text) return e; } return Entry(); } const QList<MoodCatalog::Entry>& MoodCatalog::entries() const { return entries_; } MoodCatalog* MoodCatalog::instance_ = 0; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pluginhost.cpp�������������������������������������������������������������������������0000644�0001750�0001750�00000040711�11305557613�014033� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * (c) 2006 Kevin Smith * (c) 2008 Maciej Niedzielski */ #include "pluginhost.h" #include <QPluginLoader> //#include "xmpp_message.h" #include "psioptions.h" #include "pluginmanager.h" #include "psiplugin.h" #include "stanzasender.h" #include "stanzafilter.h" #include "iqfilter.h" #include "iqnamespacefilter.h" #include "eventfilter.h" #include "optionaccessor.h" /** * \brief Constructs a host/wrapper for a plugin. * * PluginHost object manages one plugin. It can load/unload, enable/disable * a plugin. It also provides host-side services to the plugin. * * Constructor attempts to load the plugin, check if it is a valid psi plugin, * and cache its name, shortname and version. * * \param manager PluginManager instance that manages all plugins * \param pluginFile path to plugin file */ PluginHost::PluginHost(PluginManager* manager, const QString& pluginFile) : manager_(manager) , file_(pluginFile) , plugin_(0) , loader_(0) , connected_(false) , enabled_(false) , valid_(false) { load(); // reads plugin name, etc unload(); } /** * \brief Destroys plugin host. * * Plugin is disabled and unloaded if needed. */ PluginHost::~PluginHost() { disable(); unload(); if (loader_) { delete loader_; loader_ = 0; } } /** * \brief Returns true if wrapped file is a valid Psi plugin. * * Check is done once, in PluginHost constructor. */ bool PluginHost::isValid() const { return valid_; } /** * \brief Returns full path to plugin file. */ const QString& PluginHost::path() const { return file_; } /** * \brief Returns plugin full name. * * Data is available also when plugin is not loaded. */ const QString& PluginHost::name() const { return name_; } /** * \brief Returns plugin short name. * * Data is available also when plugin is not loaded. */ const QString& PluginHost::shortName() const { return shortName_; } /** * \brief Returns plugin version string. * * Data is available also when plugin is not loaded. */ const QString& PluginHost::version() const { return version_; } /** * \brief Returns plugin options widget. * * Always returns null if plugin is not currently loaded. */ QWidget* PluginHost::optionsWidget() const { QWidget* widget = 0; if (plugin_) { widget = qobject_cast<PsiPlugin*>(plugin_)->options(); } return widget; } //-- loading and enabling ------------------------------------------- /** * \brief Loads the plugin. * * Plugin is loaded but not enabled. * Does nothing if plugin was already loaded. * * Will fail if the plugin is not suitable (wrong Qt version, * wrong debug setting, wrong Psi plugin interface version etc). * * \return true if plugin is successfully loaded or if it was already loaded before. */ bool PluginHost::load() { qDebug() << "Loading Plugin " << file_; if (plugin_) { qWarning() << QString("Plugin %1 was already loaded.").arg(file_); } else { if (!loader_) { loader_ = new QPluginLoader(file_); } QObject* plugin = loader_->instance(); if (!loader_->isLoaded()) { delete loader_; } else if (plugin) { qDebug("Trying to load plugin"); //Check it's the right sort of plugin PsiPlugin* psiPlugin = qobject_cast<PsiPlugin*>(plugin); if (psiPlugin) { plugin_ = plugin; valid_ = true; //loaded_ = true; //enabled_ = false; name_ = psiPlugin->name(); shortName_ = psiPlugin->shortName(); version_ = psiPlugin->version(); } else { qWarning("Attempted to load %s, but it is not a valid plugin.", qPrintable(file_)); if (loader_->isLoaded()) { qWarning("File is a plugin but not for Psi"); loader_->unload(); } delete loader_; } } } return plugin_ != 0; } /** * \brief Unloads the plugin. * * Plugin is disabled (if needed) and unloaded. * Does nothing if plugin was not loaded yet. * * If plugin is successfully disabled but unloading fails, it is not enabled again. * * \return true if plugin is successfully unloaded or if it was not loaded at all. */ bool PluginHost::unload() { return false; // TODO(mck): loading plugin again after unloading fails for some reason // so I disabled unloading for now. if (plugin_ && disable()) { if (!loader_) { qWarning("Plugin %s's loader wasn't found when trying to unload", qPrintable(name_)); return false; } else if (loader_->unload()) { //if we're done with the plugin completely and it's unloaded // we can delete the loader; delete plugin_; delete loader_; plugin_ = 0; } } return plugin_ == 0; } /** * \brief Returns true if plugin is currently loaded. */ bool PluginHost::isLoaded() const { return plugin_ != 0; } /** * \brief Enabled the plugin * * Plugin is loaded (if needed) and enabled. * Does nothing if plugin was already enabled. * * Before plugin is enabled for the first time, * all appropriate set...Host() methods are called. * * Will fail if the plugin cannot be loaded or if plugin's enable() method fails. * * \return true if plugin is successfully enabled or if it was already enabled before. */ bool PluginHost::enable() { if (!enabled_ && load()) { if (!connected_) { qDebug() << "connecting plugin " << name_; StanzaSender* s = qobject_cast<StanzaSender*>(plugin_); if (s) { qDebug("connecting stanza sender"); s->setStanzaSendingHost(this); } IqFilter* f = qobject_cast<IqFilter*>(plugin_); if (f) { qDebug("connecting iq filter"); f->setIqFilteringHost(this); } OptionAccessor* o = qobject_cast<OptionAccessor*>(plugin_); if (o) { qDebug("connecting option accessor"); o->setOptionAccessingHost(this); } connected_ = true; } enabled_ = qobject_cast<PsiPlugin*>(plugin_)->enable(); } return enabled_; } /** * \brief Disabled the plugin. * * Plugin is disabled but not unloaded. * Does nothing if plugin was not enabled yet. * * \return true if plugin is successfully disabled or if it was not enabled at all. */ bool PluginHost::disable() { if (enabled_) { enabled_ = qobject_cast<PsiPlugin*>(plugin_)->disable(); } return !enabled_; } /** * \brief Returns true if plugin is currently enabled. */ bool PluginHost::isEnabled() const { return enabled_; } //-- for StanzaFilter and IqNamespaceFilter ------------------------- /** * \brief Give plugin the opportunity to process incoming xml * * If plugin implements incoming XML filters, they are called in turn. * Any handler may then modify the XML and may cause the stanza to be * silently discarded. * TODO: modification doesn't work * * \param account Identifier of the PsiAccount responsible * \param xml Incoming XML (may be modified) * \return Continue processing the XML stanza; true if the stanza should be silently discarded. */ bool PluginHost::incomingXml(int account, const QDomElement &e) { bool handled = false; // try stanza filter first StanzaFilter* sf = qobject_cast<StanzaFilter*>(plugin_); if (sf && sf->incomingStanza(account, e)) { handled = true; } // try iq filters else if (e.tagName() == "iq") { // get iq namespace QString ns; for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if (!i.isNull() && i.hasAttribute("xmlns")) { ns = i.attribute("xmlns"); break; } } // choose handler function depending on iq type bool (IqNamespaceFilter::*handler)(int account, const QDomElement& xml) = 0; const QString type = e.attribute("type"); if (type == "get") { handler = &IqNamespaceFilter::iqGet; } else if (type == "set") { handler = &IqNamespaceFilter::iqSet; } else if (type == "result") { handler = &IqNamespaceFilter::iqResult; } else if (type == "error") { handler = &IqNamespaceFilter::iqError; } if (handler) { // normal filters foreach (IqNamespaceFilter* f, iqNsFilters_.values(ns)) { if ((f->*handler)(account, e)) { handled = true; break; } } // regex filters QMapIterator<QRegExp, IqNamespaceFilter*> i(iqNsxFilters_); while (!handled && i.hasNext()) { if (i.key().indexIn(ns) >= 0 && (i.value()->*handler)(account, e)) { handled = true; } } } } return handled; } //-- for EventFilter ------------------------------------------------ /** * \brief Give plugin the opportunity to process incoming event. * * If plugin implements EventFilter interface, * this will call its processEvent() handler. * Handler may then modify the event and may cause the event to be * silently discarded. * TODO: modification doesn't work * * \param account Identifier of the PsiAccount responsible * \param e Event XML * \return Continue processing the event; true if the stanza should be silently discarded. */ bool PluginHost::processEvent(int account, const QDomElement& e) { bool handled = false; EventFilter *ef = qobject_cast<EventFilter*>(plugin_); if (ef && ef->processEvent(account, e)) { handled = true; } return handled; } /** * \brief Give plugin the opportunity to process incoming message event. * * If plugin implements EventFilter interface, * this will call its processMessage() handler. * Handler may then modify the event and may cause the event to be * silently discarded. * TODO: modification doesn't work * * \param account Identifier of the PsiAccount responsible * \param jidFrom Jid of message sender * \param body Message body * \param subject Message subject * \return Continue processing the event; true if the stanza should be silently discarded. */ bool PluginHost::processMessage(int account, const QString& jidFrom, const QString& body, const QString& subject) { bool handled = false; EventFilter *ef = qobject_cast<EventFilter*>(plugin_); if (ef && ef->processMessage(account, jidFrom, body, subject)) { handled = true; } return handled; } //-- StanzaSender --------------------------------------------------- /** * \brief Sends a stanza from the specified account. * * \param account Identifier of the PsiAccount responsible * \param stanza The stanza to be sent */ void PluginHost::sendStanza(int account, const QDomElement& stanza) { QTextStream stream; stream.setString(new QString()); stanza.save(stream, 0); manager_->sendXml(account, *stream.string()); } /** * \brief Sends a stanza from the specified account. * * \param account Identifier of the PsiAccount responsible * \param stanza The stanza to be sent. */ void PluginHost::sendStanza(int account, const QString& stanza) { manager_->sendXml(account, stanza); } /** * \brief Sends a message from the specified account. * * \param account Identifier of the PsiAccount responsible * \param to Jid of message addressee * \param body Message body * \param subject Message type * \param type Message type (XMPP message type) * \param stanza The stanza to be sent. */ void PluginHost::sendMessage(int account, const QString& to, const QString& body, const QString& subject, const QString& type) { //XMPP::Message m; //m.setTo(to); //m.setBody(body); //m.setSubject(subject); //if (type =="chat" || type == "error" || type == "groupchat" || type == "headline" || type == "normal") { // m.setType(type); //} //manager_->sendXml(account, m.toStanza(...).toString()); //TODO(mck): yeah, that's sick.. manager_->sendXml(account, QString("<message to='%1' type='%4'><subject>%3</subject><body>%2</body></message>").arg(to).arg(body).arg(subject).arg(type)); } /** * \brief Returns a unique stanza id in given account XMPP stream. * * \param account Identifier of the PsiAccount responsible * \return Unique stanza id, or empty string if account id is invalid. */ QString PluginHost::uniqueId(int account) { return manager_->uniqueId(account); } //-- IqFilter ------------------------------------------------------- /** * \brief Registers an Iq handler for given namespace. * * One plugin may register multiple handlers, even for the same namespace. * The same handler may be registered for more than one namespace. * Attempts to register the same handler for the same namespace will be blocked. * * When Iq stanza arrives, it is passed in turn to matching handlers. * Handler may then modify the event and may cause the event to be * silently discarded. * * Note that iq-result may contain no namespaced element in some protocols, * and connection made by this method will not work in such case. * * \param ns Iq namespace * \param filter Filter to be registered */ void PluginHost::addIqNamespaceFilter(const QString &ns, IqNamespaceFilter *filter) { if (iqNsFilters_.values(ns).contains(filter)) { qWarning("pluginmanager: blocked attempt to register the same filter again"); } else { iqNsFilters_.insert(ns, filter); } } /** * \brief Registers an Iq handler for given namespace. * * One plugin may register multiple handlers, even for the same namespace. * The same handler may be registered for more than one namespace. * Attempts to register the same handler for the same namespace will be blocked. * * When Iq stanza arrives, it is passed in turn to matching handlers. * Handler may then modify the event and may cause the event to be * silently discarded. * * Note that iq-result may contain no namespaced element in some protocols, * and connection made by this method will not work in such case. * * \param ns Iq namespace defined by a regular expression * \param filter Filter to be registered */ void PluginHost::addIqNamespaceFilter(const QRegExp &ns, IqNamespaceFilter *filter) { qDebug("add nsx"); if (iqNsxFilters_.values(ns).contains(filter)) { qWarning("pluginmanager: blocked attempt to register the same filter again"); } else { iqNsxFilters_.insert(ns, filter); } } /** * \brief Unregisters namespace handler. * * Breaks connection made by addIqNamespaceFilter(). * Note that \a filter object is never deleted by this function. */ void PluginHost::removeIqNamespaceFilter(const QString &ns, IqNamespaceFilter *filter) { iqNsFilters_.remove(ns, filter); } /** * \brief Unregisters namespace handler. * * Breaks connection made by addIqNamespaceFilter(). * Note that \a filter object is never deleted by this function. */ void PluginHost::removeIqNamespaceFilter(const QRegExp &ns, IqNamespaceFilter *filter) { iqNsxFilters_.remove(ns, filter); } //-- OptionAccessor ------------------------------------------------- /** * \brief Sets an option (local to the plugin) * The options will be automatically prefixed by the plugin manager, so * there is no need to uniquely name the options. In the same way as the * main options system, a hierachy is available by dot-delimiting the * levels ( e.g. "emoticons.show"). Use this and not setGlobalOption * in almost every case. * \param option Option to set * \param value New option value */ void PluginHost::setPluginOption( const QString& option, const QVariant& value) { // TODO(mck) //PsiPlugin* plugin=NULL; // //if (!plugin) // return; //QString pluginName = plugin->name(); //QString optionKey=QString("%1.%2.%3").arg(pluginOptionPrefix).arg(shortNames_[pluginName]).arg(option); //PsiOptions::instance()->setOption(optionKey,value); } /** * \brief Gets an option (local to the plugin) * The options will be automatically prefixed by the plugin manager, so * there is no need to uniquely name the options. In the same way as the * main options system, a hierachy is available by dot-delimiting the * levels ( e.g. "emoticons.show"). Use this and not getGlobalOption * in almost every case. * \param option Option to set * \param value Return value */ QVariant PluginHost::getPluginOption(const QString& option) { return QVariant(); // TODO(mck) } /** * \brief Sets a global option (not local to the plugin) * The options will be passed unaltered by the plugin manager, so * the options are presented as they are stored in the main option * system. Use setPluginOption instead of this in almost every case. * \param option Option to set * \param value New option value */ void PluginHost::setGlobalOption(const QString& option, const QVariant& value) { PsiOptions::instance()->setOption(option, value); } /** * \brief Gets a global option (not local to the plugin) * The options will be passed unaltered by the plugin manager, so * the options are presented as they are stored in the main option * system. Use getPluginOption instead of this in almost every case. * \param option Option to set * \param value Return value */ QVariant PluginHost::getGlobalOption(const QString& option) { return PsiOptions::instance()->getOption(option); } //-- helpers -------------------------------------------------------- static bool operator<(const QRegExp &a, const QRegExp &b) { return a.pattern() < b.pattern(); } �������������������������������������������������������psi-0.14/src/adduser.ui�����������������������������������������������������������������������������0000644�0001750�0001750�00000045607�11305557613�013132� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" stdsetdef="1" > <author></author> <comment></comment> <exportmacro></exportmacro> <class>AddUser</class> <widget class="QDialog" name="AddUser" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>601</width> <height>367</height> </rect> </property> <property name="windowTitle" > <string>Add Contact</string> </property> <layout class="QHBoxLayout" > <property name="margin" > <number>11</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QTextEdit" name="te_info" > <property name="sizePolicy" > <sizepolicy> <hsizetype>0</hsizetype> <vsizetype>7</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize" > <size> <width>200</width> <height>0</height> </size> </property> <property name="maximumSize" > <size> <width>200</width> <height>32767</height> </size> </property> <property name="text" > <string><qt>To add a <b>Jabber</b> user, simply fill out the Jabber ID (and optional nickname and group) at the bottom and press <i>Add</i>.<br> <br> To add a contact from a <b>non-Jabber</b> service, make sure you are registered with the service first (see Service Discovery from the main menu), and then select the service from the box at the top. Follow the instructions in the <i>Service ID Translation</i> box and press the <i>Get Jabber ID</i> button to generate a Jabber ID for the contact.<br> </qt></string> </property> <property name="readOnly" > <bool>true</bool> </property> </widget> </item> <item> <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="QWidget" native="1" name="w_serviceTranslation" > <layout class="QVBoxLayout" name="verticalLayout" > <property name="margin" > <number>0</number> </property> <item> <layout class="QHBoxLayout" name="hb_service" > <property name="spacing" > <number>6</number> </property> <property name="margin" > <number>0</number> </property> <item> <widget class="QLabel" name="TextLabel5" > <property name="text" > <string>Service:</string> </property> </widget> </item> <item> <widget class="QComboBox" name="cb_service" > <item> <property name="text" > <string>Jabber</string> </property> </item> </widget> </item> <item> <spacer name="Spacer1" > <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0" > <size> <width>20</width> <height>0</height> </size> </property> </spacer> </item> </layout> </item> <item> <widget class="QGroupBox" name="gb_trans" > <property name="enabled" > <bool>false</bool> </property> <property name="title" > <string>Service ID Translation</string> </property> <layout class="QVBoxLayout" name="_2" > <property name="spacing" > <number>6</number> </property> <property name="margin" > <number>11</number> </property> <item> <widget class="QLabel" name="lb_transDesc" > <property name="sizePolicy" > <sizepolicy vsizetype="Expanding" hsizetype="Preferred" > <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text" > <string>No description</string> </property> </widget> </item> <item> <layout class="QHBoxLayout" name="_3" > <property name="spacing" > <number>6</number> </property> <property name="margin" > <number>0</number> </property> <item> <widget class="QLineEdit" name="le_transPrompt" /> </item> <item> <widget class="QPushButton" name="pb_transGet" > <property name="text" > <string>Get Jabber ID</string> </property> </widget> </item> </layout> </item> </layout> </widget> </item> </layout> </widget> </item> <item> <layout class="QGridLayout" > <property name="margin" > <number>0</number> </property> <item row="0" column="1" > <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="QLineEdit" name="le_jid" /> </item> <item> <widget class="IconToolButton" name="tb_vCard" > <property name="enabled" > <bool>false</bool> </property> <property name="text" > <string/> </property> <property name="psiIconName" stdset="0" > <string>psi/vCard</string> </property> </widget> </item> </layout> </item> <item row="2" column="0" > <widget class="QLabel" name="TextLabel8" > <property name="text" > <string>Group:</string> </property> </widget> </item> <item row="1" column="1" > <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="QLineEdit" name="le_nick" /> </item> <item> <widget class="QToolButton" name="tb_resolveNick" > <property name="enabled" > <bool>false</bool> </property> <property name="text" > <string>Resolve</string> </property> </widget> </item> </layout> </item> <item row="1" column="0" > <widget class="QLabel" name="TextLabel7" > <property name="text" > <string>Nickname (optional):</string> </property> </widget> </item> <item row="0" column="0" > <widget class="QLabel" name="TextLabel6" > <property name="text" > <string>Jabber ID:</string> </property> </widget> </item> <item row="2" column="1" > <widget class="QComboBox" name="cb_group" > <property name="editable" > <bool>true</bool> </property> </widget> </item> </layout> </item> <item> <widget class="QCheckBox" name="ck_authreq" > <property name="text" > <string>Request authorization when adding</string> </property> </widget> </item> <item> <spacer name="Spacer3" > <property name="sizeHint" > <size> <width>16</width> <height>33</height> </size> </property> <property name="sizeType" > <enum>Expanding</enum> </property> <property name="orientation" > <enum>Vertical</enum> </property> </spacer> </item> <item> <widget class="QCheckBox" name="ck_close" > <property name="text" > <string>Close window after adding</string> </property> </widget> </item> <item> <widget class="Line" name="Line2" > <property name="frameShape" > <enum>QFrame::HLine</enum> </property> <property name="frameShadow" > <enum>QFrame::Sunken</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="BusyWidget" name="busy" /> </item> <item> <spacer name="Spacer2" > <property name="sizeHint" > <size> <width>140</width> <height>20</height> </size> </property> <property name="sizeType" > <enum>Expanding</enum> </property> <property name="orientation" > <enum>Horizontal</enum> </property> </spacer> </item> <item> <widget class="IconButton" name="pb_close" > <property name="text" > <string>&Close</string> </property> </widget> </item> <item> <widget class="IconButton" name="pb_add" > <property name="text" > <string>&Add</string> </property> <property name="shortcut" > <string>Alt+A</string> </property> <property name="default" > <bool>true</bool> </property> <property name="psiIconName" stdset="0" > <string>psi/addContact</string> </property> </widget> </item> </layout> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11" /> <pixmapfunction></pixmapfunction> <customwidgets> <customwidget> <class>BusyWidget</class> <extends></extends> <header location="local" >busywidget.h</header> <sizehint> <width>-1</width> <height>-1</height> </sizehint> <container>0</container> <sizepolicy> <hordata>5</hordata> <verdata>5</verdata> </sizepolicy> <pixmap>image0</pixmap> <properties> <property type="CString" >name</property> <property type="Bool" >enabled</property> <property type="Rect" >geometry</property> <property type="SizePolicy" >sizePolicy</property> <property type="Size" >minimumSize</property> <property type="Size" >maximumSize</property> <property type="Size" >sizeIncrement</property> <property type="Size" >baseSize</property> <property type="Color" >paletteForegroundColor</property> <property type="Color" >paletteBackgroundColor</property> <property type="Pixmap" >paletteBackgroundPixmap</property> <property type="Palette" >palette</property> <property type="BackgroundOrigin" >backgroundOrigin</property> <property type="Font" >font</property> <property type="Cursor" >cursor</property> <property type="String" >caption</property> <property type="Pixmap" >icon</property> <property type="String" >iconText</property> <property type="Bool" >mouseTracking</property> <property type="FocusPolicy" >focusPolicy</property> <property type="Bool" >acceptDrops</property> <property type="Bool" >active</property> </properties> </customwidget> <customwidget> <class>IconButton</class> <extends></extends> <header location="local" >iconbutton.h</header> <sizehint> <width>-1</width> <height>-1</height> </sizehint> <container>0</container> <sizepolicy> <hordata>5</hordata> <verdata>5</verdata> </sizepolicy> <pixmap>image0</pixmap> <properties> <property type="CString" >name</property> <property type="Bool" >enabled</property> <property type="Rect" >geometry</property> <property type="SizePolicy" >sizePolicy</property> <property type="Size" >minimumSize</property> <property type="Size" >maximumSize</property> <property type="Size" >sizeIncrement</property> <property type="Size" >baseSize</property> <property type="Color" >paletteForegroundColor</property> <property type="Color" >paletteBackgroundColor</property> <property type="Pixmap" >paletteBackgroundPixmap</property> <property type="Palette" >palette</property> <property type="BackgroundOrigin" >backgroundOrigin</property> <property type="Font" >font</property> <property type="Cursor" >cursor</property> <property type="String" >caption</property> <property type="Pixmap" >icon</property> <property type="String" >iconText</property> <property type="Bool" >mouseTracking</property> <property type="FocusPolicy" >focusPolicy</property> <property type="Bool" >acceptDrops</property> <property type="String" >text</property> <property type="Pixmap" >pixmap</property> <property type="KeySequence" >accel</property> <property type="Bool" >autoRepeat</property> <property type="Bool" >autoDefault</property> <property type="Bool" >default</property> <property type="IconSet" >iconSet</property> <property type="Bool" >toggleButton</property> <property type="Bool" >on</property> <property type="Bool" >flat</property> <property type="Bool" >autoMask</property> <property type="String" >psiIconName</property> <property type="Bool" >textVisible</property> </properties> </customwidget> </customwidgets> <tabstops> <tabstop>cb_service</tabstop> <tabstop>le_transPrompt</tabstop> <tabstop>pb_transGet</tabstop> <tabstop>le_jid</tabstop> <tabstop>le_nick</tabstop> <tabstop>cb_group</tabstop> <tabstop>ck_authreq</tabstop> <tabstop>ck_close</tabstop> <tabstop>te_info</tabstop> </tabstops> <images> <image name="image0" > <data format="PNG" length="1125" >89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154789cb5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c203e47720000000049454e44ae426082</data> </image> </images> </ui> �������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psioptions.cpp�������������������������������������������������������������������������0000644�0001750�0001750�00000021234�11305557613�014045� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psioptions.cpp - Psi options class * Copyright (C) 2006 Kevin Smith, Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psioptions.h" #include <QCoreApplication> #include <QTimer> #include "applicationinfo.h" #include "xmpp_xmlcommon.h" #include "xmpp_task.h" #include "xmpp_jid.h" #include "xmpp_client.h" #include "statuspreset.h" #include "psitoolbar.h" #include "common.h" using namespace XMPP; // ---------------------------------------------------------------------------- class OptionsStorageTask : public Task { public: OptionsStorageTask(Task* parent) : Task(parent) { } // TODO void set(/* ... */) { iq_ = createIQ(doc(), "set", "", id()); QDomElement prvt = doc()->createElement("query"); prvt.setAttribute("xmlns", "jabber:iq:private"); iq_.appendChild(prvt); // ... } void get() { iq_ = createIQ(doc(), "get", "", id()); QDomElement prvt = doc()->createElement("query"); prvt.setAttribute("xmlns", "jabber:iq:private"); iq_.appendChild(prvt); QDomElement options = doc()->createElement("options"); options.setAttribute("xmlns", ApplicationInfo::storageNS()); prvt.appendChild(options); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (!e.isNull() && e.tagName() == "options" && e.attribute("xmlns") == ApplicationInfo::storageNS()) { options_ = e; } } setSuccess(); } else { setError(x); } return true; } const QDomElement& options() const { return options_; } private: QDomElement iq_; QDomElement options_; }; // ---------------------------------------------------------------------------- /** * Returns the singleton instance of this class * \return Instance of PsiOptions */ PsiOptions* PsiOptions::instance() { if ( !instance_ ) instance_ = new PsiOptions(); return instance_; } /** * Returns the instance of this class containing default values of all options * \return Instance of PsiOptions */ const PsiOptions* PsiOptions::defaults() { if ( !defaults_ ) defaults_ = new PsiOptions(); return defaults_; } /** * Reset the singleton instance of this class * this delete the old instance so be sure no references are there anymore */ void PsiOptions::reset() { instance_ = 0; delete instance_; } /** * initizialises the default options for a new profile */ bool PsiOptions::newProfile() { bool ok = true; if (!load(":/options/newprofile.xml")) { ok = false; } StatusPreset(tr("Away from desk"), tr("I am away from my desk. Leave a message."), XMPP::Status::Away ).toOptions(this); StatusPreset(tr("Showering"), tr("I'm in the shower. You'll have to wait for me to get out."), XMPP::Status::Away ).toOptions(this); StatusPreset(tr("Eating"), tr("Out eating. Mmmm.. food."), XMPP::Status::Away ).toOptions(this); StatusPreset(tr("Sleep"), tr("Sleep is good. Zzzzz"), XMPP::Status::DND ).toOptions(this); StatusPreset(tr("Work"), tr("Can't chat. Gotta work."), XMPP::Status::DND ).toOptions(this); StatusPreset(tr("Air"), tr("Stepping out to get some fresh air."), XMPP::Status::Away ).toOptions(this); StatusPreset(tr("Movie"), tr("Out to a movie. Is that OK with you?"), XMPP::Status::Away ).toOptions(this); StatusPreset(tr("Secret"), tr("I'm not available right now and that's all you need to know."), XMPP::Status::XA ).toOptions(this); StatusPreset(tr("Out for the night"), tr("Out for the night."), XMPP::Status::Away ).toOptions(this); StatusPreset(tr("Greece"), tr("I have gone to a far away place. I will be back someday!"), XMPP::Status::XA ).toOptions(this); { ToolbarPrefs buttons; buttons.name = tr("Buttons"); #ifndef Q_WS_MAC buttons.on = true; #endif buttons.keys << "button_options" << "button_status"; buttons.dock = Qt3Dock_Bottom; ToolbarPrefs showContacts; showContacts.name = tr("Show contacts"); showContacts.keys << "show_offline" << "show_hidden" << "show_agents" << "show_self" << "show_statusmsg"; ToolbarPrefs eventNotifier; eventNotifier.name = tr("Event notifier"); eventNotifier.keys << "event_notifier"; eventNotifier.dock = Qt3Dock_Bottom; QList<ToolbarPrefs> toolbars; toolbars << buttons << showContacts << eventNotifier; foreach(ToolbarPrefs tb, toolbars) { tb.locked = true; PsiToolBar::structToOptions(this, tb); } } setOption("options.status.auto-away.message", tr("Auto Status (idle)")); return ok; } /** * Checks for existing saved Options. * Does not guarantee that load succeeds if the config file was corrupted. */ bool PsiOptions::exists(QString fileName) { return OptionsTree::exists(fileName); } /** * Loads the options present in the xml config file named. * \param file Name of the xml config file to load * \return Success */ bool PsiOptions::load(QString file) { return loadOptions(file, "options", ApplicationInfo::optionsNS()); } /** * Loads the options stored in the private storage of * the given client connection. * \param client the client whose private storage should be checked */ void PsiOptions::load(XMPP::Client* client) { OptionsStorageTask* t = new OptionsStorageTask(client->rootTask()); connect(t,SIGNAL(finished()),SLOT(getOptionsStorage_finished())); t->get(); t->go(true); } /** * Saves the options tree to an xml config file. * \param file Name of file to save to * \return Success */ bool PsiOptions::save(QString file) { return saveOptions(file, "options", ApplicationInfo::optionsNS(), ApplicationInfo::version()); } PsiOptions::PsiOptions() : OptionsTree() , autoSaveTimer_(0) { autoSaveTimer_ = new QTimer(this); autoSaveTimer_->setSingleShot(true); autoSaveTimer_->setInterval(1000); connect(autoSaveTimer_, SIGNAL(timeout()), SLOT(saveToAutoFile())); setParent(QCoreApplication::instance()); autoSave(false); if (!load(":/options/default.xml")) qWarning("ERROR: Failed to load default options"); #ifdef Q_WS_MAC if (!load(":/options/macosx.xml")) qWarning("ERROR: Failed to load Mac OS X-specific options"); #endif #ifdef Q_WS_WIN if (!load(":/options/windows.xml")) qWarning("ERROR: Failed to load Windows-specific options"); #endif } PsiOptions::~PsiOptions() { // since we queue connection to saveToAutoFile, so if some option was saved prior // to program termination, the PsiOptions is never given the chance to save // the changed option if (!autoFile_.isEmpty()) { saveToAutoFile(); } } /** * Sets whether to automatically save the options each time they change * * \param autoSave Enable/disable the feature * \param autoFile File to automatically save to (not needed when disabling the feature) */ void PsiOptions::autoSave(bool autoSave, QString autoFile) { if (autoSave) { connect(this, SIGNAL(optionChanged(const QString&)), autoSaveTimer_, SLOT(start())); autoFile_ = autoFile; } else { disconnect(this, SIGNAL(optionChanged(const QString&)), autoSaveTimer_, SLOT(start())); autoFile = ""; } } /** * Saves to the previously set file, if automatic saving is enabled */ void PsiOptions::saveToAutoFile() { if (!autoFile_.isEmpty()) { save(autoFile_); } } /** * This slot is called when the stored options retrieval is finished. */ void PsiOptions::getOptionsStorage_finished() { OptionsStorageTask* t = (OptionsStorageTask*) sender(); if (t->success()) { QDomElement e = t->options(); e.setAttribute("xmlns",ApplicationInfo::optionsNS()); loadOptions(e, "options", ApplicationInfo::optionsNS()); } } PsiOptions* PsiOptions::instance_ = NULL; PsiOptions* PsiOptions::defaults_ = NULL; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/actionlist.h���������������������������������������������������������������������������0000644�0001750�0001750�00000003270�11305557613�013454� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * actionlist.h - the customizeable action list * Copyright (C) 2004 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACTIONLIST_H #define ACTIONLIST_H #include <QObject> #include <QList> class QString; class QStringList; class IconAction; class ActionList : public QObject { Q_OBJECT public: ActionList(QString name, int id, bool autoDelete = true); ActionList(const ActionList &); ~ActionList(); QString name() const; int id() const; IconAction *action( QString name ) const; QStringList actions() const; void addAction( QString name, IconAction *action ); void clear(); public: class Private; private: Private *d; }; class MetaActionList : public QObject { Q_OBJECT public: MetaActionList(); ~MetaActionList(); ActionList *actionList( QString name ) const; QList<ActionList*> actionLists( int id ) const; QStringList actionLists() const; ActionList suitableActions( int id ) const; void addList( ActionList * ); void clear(); private: class Private; Private *d; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/search.ui������������������������������������������������������������������������������0000644�0001750�0001750�00000026312�11305557613�012740� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" stdsetdef="1" > <author></author> <comment></comment> <exportmacro></exportmacro> <class>Search</class> <widget class="QWidget" name="Search" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>568</width> <height>422</height> </rect> </property> <property name="windowTitle" > <string>Search: %1</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>11</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="QGroupBox" name="gb_search" > <property name="maximumSize" > <size> <width>256</width> <height>32767</height> </size> </property> <property name="title" > <string>Search Fields</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>11</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="QLabel" name="lb_instructions" > <property name="frameShape" > <enum>QFrame::Panel</enum> </property> <property name="frameShadow" > <enum>QFrame::Sunken</enum> </property> <property name="text" > <string>Instructions go here.</string> </property> <property name="wordWrap" > <bool>true</bool> </property> </widget> </item> <item> <widget class="QLabel" name="lb_form" > <property name="text" > <string>form</string> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="IconButton" name="pb_search" > <property name="text" > <string>&Search</string> </property> <property name="psiIconName" stdset="0" > <string>psi/search</string> </property> <property name="default" > <bool>true</bool> </property> </widget> </item> <item> <spacer name="Spacer1" > <property name="sizeHint" > <size> <width>30</width> <height>16</height> </size> </property> <property name="sizeType" > <enum>Expanding</enum> </property> <property name="orientation" > <enum>Horizontal</enum> </property> </spacer> </item> <item> <widget class="IconButton" name="pb_stop" > <property name="text" > <string>&Stop</string> </property> <property name="psiIconName" stdset="0" > <string>psi/stop</string> </property> </widget> </item> </layout> </item> </layout> </item> </layout> </widget> </item> <item> <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="QTreeWidget" name="lv_results" > <property name="alternatingRowColors" > <bool>true</bool> </property> <property name="selectionMode" > <enum>QAbstractItemView::ExtendedSelection</enum> </property> <property name="selectionBehavior" > <enum>QAbstractItemView::SelectRows</enum> </property> <property name="indentation" > <number>0</number> </property> <property name="uniformRowHeights" > <bool>true</bool> </property> <property name="itemsExpandable" > <bool>false</bool> </property> <property name="allColumnsShowFocus" > <bool>true</bool> </property> <property name="sortingEnabled" > <bool>true</bool> </property> <column> <property name="text" > <string>Nickname</string> </property> <property name="clickable" > <bool>true</bool> </property> <property name="resizable" > <bool>true</bool> </property> </column> <column> <property name="text" > <string>First Name</string> </property> <property name="clickable" > <bool>true</bool> </property> <property name="resizable" > <bool>true</bool> </property> </column> <column> <property name="text" > <string>Last Name</string> </property> <property name="clickable" > <bool>true</bool> </property> <property name="resizable" > <bool>true</bool> </property> </column> <column> <property name="text" > <string>E-Mail Address</string> </property> <property name="clickable" > <bool>true</bool> </property> <property name="resizable" > <bool>true</bool> </property> </column> <column> <property name="text" > <string>Jabber ID</string> </property> <property name="clickable" > <bool>true</bool> </property> <property name="resizable" > <bool>true</bool> </property> </column> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <spacer name="Spacer3" > <property name="sizeHint" > <size> <width>222</width> <height>16</height> </size> </property> <property name="sizeType" > <enum>Expanding</enum> </property> <property name="orientation" > <enum>Horizontal</enum> </property> </spacer> </item> <item> <widget class="IconButton" name="pb_add" > <property name="text" > <string>&Add Contact</string> </property> <property name="psiIconName" stdset="0" > <string>psi/addContact</string> </property> </widget> </item> <item> <widget class="IconButton" name="pb_info" > <property name="text" > <string>User &Info</string> </property> <property name="psiIconName" stdset="0" > <string>psi/vCard</string> </property> </widget> </item> </layout> </item> </layout> </item> </layout> </item> <item> <widget class="Line" name="line" > <property name="frameShape" > <enum>QFrame::HLine</enum> </property> <property name="frameShadow" > <enum>QFrame::Sunken</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <item> <widget class="BusyWidget" name="busy" /> </item> <item> <spacer name="Spacer2" > <property name="sizeHint" > <size> <width>485</width> <height>16</height> </size> </property> <property name="sizeType" > <enum>Expanding</enum> </property> <property name="orientation" > <enum>Horizontal</enum> </property> </spacer> </item> <item> <widget class="IconButton" name="pb_close" > <property name="text" > <string>&Close</string> </property> </widget> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11" /> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> </ui> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psichatdlg.cpp�������������������������������������������������������������������������0000644�0001750�0001750�00000043146�11305557613�013766� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "psichatdlg.h" #include <QLabel> #include <QCursor> #include <QLineEdit> #include <QToolButton> #include <QLayout> #include <QSplitter> #include <QToolBar> #include <QPixmap> #include <QColor> #include <QCloseEvent> #include <QHBoxLayout> #include <QVBoxLayout> #include <QContextMenuEvent> #include <QResizeEvent> #include <QMenu> #include <QDragEnterEvent> #include <QMessageBox> #include <QDebug> #include "psicon.h" #include "psiaccount.h" #include "iconaction.h" #include "stretchwidget.h" #include "psiiconset.h" #include "iconwidget.h" #include "fancylabel.h" #include "msgmle.h" #include "iconselect.h" #include "avatars.h" #include "psitooltip.h" #include "psioptions.h" #include "shortcutmanager.h" #include "accountlabel.h" #include "iconlabel.h" #include "capsmanager.h" #include "psicontactlist.h" #include "userlist.h" #include "jidutil.h" #include "textutil.h" #include "xmpp_tasks.h" #include "lastactivitytask.h" #define MCMDCHAT "http://psi-im.org/ids/mcmd#chatmain" class PsiChatDlg::ChatDlgMCmdProvider : public QObject, public MCmdProviderIface { Q_OBJECT public: ChatDlgMCmdProvider(PsiChatDlg *dlg) : dlg_(dlg) {}; virtual bool mCmdTryStateTransit(MCmdStateIface *oldstate, QStringList command, MCmdStateIface *&newstate, QStringList &preset) { Q_UNUSED(preset); if (oldstate->getName() == MCMDCHAT) { QString cmd; if (command.count() > 0) cmd = command[0].toLower(); if (cmd == "version") { JT_ClientVersion *version = new JT_ClientVersion(dlg_->account()->client()->rootTask()); connect(version, SIGNAL(finished()), SLOT(version_finished())); //qDebug() << "querying: " << dlg_->jid().full(); version->get(dlg_->jid()); version->go(); newstate = 0; } else if (cmd == "idle") { LastActivityTask *idle = new LastActivityTask(dlg_->jid(), dlg_->account()->client()->rootTask()); connect(idle, SIGNAL(finished()), SLOT(lastactivity_finished())); idle->go(); newstate = 0; } else if (cmd == "clear") { dlg_->doClear(); newstate = 0; } else if (cmd == "vcard") { dlg_->doInfo(); newstate = 0; } else if (cmd == "auth") { if (command.count() == 2) { if (command[1].toLower() == "request") { dlg_->account()->actionAuthRequest(dlg_->jid()); } } newstate = 0; } else if (cmd == "compact") { if (command.count() == 2) { QString sub = command[1].toLower(); if ("on" == sub) { dlg_->smallChat_ = true; } else if ("off" == sub) { dlg_->smallChat_ = false; } else { dlg_->appendSysMsg("usage: compact {on,off}"); } } else { dlg_->smallChat_ = !dlg_->smallChat_; } dlg_->setLooks(); newstate = 0; } else if (!cmd.isEmpty()) { return false; } return true; } else { return false; } }; virtual QStringList mCmdTryCompleteCommand(MCmdStateIface *state, QString query, QStringList partcommand, int item) { Q_UNUSED(partcommand); QStringList all; if (state->getName() == MCMDCHAT) { if (item == 0) { all << "version" << "idle" << "clear" << "vcard" << "auth" << "compact"; } } QStringList res; foreach(QString cmd, all) { if (cmd.startsWith(query)) { res << cmd; } } return res; }; virtual void mCmdSiteDestroyed() {}; virtual ~ChatDlgMCmdProvider() {}; public slots: void version_finished() { JT_ClientVersion *version = qobject_cast<JT_ClientVersion*>(sender()); if (!version) { dlg_->appendSysMsg("No version information available."); return; } dlg_->appendSysMsg(QString("Version response: N: %2 V: %3 OS: %4") .arg(version->name(), version->version(), version->os())); }; void lastactivity_finished() { LastActivityTask *idle = (LastActivityTask *)sender(); if (!idle->success()) { dlg_->appendSysMsg("Could not determine time of last activity."); return; } if (idle->status().isEmpty()) { dlg_->appendSysMsg(QString("Last activity at %1") .arg(idle->time().toString())); } else { dlg_->appendSysMsg(QString("Last activity at %1 (%2)") .arg(idle->time().toString(), idle->status())); } } private: PsiChatDlg *dlg_; }; PsiChatDlg::PsiChatDlg(const Jid& jid, PsiAccount* pa, TabManager* tabManager) : ChatDlg(jid, pa, tabManager), mCmdManager_(&mCmdSite_), tabCompletion(&mCmdManager_) { connect(account()->psi(), SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility())); mCmdManager_.registerProvider(new ChatDlgMCmdProvider(this)); } void PsiChatDlg::initUi() { ui_.setupUi(this); ui_.lb_ident->setAccount(account()); ui_.lb_ident->setShowJid(false); PsiToolTip::install(ui_.lb_status); ui_.lb_status->setPsiIcon(IconsetFactory::iconPtr("status/noauth")); ui_.tb_emoticons->setIcon(IconsetFactory::icon("psi/smile").icon()); connect(ui_.mle, SIGNAL(textEditCreated(QTextEdit*)), SLOT(chatEditCreated())); chatEditCreated(); #ifdef Q_WS_MAC connect(chatView(), SIGNAL(selectionChanged()), SLOT(logSelectionChanged())); #endif initToolButtons(); initToolBar(); updateAvatar(); PsiToolTip::install(ui_.avatar); UserListItem* u = account()->findFirstRelevant(jid()); if (u && u->isSecure(jid().resource())) { setPGPEnabled(true); } connect(account()->avatarFactory(), SIGNAL(avatarChanged(const Jid&)), this, SLOT(updateAvatar(const Jid&))); pm_settings_ = new QMenu(this); connect(pm_settings_, SIGNAL(aboutToShow()), SLOT(buildMenu())); ui_.tb_actions->setMenu(pm_settings_); connect(account()->capsManager(), SIGNAL(capsChanged(const Jid&)), SLOT(capsChanged(const Jid&))); QList<int> list; list << 324; list << 96; ui_.splitter->setSizes(list); smallChat_ = PsiOptions::instance()->getOption("options.ui.chat.use-small-chats").toBool(); act_mini_cmd_ = new QAction(this); act_mini_cmd_->setText(tr("Input command...")); connect(act_mini_cmd_, SIGNAL(triggered()), SLOT(doMiniCmd())); addAction(act_mini_cmd_); ui_.mini_prompt->hide(); } void PsiChatDlg::updateCountVisibility() { if (PsiOptions::instance()->getOption("options.ui.message.show-character-count").toBool() && !smallChat_) { ui_.lb_count->show(); } else { ui_.lb_count->hide(); } } void PsiChatDlg::setLooks() { ChatDlg::setLooks(); ui_.splitter->optionsChanged(); ui_.mle->optionsChanged(); ui_.tb_pgp->hide(); if (smallChat_) { ui_.lb_status->hide(); ui_.le_jid->hide(); ui_.tb_actions->hide(); ui_.tb_emoticons->hide(); ui_.toolbar->hide(); } else { ui_.lb_status->show(); ui_.le_jid->show(); if (PsiOptions::instance()->getOption("options.ui.chat.central-toolbar").toBool()) { ui_.toolbar->show(); ui_.tb_actions->hide(); ui_.tb_emoticons->hide(); } else { ui_.toolbar->hide(); ui_.tb_emoticons->setVisible(PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool()); ui_.tb_actions->show(); } } updateIdentityVisibility(); updateCountVisibility(); // toolbuttons QIcon i; i.addPixmap(IconsetFactory::icon("psi/cryptoNo").impix(), QIcon::Normal, QIcon::Off); i.addPixmap(IconsetFactory::icon("psi/cryptoYes").impix(), QIcon::Normal, QIcon::On); act_pgp_->setPsiIcon(0); act_pgp_->setIcon(i); } void PsiChatDlg::setShortcuts() { ChatDlg::setShortcuts(); act_clear_->setShortcuts(ShortcutManager::instance()->shortcuts("chat.clear")); act_info_->setShortcuts(ShortcutManager::instance()->shortcuts("common.user-info")); act_history_->setShortcuts(ShortcutManager::instance()->shortcuts("common.history")); act_mini_cmd_->setShortcuts(ShortcutManager::instance()->shortcuts("chat.quick-command")); } void PsiChatDlg::updateIdentityVisibility() { if (!smallChat_) { bool visible = account()->psi()->contactList()->enabledAccounts().count() > 1; ui_.lb_ident->setVisible(visible); } else { ui_.lb_ident->setVisible(false); } } void PsiChatDlg::initToolButtons() { act_clear_ = new IconAction(tr("Clear Chat Window"), "psi/clearChat", tr("Clear Chat Window"), 0, this); connect(act_clear_, SIGNAL(triggered()), SLOT(doClearButton())); connect(account()->psi()->iconSelectPopup(), SIGNAL(textSelected(QString)), this, SLOT(addEmoticon(QString))); act_icon_ = new IconAction(tr("Select Icon"), "psi/smile", tr("Select Icon"), 0, this); act_icon_->setMenu(account()->psi()->iconSelectPopup()); ui_.tb_emoticons->setMenu(account()->psi()->iconSelectPopup()); act_voice_ = new IconAction(tr("Voice Call"), "psi/voice", tr("Voice Call"), 0, this); connect(act_voice_, SIGNAL(triggered()), SLOT(doVoice())); act_voice_->setEnabled(false); act_file_ = new IconAction(tr("Send File"), "psi/upload", tr("Send File"), 0, this); connect(act_file_, SIGNAL(triggered()), SLOT(doFile())); act_pgp_ = new IconAction(tr("Toggle Encryption"), "", tr("Toggle Encryption"), 0, this, 0, true); ui_.tb_pgp->setDefaultAction(act_pgp_); act_info_ = new IconAction(tr("User Info"), "psi/vCard", tr("User Info"), 0, this); connect(act_info_, SIGNAL(triggered()), SLOT(doInfo())); act_history_ = new IconAction(tr("Message History"), "psi/history", tr("Message History"), 0, this); connect(act_history_, SIGNAL(triggered()), SLOT(doHistory())); act_compact_ = new IconAction(tr("Toggle Compact/Full Size"), "psi/compact", tr("Toggle Compact/Full Size"), 0, this); connect(act_compact_, SIGNAL(triggered()), SLOT(toggleSmallChat())); } void PsiChatDlg::initToolBar() { ui_.toolbar->setWindowTitle(tr("Chat Toolbar")); ui_.toolbar->setIconSize(QSize(16, 16)); ui_.toolbar->addAction(act_clear_); ui_.toolbar->addWidget(new StretchWidget(ui_.toolbar)); ui_.toolbar->addAction(act_icon_); ui_.toolbar->addAction(act_file_); if (PsiOptions::instance()->getOption("options.pgp.enable").toBool()) { ui_.toolbar->addAction(act_pgp_); } ui_.toolbar->addAction(act_info_); ui_.toolbar->addAction(act_history_); if (account()->voiceCaller()) { ui_.toolbar->addAction(act_voice_); } } void PsiChatDlg::contextMenuEvent(QContextMenuEvent *) { pm_settings_->exec(QCursor::pos()); } void PsiChatDlg::capsChanged() { ChatDlg::capsChanged(); QString resource = jid().resource(); UserListItem *ul = account()->findFirstRelevant(jid()); if (resource.isEmpty() && ul && !ul->userResourceList().isEmpty()) { resource = (*(ul->userResourceList().priority())).name(); } act_voice_->setEnabled(!account()->capsManager()->isEnabled() || (ul && ul->isAvailable() && account()->capsManager()->features(jid().withResource(resource)).canVoice())); } void PsiChatDlg::activated() { ChatDlg::activated(); updateCountVisibility(); } void PsiChatDlg::setContactToolTip(QString text) { ui_.lb_status->setToolTip(text); ui_.avatar->setToolTip(text); } void PsiChatDlg::contactUpdated(UserListItem* u, int status, const QString& statusString) { Q_UNUSED(statusString); if (status == -1 || !u) { ui_.lb_status->setPsiIcon(IconsetFactory::iconPtr("status/noauth")); } else { ui_.lb_status->setPsiIcon(PsiIconset::instance()->statusPtr(jid(), status)); } if (u) { setContactToolTip(u->makeTip(true, false)); } else { setContactToolTip(QString()); } if (u) { QString name; QString j; if (jid().resource().isEmpty()) j = JIDUtil::toString(u->jid(), true); else j = JIDUtil::toString(u->jid().bare(), false) + '/' + jid().resource(); if (!u->name().isEmpty()) name = u->name() + QString(" <%1>").arg(j); else name = j; ui_.le_jid->setText(name); ui_.le_jid->setCursorPosition(0); ui_.le_jid->setToolTip(name); } } void PsiChatDlg::updateAvatar() { QString res; QString client; if (!PsiOptions::instance()->getOption("options.ui.chat.avatars.show").toBool()) { ui_.avatar->hide(); return; } UserListItem *ul = account()->findFirstRelevant(jid()); if (ul && !ul->userResourceList().isEmpty()) { UserResourceList::Iterator it = ul->userResourceList().find(jid().resource()); if (it == ul->userResourceList().end()) it = ul->userResourceList().priority(); res = (*it).name(); client = (*it).clientName(); } //QPixmap p = account()->avatarFactory()->getAvatar(jid().withResource(res),client); QPixmap p = account()->avatarFactory()->getAvatar(jid().withResource(res)); if (p.isNull()) { ui_.avatar->hide(); } else { int size = PsiOptions::instance()->getOption("options.ui.chat.avatars.size").toInt(); ui_.avatar->setPixmap(p.scaled(QSize(size, size), Qt::KeepAspectRatio, Qt::SmoothTransformation)); ui_.avatar->show(); } } void PsiChatDlg::optionsUpdate() { smallChat_ = PsiOptions::instance()->getOption("options.ui.chat.use-small-chats").toBool(); ChatDlg::optionsUpdate(); } void PsiChatDlg::updatePGP() { if (account()->hasPGP()) { act_pgp_->setEnabled(true); } else { act_pgp_->setChecked(false); act_pgp_->setEnabled(false); } ui_.tb_pgp->setVisible(account()->hasPGP() && !smallChat_ && !PsiOptions::instance()->getOption("options.ui.chat.central-toolbar").toBool()); } void PsiChatDlg::doClearButton() { int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to clear the chat window?\n(note: does not affect saved history)"), tr("&Yes"), tr("&No")); if (n == 0) doClear(); } void PsiChatDlg::setPGPEnabled(bool enabled) { act_pgp_->setChecked(enabled); } void PsiChatDlg::toggleSmallChat() { smallChat_ = !smallChat_; setLooks(); } void PsiChatDlg::buildMenu() { // Dialog menu pm_settings_->clear(); pm_settings_->addAction(act_compact_); pm_settings_->addAction(act_clear_); pm_settings_->addSeparator(); pm_settings_->addAction(act_icon_); pm_settings_->addAction(act_file_); if (account()->voiceCaller()) act_voice_->addTo(pm_settings_); pm_settings_->addAction(act_pgp_); pm_settings_->addSeparator(); pm_settings_->addAction(act_info_); pm_settings_->addAction(act_history_); } void PsiChatDlg::updateCounter() { ui_.lb_count->setNum(chatEdit()->toPlainText().length()); } void PsiChatDlg::appendEmoteMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt) { updateLastMsgTime(time); QString color = colorString(local, spooled); QString timestr = chatView()->formatTimeStamp(time); chatView()->appendText(QString("<span style=\"color: %1\">").arg(color) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(whoNick(local)) + txt + "</span>"); } void PsiChatDlg::appendNormalMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt) { updateLastMsgTime(time); QString color = colorString(local, spooled); QString timestr = chatView()->formatTimeStamp(time); if (PsiOptions::instance()->getOption("options.ui.chat.use-chat-says-style").toBool()) { chatView()->appendText(QString("<p style=\"color: %1\">").arg(color) + QString("[%1] ").arg(timestr) + tr("%1 says:").arg(whoNick(local)) + "</p>" + txt); } else { chatView()->appendText(QString("<span style=\"color: %1\">").arg(color) + QString("[%1] <").arg(timestr) + whoNick(local) + QString("></span> ") + txt); } } void PsiChatDlg::appendMessageFields(const Message& m) { if (!m.subject().isEmpty()) { chatView()->appendText(QString("<b>") + tr("Subject:") + "</b> " + QString("%1").arg(Qt::escape(m.subject()))); } if (!m.urlList().isEmpty()) { UrlList urls = m.urlList(); chatView()->appendText(QString("<i>") + tr("-- Attached URL(s) --") + "</i>"); for (QList<Url>::ConstIterator it = urls.begin(); it != urls.end(); ++it) { const Url &u = *it; chatView()->appendText(QString("<b>") + tr("URL:") + "</b> " + QString("%1").arg(TextUtil::linkify(Qt::escape(u.url())))); chatView()->appendText(QString("<b>") + tr("Desc:") + "</b> " + QString("%1").arg(u.desc())); } } } bool PsiChatDlg::isEncryptionEnabled() const { return act_pgp_->isChecked(); } void PsiChatDlg::appendSysMsg(const QString &str) { QDateTime t = QDateTime::currentDateTime(); updateLastMsgTime(t); QString timestr = chatView()->formatTimeStamp(t); QString color = PsiOptions::instance()->getOption("options.ui.look.colors.messages.informational").toString(); chatView()->appendText(QString("<font color=\"%1\">[%2]").arg(color, timestr) + QString(" *** %1</font>").arg(str)); } QString PsiChatDlg::colorString(bool local, ChatDlg::SpooledType spooled) const { if (spooled == ChatDlg::Spooled_OfflineStorage) { return PsiOptions::instance()->getOption("options.ui.look.colors.messages.informational").toString(); } if (local) { return PsiOptions::instance()->getOption("options.ui.look.colors.messages.sent").toString(); } return PsiOptions::instance()->getOption("options.ui.look.colors.messages.received").toString(); } ChatView* PsiChatDlg::chatView() const { return ui_.log; } ChatEdit* PsiChatDlg::chatEdit() const { return ui_.mle->chatEdit(); } void PsiChatDlg::chatEditCreated() { ChatDlg::chatEditCreated(); connect(chatEdit(), SIGNAL(textChanged()), this, SLOT(updateCounter())); chatEdit()->installEventFilter(this); mCmdSite_.setInput(chatEdit()); mCmdSite_.setPrompt(ui_.mini_prompt); tabCompletion.setTextEdit(chatEdit()); } void PsiChatDlg::doSend() { tabCompletion.reset(); if (mCmdSite_.isActive()) { QString str = chatEdit()->toPlainText(); if (!mCmdManager_.processCommand(str)) { appendSysMsg(tr("Error: Can not parse command: ") + str); } } else { ChatDlg::doSend(); } } void PsiChatDlg::updateLastMsgTime(QDateTime t) { bool doInsert = t.date() != lastMsgTime_.date(); lastMsgTime_ = t; if (doInsert) { QString color = "#00A000"; chatView()->appendText(QString("<font color=\"%1\">*** %2</font>").arg(color).arg(t.date().toString(Qt::ISODate))); } } void PsiChatDlg::doMiniCmd() { mCmdManager_.open(new MCmdSimpleState(MCMDCHAT, tr("Command>")), QStringList() ); } bool PsiChatDlg::eventFilter( QObject *obj, QEvent *ev ) { if ( obj == chatEdit() && ev->type() == QEvent::KeyPress ) { QKeyEvent *e = (QKeyEvent *)ev; if ( e->key() == Qt::Key_Tab ) { tabCompletion.tryComplete(); return true; } tabCompletion.reset(); return false; } return ChatDlg::eventFilter( obj, ev ); } #include "psichatdlg.moc" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/userlist.h�����������������������������������������������������������������������������0000644�0001750�0001750�00000011273�11305557613�013157� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * userlist.h - high-level roster * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef USERLIST_H #define USERLIST_H #include <qstring.h> #include <qdatetime.h> #include <QList> #include <QPixmap> #include "xmpp_resource.h" #include "xmpp_liverosteritem.h" #include "mood.h" #include "geolocation.h" #include "physicallocation.h" class AvatarFactory; namespace XMPP { class Jid; } class UserResource : public XMPP::Resource { public: UserResource(); UserResource(const XMPP::Resource &); ~UserResource(); void setResource(const XMPP::Resource &); const QString& versionString() const; const QString& clientVersion() const; const QString& clientName() const; const QString& clientOS() const; void setClient(const QString& name, const QString& version, const QString& os); const QString & publicKeyID() const; int pgpVerifyStatus() const; QDateTime sigTimestamp() const; void setPublicKeyID(const QString &); void setPGPVerifyStatus(int); void setSigTimestamp(const QDateTime &); void setTune(const QString&); const QString& tune() const; void setGeoLocation(const GeoLocation&); const GeoLocation& geoLocation() const; void setPhysicalLocation(const PhysicalLocation&); const PhysicalLocation& physicalLocation() const; private: QString v_ver, v_clientName, v_clientVersion, v_clientOS, v_keyID; QString v_tune; GeoLocation v_geoLocation; PhysicalLocation v_physicalLocation; int v_pgpVerifyStatus; QDateTime sigts; }; bool operator<(const UserResource &r1, const UserResource &r2); bool operator<=(const UserResource &r1, const UserResource &r2); bool operator==(const UserResource &r1, const UserResource &r2); bool operator>(const UserResource &r1, const UserResource &r2); bool operator>=(const UserResource &r1, const UserResource &r2); class UserResourceList : public QList<UserResource> { public: UserResourceList(); ~UserResourceList(); void sort(); UserResourceList::Iterator find(const QString &); UserResourceList::Iterator priority(); UserResourceList::ConstIterator find(const QString &) const; UserResourceList::ConstIterator priority() const; }; class UserListItem : public XMPP::LiveRosterItem { public: UserListItem(bool self=false); ~UserListItem(); bool inList() const; bool isTransport() const; bool isAvailable() const; bool isHidden() const; bool isAway() const; QDateTime lastAvailable() const; int lastMessageType() const; void setLastMessageType(const int mtype); const QString & presenceError() const; bool isSelf() const; QString makeTip(bool trim = true, bool doLinkify = true) const; QString makeBareTip(bool trim, bool doLinkify) const; QString makeDesc() const; bool isPrivate() const; const Mood& mood() const; void setJid(const XMPP::Jid &); void setInList(bool); void setLastAvailable(const QDateTime &); void setPresenceError(const QString &); void setPrivate(bool); void setMood(const Mood&); void setTune(const QString&); const QString& tune() const; void setGeoLocation(const GeoLocation&); const GeoLocation& geoLocation() const; void setPhysicalLocation(const PhysicalLocation&); const PhysicalLocation& physicalLocation() const; void setAvatarFactory(AvatarFactory*); UserResourceList & userResourceList(); UserResourceList::Iterator priority(); const UserResourceList & userResourceList() const; UserResourceList::ConstIterator priority() const; bool isSecure(const QString &rname) const; void setSecure(const QString &rname, bool); const QString & publicKeyID() const; void setPublicKeyID(const QString &); private: int lastmsgtype; bool v_inList; QDateTime v_t; UserResourceList v_url; QString v_perr; bool v_self, v_isTransport; bool v_private; QStringList secList; QString v_keyID; QPixmap v_avatar; Mood v_mood; QString v_tune; GeoLocation v_geoLocation; PhysicalLocation v_physicalLocation; AvatarFactory* v_avatarFactory; }; typedef QListIterator<UserListItem*> UserListIt; class UserList : public QList<UserListItem*> { public: UserList(); ~UserList(); UserListItem *find(const XMPP::Jid &); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/ahcommandserver.h����������������������������������������������������������������������0000644�0001750�0001750�00000002657�11305557613�014471� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ahcommandserver.h - Server implementation of JEP-50 (Ad-Hoc Commands) * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHCOMMANDSERVER_H #define AHCOMMANDSERVER_H class AHCServerManager; class QString; class AHCommand; namespace XMPP { class Jid; } class AHCommandServer { public: AHCommandServer(AHCServerManager*); virtual ~AHCommandServer(); virtual QString name() const = 0; virtual QString node() const = 0; virtual bool isAllowed(const XMPP::Jid&) const { return true; } virtual AHCommand execute(const AHCommand&, const XMPP::Jid& requester) = 0; virtual void cancel(const AHCommand&) { } protected: AHCServerManager* manager() const { return manager_; } private: AHCServerManager* manager_; }; #endif ���������������������������������������������������������������������������������psi-0.14/src/groupchatdlg.h�������������������������������������������������������������������������0000644�0001750�0001750�00000007724�11305557613�013776� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * groupchatdlg.h - dialogs for handling groupchat * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GROUPCHATDLG_H #define GROUPCHATDLG_H #include <QWidget> #include <QDialog> #include "advwidget.h" #include "tabbablewidget.h" #include "ui_groupchatdlg.h" #include "mucmanager.h" #include "advwidget.h" using namespace XMPP; class PsiCon; class PsiAccount; class PsiOptions; class QRect; class GCMainDlg; class QColorGroup; class Q3DragObject; namespace XMPP { class Message; } /*class GCLineEdit : public QLineEdit { Q_OBJECT public: GCLineEdit(QWidget *parent=0, const char *name=0); signals: void upPressed(); void downPressed(); protected: void keyPressEvent(QKeyEvent *); };*/ class GCMainDlg : public TabbableWidget { Q_OBJECT public: GCMainDlg(PsiAccount *, const Jid &, TabManager *tabManager); ~GCMainDlg(); PsiAccount* account() const; void error(int, const QString &); void presence(const QString &, const Status &); void message(const Message &); void joined(); void setPassword(const QString&); const QString& nick() const; bool isInactive() const; void reactivate(); // reimplemented virtual TabbableWidget::State state() const; virtual int unreadMessageCount() const; virtual QString desiredCaption() const; protected: void setShortcuts(); // reimplemented void dragEnterEvent(QDragEnterEvent *); void dropEvent(QDropEvent *); void closeEvent(QCloseEvent *); void resizeEvent(QResizeEvent*); void mucInfoDialog(const QString& title, const QString& message, const Jid& actor, const QString& reason); signals: void aSend(const Message &); public slots: // reimplemented virtual void deactivated(); virtual void activated(); virtual void ensureTabbedCorrectly(); void optionsUpdate(); private slots: void scrollUp(); void scrollDown(); void mle_returnPressed(); void doTopic(); void openFind(); void configureRoom(); void doFind(const QString &); void pa_updatedActivity(); void goDisc(); void goConn(); void goForcedLeave(); void lv_action(const QString &, const Status &, int); void doClear(); void doClearButton(); void buildMenu(); void logSelectionChanged(); void setConnecting(); void unsetConnecting(); void action_error(MUCManager::Action, int, const QString&); void updateIdentityVisibility(); #ifdef WHITEBOARDING void openWhiteboard(); #endif void chatEditCreated(); public: class Private; friend class Private; private: Private *d; Ui::GroupChatDlg ui_; void doAlert(); void appendSysMsg(const QString &, bool, const QDateTime &ts=QDateTime()); void appendMessage(const Message &, bool); void updateLastMsgTime(QDateTime t); void setLooks(); void mucKickMsgHelper(const QString &nick, const Status &s, const QString &nickJid, const QString &title, const QString &youSimple, const QString &youBy, const QString &someoneSimple, const QString &someoneBy); void contextMenuEvent(QContextMenuEvent *); QString getNickColor(QString); QMap<QString,int> nicks; int nicknumber; PsiOptions* options_; QDateTime lastMsgTime_; }; class GCFindDlg : public QDialog { Q_OBJECT public: GCFindDlg(const QString&, QWidget* parent); ~GCFindDlg(); void found(); void error(const QString &); signals: void find(const QString &); private slots: void doFind(); private: QLineEdit *le_input; }; #endif ��������������������������������������������psi-0.14/src/optioneditor.ui������������������������������������������������������������������������0000644�0001750�0001750�00000006447�11305557613�014221� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <class>OptionEditor</class> <widget class="QDialog" name="OptionEditor" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>324</width> <height>146</height> </rect> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="label" > <property name="text" > <string>Option:</string> </property> <property name="buddy" > <cstring>le_option</cstring> </property> </widget> </item> <item> <widget class="QLineEdit" name="le_option" /> </item> </layout> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="label_2" > <property name="text" > <string>Typ:</string> </property> <property name="buddy" > <cstring>le_value</cstring> </property> </widget> </item> <item> <widget class="QComboBox" name="cb_typ" /> </item> <item> <widget class="QLabel" name="label_3" > <property name="text" > <string>Value: </string> </property> <property name="buddy" > <cstring>le_value</cstring> </property> </widget> </item> <item> <widget class="QLineEdit" name="le_value" > <property name="sizePolicy" > <sizepolicy> <hsizetype>3</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize" > <size> <width>150</width> <height>0</height> </size> </property> </widget> </item> </layout> </item> <item> <widget class="QLabel" name="lb_comment" > <property name="text" > <string/> </property> <property name="textFormat" > <enum>Qt::PlainText</enum> </property> <property name="wordWrap" > <bool>true</bool> </property> <property name="textInteractionFlags" > <enum>Qt::TextSelectableByMouse</enum> </property> </widget> </item> <item> <widget class="QDialogButtonBox" name="buttonBox" > <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="standardButtons" > <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> </property> </widget> </item> </layout> </widget> <resources/> <connections> <connection> <sender>buttonBox</sender> <signal>rejected()</signal> <receiver>OptionEditor</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel" > <x>316</x> <y>260</y> </hint> <hint type="destinationlabel" > <x>286</x> <y>274</y> </hint> </hints> </connection> </connections> </ui> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psiactions.h���������������������������������������������������������������������������0000644�0001750�0001750�00000001642�11305557613�013460� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psiactions.h - stanza activation types * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIACTIONS_H #define PSIACTIONS_H enum ActivationType { UserAction = 0, IncomingStanza, FromXml }; #endif ����������������������������������������������������������������������������������������������psi-0.14/src/conferencebookmark.h�������������������������������������������������������������������0000644�0001750�0001750�00000003045�11305557613�015140� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * conferencebookmark.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CONFERENCEBOOKMARK_H #define CONFERENCEBOOKMARK_H #include <QString> #include "xmpp_jid.h" class QDomElement; class QDomDocument; class ConferenceBookmark { public: ConferenceBookmark(const QString& name, const XMPP::Jid& jid, bool auto_join, const QString& nick = QString(), const QString& password = QString()); ConferenceBookmark(const QDomElement&); const QString& name() const; const XMPP::Jid& jid() const; bool autoJoin() const; const QString& nick() const; const QString& password() const; bool isNull() const; void fromXml(const QDomElement&); QDomElement toXml(QDomDocument&) const; bool operator==(const ConferenceBookmark& other) const; private: QString name_; XMPP::Jid jid_; bool auto_join_; QString nick_; QString password_; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/conferencebookmark.cpp�����������������������������������������������������������������0000644�0001750�0001750�00000005446�11305557613�015502� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * conferencebookmark.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QDomDocument> #include <QDomElement> #include "conferencebookmark.h" #include "xmpp_xmlcommon.h" ConferenceBookmark::ConferenceBookmark(const QString& name, const XMPP::Jid& jid, bool auto_join, const QString& nick, const QString& password) : name_(name), jid_(jid), auto_join_(auto_join), nick_(nick), password_(password) { } ConferenceBookmark::ConferenceBookmark(const QDomElement& el) : auto_join_(false) { fromXml(el); } const QString& ConferenceBookmark::name() const { return name_; } const XMPP::Jid& ConferenceBookmark::jid() const { return jid_; } bool ConferenceBookmark::autoJoin() const { return auto_join_; } const QString& ConferenceBookmark::nick() const { return nick_; } const QString& ConferenceBookmark::password() const { return password_; } bool ConferenceBookmark::isNull() const { return name_.isEmpty() && jid_.isEmpty(); } void ConferenceBookmark::fromXml(const QDomElement& e) { jid_ = e.attribute("jid"); name_ = e.attribute("name"); if (e.attribute("autojoin") == "true" || e.attribute("autojoin") == "1") auto_join_ = true; for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if (i.isNull()) continue; else if (i.tagName() == "nick") { nick_ = i.text(); } else if (i.tagName() == "password") { password_ = i.text(); } } } QDomElement ConferenceBookmark::toXml(QDomDocument& doc) const { QDomElement e = doc.createElement("conference"); e.setAttribute("jid",jid_.full()); e.setAttribute("name",name_); if (auto_join_) e.setAttribute("autojoin","true"); if (!nick_.isEmpty()) e.appendChild(textTag(&doc,"nick",nick_)); if (!password_.isEmpty()) e.appendChild(textTag(&doc,"password",password_)); return e; } bool ConferenceBookmark::operator==(const ConferenceBookmark & other) const { return name_ == other.name_ && jid_.full() == other.jid_.full() && auto_join_ == other.auto_join_ && nick_ == other.nick_ && password_ == other.password_; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/src.pro��������������������������������������������������������������������������������0000644�0001750�0001750�00000011021�11305557613�012434� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Psi qmake profile # # Configuration TEMPLATE = app TARGET = psi CONFIG += qt thread x11 #CONFIG += use_crash CONFIG += pep #CONFIG += whiteboarding #CONFIG += psi_plugins DEFINES += QT_STATICPLUGIN DEFINES += QT3_SUPPORT_WARNINGS # Import several very useful Makefile targets # as well as set up default directories for # generated files include(../qa/valgrind/valgrind.pri) include(../qa/oldtest/unittest.pri) # qconf include(../conf.pri) unix { # Target target.path = $$BINDIR INSTALLS += target # Shared files sharedfiles.path = $$PSI_DATADIR sharedfiles.files = ../README ../COPYING ../iconsets ../sound ../certs INSTALLS += sharedfiles # Widgets #widgets.path = $$PSI_DATADIR/designer #widgets.files = ../libpsi/psiwidgets/libpsiwidgets.so #INSTALLS += widgets # icons and desktop files dt.path=$$PREFIX/share/applications/ dt.files = ../psi.desktop icon1.path=$$PREFIX/share/icons/hicolor/16x16/apps icon1.extra = cp -f ../iconsets/system/default/logo_16.png $(INSTALL_ROOT)$$icon1.path/psi.png icon2.path=$$PREFIX/share/icons/hicolor/32x32/apps icon2.extra = cp -f ../iconsets/system/default/logo_32.png $(INSTALL_ROOT)$$icon2.path/psi.png icon3.path=$$PREFIX/share/icons/hicolor/48x48/apps icon3.extra = cp -f ../iconsets/system/default/logo_48.png $(INSTALL_ROOT)$$icon3.path/psi.png icon4.path=$$PREFIX/share/icons/hicolor/64x64/apps icon4.extra = cp -f ../iconsets/system/default/logo_64.png $(INSTALL_ROOT)$$icon4.path/psi.png icon5.path=$$PREFIX/share/icons/hicolor/128x128/apps icon5.extra = cp -f ../iconsets/system/default/logo_128.png $(INSTALL_ROOT)$$icon5.path/psi.png INSTALLS += dt icon1 icon2 icon3 icon4 icon5 } windows { include(../conf_windows.pri) LIBS += -lWSock32 -lUser32 -lShell32 -lGdi32 -lAdvAPI32 DEFINES += QT_STATICPLUGIN DEFINES += NOMINMAX # suppress min/max #defines in windows headers INCLUDEPATH += . # otherwise MSVC will fail to find "common.h" when compiling options/* stuff #QTPLUGIN += qjpeg qgif } # Psi sources include(src.pri) # don't clash with unittests SOURCES += main.cpp HEADERS += main.h ################################################################################ # Translation ################################################################################ LANG_PATH = ../lang TRANSLATIONS = \ $$LANG_PATH/psi_ar.ts \ $$LANG_PATH/psi_be.ts \ $$LANG_PATH/psi_bg.ts \ $$LANG_PATH/psi_br.ts \ $$LANG_PATH/psi_ca.ts \ $$LANG_PATH/psi_cs.ts \ $$LANG_PATH/psi_da.ts \ $$LANG_PATH/psi_de.ts \ $$LANG_PATH/psi_ee.ts \ $$LANG_PATH/psi_el.ts \ $$LANG_PATH/psi_eo.ts \ $$LANG_PATH/psi_es.ts \ $$LANG_PATH/psi_et.ts \ $$LANG_PATH/psi_fi.ts \ $$LANG_PATH/psi_fr.ts \ $$LANG_PATH/psi_hr.ts \ $$LANG_PATH/psi_hu.ts \ $$LANG_PATH/psi_it.ts \ $$LANG_PATH/psi_ja.ts \ $$LANG_PATH/psi_mk.ts \ $$LANG_PATH/psi_nl.ts \ $$LANG_PATH/psi_pl.ts \ $$LANG_PATH/psi_pt.ts \ $$LANG_PATH/psi_pt_BR.ts \ $$LANG_PATH/psi_ru.ts \ $$LANG_PATH/psi_se.ts \ $$LANG_PATH/psi_sk.ts \ $$LANG_PATH/psi_sl.ts \ $$LANG_PATH/psi_sr.ts \ $$LANG_PATH/psi_sr@latin.ts \ $$LANG_PATH/psi_sv.ts \ $$LANG_PATH/psi_sw.ts \ $$LANG_PATH/psi_uk.ts \ $$LANG_PATH/psi_ur_PK.ts \ $$LANG_PATH/psi_vi.ts \ $$LANG_PATH/psi_zh_CN.ts \ $$LANG_PATH/psi_zh_TW.ts OPTIONS_TRANSLATIONS_FILE=$$PWD/option_translations.cpp QMAKE_EXTRA_TARGETS += translate_options translate_options.commands = $$PWD/../admin/update_options_ts.py $$PWD/../options/default.xml > $$OPTIONS_TRANSLATIONS_FILE # In case lupdate doesn't work QMAKE_EXTRA_TARGETS += translate translate.commands = lupdate . options widgets tools/grepshortcutkeydlg ../cutestuff/network ../iris/xmpp-im -ts $$TRANSLATIONS exists($$OPTIONS_TRANSLATIONS_FILE) { SOURCES += $$OPTIONS_TRANSLATIONS_FILE } QMAKE_CLEAN += $$OPTIONS_TRANSLATIONS_FILE ################################################################################ # Resources RESOURCES += ../psi.qrc ../iconsets.qrc # Platform specifics unix:!mac { QMAKE_POST_LINK = rm -f ../psi ; ln -s src/psi ../psi } win32 { RC_FILE = ../win32/psi_win32.rc # buggy MSVC workaround win32-msvc|win32-msvc.net|win32-msvc2005: QMAKE_LFLAGS += /FORCE:MULTIPLE } mac { # Universal binaries qc_universal:contains(QT_CONFIG,x86):contains(QT_CONFIG,ppc) { CONFIG += x86 ppc QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 } # Frameworks are specified in src.pri QMAKE_INFO_PLIST = ../mac/Info.plist RC_FILE = ../mac/application.icns QMAKE_POST_LINK = cp -R ../certs ../iconsets ../sound `dirname $(TARGET)`/../Resources ; echo "APPLpsi " > `dirname $(TARGET)`/../PkgInfo } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/�����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�013143� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/unittest/��������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�015022� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/unittest/unittest.pri��������������������������������������������������������0000644�0001750�0001750�00000000053�11305557613�017413� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SOURCES += \ $$PWD/iodeviceopenertest.cpp �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/unittest/unittest.pro��������������������������������������������������������0000644�0001750�0001750�00000000171�11305557613�017422� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$PSI_UTILITIES_MODULE) include(unittest.pri) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/unittest/iodeviceopenertest.cpp����������������������������������������������0000644�0001750�0001750�00000004446�11305557613�021436� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * Copyright (C) 2007, Remko Troncon */ #include <QObject> #include <QtTest/QtTest> #include <QList> #include <QStringList> #include <QBuffer> #include "qttestutil/qttestutil.h" #include "utilities/iodeviceopener.h" class IODeviceOpenerTest : public QObject { Q_OBJECT private slots: void testConstructor() { QBuffer buffer; IODeviceOpener opener(&buffer, QIODevice::WriteOnly); QVERIFY(buffer.isOpen()); QVERIFY(QIODevice::WriteOnly == buffer.openMode()); QVERIFY(opener.isOpen()); } void testConstructor_Open() { QBuffer buffer; buffer.open(QIODevice::ReadOnly); IODeviceOpener opener(&buffer, QIODevice::ReadOnly); QVERIFY(buffer.isOpen()); QVERIFY(QIODevice::ReadOnly == buffer.openMode()); QVERIFY(opener.isOpen()); } void testConstructor_OpenInSubsetMode() { QBuffer buffer; buffer.open(QIODevice::ReadWrite); IODeviceOpener opener(&buffer, QIODevice::WriteOnly); QVERIFY(buffer.isOpen()); QVERIFY(QIODevice::ReadWrite == buffer.openMode()); QVERIFY(opener.isOpen()); } void testConstructor_OpenInWrongMode() { QBuffer buffer; buffer.open(QIODevice::ReadOnly); IODeviceOpener opener(&buffer, QIODevice::WriteOnly); QVERIFY(buffer.isOpen()); QVERIFY(QIODevice::ReadOnly == buffer.openMode()); QVERIFY(!opener.isOpen()); } void testConstructor_Unopenable() { UnopenableBuffer buffer; IODeviceOpener opener(&buffer, QIODevice::WriteOnly); QVERIFY(!opener.isOpen()); } void testDestructor() { QBuffer buffer; { IODeviceOpener opener(&buffer, QIODevice::WriteOnly); } QVERIFY(!buffer.isOpen()); } void testDestructor_Open() { QBuffer buffer; buffer.open(QIODevice::ReadOnly); { IODeviceOpener opener(&buffer, QIODevice::ReadOnly); } QVERIFY(buffer.isOpen()); } void testDestructor_OpenInWrongMode() { QBuffer buffer; buffer.open(QIODevice::ReadOnly); { IODeviceOpener opener(&buffer, QIODevice::WriteOnly); } QVERIFY(buffer.isOpen()); QVERIFY(QIODevice::ReadOnly == buffer.openMode()); } private: class UnopenableBuffer : public QBuffer { public: UnopenableBuffer() : QBuffer() { } bool open(QIODevice::OpenMode) { return false; } }; }; QTTESTUTIL_REGISTER_TEST(IODeviceOpenerTest); #include "iodeviceopenertest.moc" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/maybe.h����������������������������������������������������������������������0000755�0001750�0001750�00000003421�11305557613�014414� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * maybe.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MAYBE_H #define MAYBE_H /** * \brief A template class either containing no value or a specific value. * This container is especially handy for types that do not have an isNull() * or isEmpty() (such as primitive types). * * Example: Returns the division of numer and denom if it is an integer * \code * Maybe<int> integer_divide(int numer, int denom) { * if (numer % denom == 0) * return Maybe<int>(numer / denom); * else * return Maybe<int>(); * } * \endcode */ template<class T> class Maybe { public: /** * \brief Constructs a Maybe container with no value. */ Maybe() : hasValue_(false) {} /** * \brief Constructs a Maybe container with a value. */ Maybe(const T& value) : value_(value), hasValue_(true) {} /** * \brief Checks whether this container has a value. */ bool hasValue() const { return hasValue_; } /** * \brief Returns the value of the container. */ const T& value() const { return value_; } private: T value_; bool hasValue_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/iodeviceopener.h�������������������������������������������������������������0000644�0001750�0001750�00000003654�11305557613�016324� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef IODEVICEOPENER_H #define IODEVICEOPENER_H #include <QIODevice> #include <QPointer> /** * An IODeviceOpener is used to ensure that an IODevice is opened. * If the QIODevice was not open when the opener was created, it will be closed * again when the opener is destroyed. * * Example: * void foo(QIODevice* device) { * IODeviceOpener opener(device, QIODevice::ReadOnly); * if (!opener.isOpen()) { * qDebug() << "Error opening QIODevice"; * return; * } * ... * device->readAll() * ... * } */ class IODeviceOpener { public: /** * Opens an QIODevice in a specific mode if the device was not opened * yet. * If the device was already open but in a different, non-compatible * mode than the one requested, isOpen() will return false. */ IODeviceOpener(QIODevice* device, QIODevice::OpenModeFlag mode); /** * Closes the QIODevice passed to the constructor if the IODevice was not * opened at that time. */ ~IODeviceOpener(); /** * Checks whether the io device was opened succesfully in the mode * requested. */ bool isOpen() const { return isOpen_; } private: QPointer<QIODevice> device_; bool close_; bool isOpen_; }; #endif ������������������������������������������������������������������������������������psi-0.14/src/utilities/utilities.pri����������������������������������������������������������������0000644�0001750�0001750�00000000232�11305557613�015667� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INCLUDEPATH *= $$PWD $$PWD/.. DEPENDPATH *= $$PWD $$PWD/.. HEADERS += \ $$PWD/maybe.h \ $$PWD/iodeviceopener.h SOURCES += \ $$PWD/iodeviceopener.cpp ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/utilities/iodeviceopener.cpp�����������������������������������������������������������0000644�0001750�0001750�00000002250�11305557613�016646� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iodeviceopener.h" IODeviceOpener::IODeviceOpener(QIODevice* device, QIODevice::OpenModeFlag mode) : device_(device), close_(false) { if (!device_->isOpen()) { if (!device_->open(mode)) { isOpen_ = false; return; } close_ = true; } else if (!(device_->openMode() & mode)) { isOpen_ = false; return; } isOpen_ = true; } IODeviceOpener::~IODeviceOpener() { if (close_) { device_->close(); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/translationmanager.h�������������������������������������������������������������������0000644�0001750�0001750�00000002745�11305557613�015202� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * translationmanager.h * Copyright (C) 2006 Remko Troncon, Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TRANSLATIONMANAGER_H #define TRANSLATIONMANAGER_H #include <QObject> class VarList; class QTranslator; class TranslationManager : public QObject { Q_OBJECT public: static TranslationManager* instance(); VarList availableTranslations(); const QString& currentLanguage() const; QString currentXMLLanguage() const; void loadTranslation(const QString& language); protected: QStringList translationDirs() const; bool loadQtTranslation(const QString& language); private: TranslationManager(); ~TranslationManager(); QString currentLanguage_; //QString currentLanguageName_; QTranslator* translator_; QTranslator* qt_translator_; static TranslationManager* instance_; }; #endif ���������������������������psi-0.14/src/modules.pri����������������������������������������������������������������������������0000644�0001750�0001750�00000000723�11305557613�013316� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include($$PWD/../iris/src/xmpp/modules.pri) PSI_PROTOCOL_MODULE = $$PWD/protocol/protocol.pri PSI_UTILITIES_MODULE = $$PWD/utilities/utilities.pri PSI_CERTIFICATES_MODULE = $$PWD/Certificates/Certificates.pri PSI_CAPABILITIES_MODULE = $$PWD/capabilities/capabilities.pri PSI_TOOLS_OPTIONSTREE_MODULE = $$PWD/tools/optionstree/optionstree.pri PSI_TOOLS_ATOMICXMLFILE_MODULE = $$PWD/tools/atomicxmlfile/atomicxmlfile.pri PSI_MOCKQCA_MODULE = $$PWD/MockQCA/MockQCA.pri ���������������������������������������������psi-0.14/src/desktoputil.h��������������������������������������������������������������������������0000644�0001750�0001750�00000002121�11305557613�013644� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * desktoputil.h - url-opening routines * Copyright (C) 2007 Maciej Niedzielski, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef DESKTOPUTIL_H #define DESKTOPUTIL_H class QString; class QObject; namespace DesktopUtil { bool openUrl(const QString& url); void setUrlHandler(const QString& scheme, QObject* receiver, const char* method); void unsetUrlHandler(const QString& scheme); }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psicon.cpp�����������������������������������������������������������������������������0000644�0001750�0001750�00000123051�11305557613�013131� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psicon.cpp - core of Psi * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psicon.h" #include <qapplication.h> #include <qdesktopwidget.h> #include <QMenuBar> #include <qpointer.h> #include <qicon.h> #include <qcolor.h> #include <qimage.h> #include <qpixmapcache.h> #include <QFile> #include <QPixmap> #include <QList> #include <QImageReader> #include <QMessageBox> #include <QDir> #include "s5b.h" #include "psiaccount.h" #include "activeprofiles.h" #include "accountadddlg.h" #include "psiiconset.h" #include "contactview.h" #include "psievent.h" #include "passphrasedlg.h" #include "common.h" #include "mainwin.h" #include "idle.h" #include "accountmanagedlg.h" #include "statusdlg.h" #include "options/optionsdlg.h" #include "options/opt_toolbars.h" #include "accountregdlg.h" #include "combinedtunecontroller.h" #include "mucjoindlg.h" #include "userlist.h" #include "eventdlg.h" #include "pgputil.h" #include "eventdb.h" #include "proxy.h" #ifdef PSIMNG #include "psimng.h" #endif #include "alerticon.h" #include "iconselect.h" #include "psitoolbar.h" #include "filetransfer.h" #include "filetransdlg.h" #include "accountmodifydlg.h" #include "psiactionlist.h" #include "applicationinfo.h" #include "jidutil.h" #include "systemwatch.h" #include "accountscombobox.h" #include "tabdlg.h" #include "chatdlg.h" #include "capsregistry.h" #include "urlobject.h" #include "anim.h" #include "psioptions.h" #ifdef PSI_PLUGINS #include "pluginmanager.h" #endif #include "psicontactlist.h" #include "dbus.h" #include "tipdlg.h" #include "shortcutmanager.h" #include "globalshortcutmanager.h" #include "desktoputil.h" #include "tabmanager.h" #include "capsmanager.h" #include "avcall/avcall.h" #include "avcall/calldlg.h" #include "AutoUpdater/AutoUpdater.h" #ifdef HAVE_SPARKLE #include "AutoUpdater/SparkleAutoUpdater.h" #endif #ifdef Q_WS_MAC #include "mac_dock.h" #endif // from opt_avcall.cpp extern void options_avcall_update(); //---------------------------------------------------------------------------- // PsiConObject //---------------------------------------------------------------------------- class PsiConObject : public QObject { Q_OBJECT public: PsiConObject(QObject *parent) : QObject(parent) { QDir p(ApplicationInfo::homeDir()); QDir v(ApplicationInfo::homeDir() + "/tmp-sounds"); if(!v.exists()) p.mkdir("tmp-sounds"); Iconset::setSoundPrefs(v.absolutePath(), this, SLOT(playSound(QString))); connect(URLObject::getInstance(), SIGNAL(openURL(QString)), SLOT(openURL(QString))); } ~PsiConObject() { // removing temp dirs QDir p(ApplicationInfo::homeDir()); QDir v(ApplicationInfo::homeDir() + "/tmp-sounds"); folderRemove(v); } public slots: void playSound(QString file) { if ( file.isEmpty() || !PsiOptions::instance()->getOption("options.ui.notifications.sounds.enable").toBool() ) return; soundPlay(file); } void openURL(QString url) { DesktopUtil::openUrl(url); } private: // ripped from profiles.cpp bool folderRemove(const QDir &_d) { QDir d = _d; QStringList entries = d.entryList(); for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { if(*it == "." || *it == "..") continue; QFileInfo info(d, *it); if(info.isDir()) { if(!folderRemove(QDir(info.filePath()))) return false; } else { //printf("deleting [%s]\n", info.filePath().latin1()); d.remove(info.fileName()); } } QString name = d.dirName(); if(!d.cdUp()) return false; //printf("removing folder [%s]\n", d.filePath(name).latin1()); d.rmdir(name); return true; } }; //---------------------------------------------------------------------------- // PsiCon::Private //---------------------------------------------------------------------------- struct item_dialog { QWidget *widget; QString className; }; class PsiCon::Private : public QObject { Q_OBJECT public: Private(PsiCon *parent) : contactList(0), iconSelect(0) { psi = parent; } ~Private() { if ( iconSelect ) delete iconSelect; } void saveProfile(UserAccountList acc) { // clear it accountTree.removeOption("accounts", true); // save accounts with known base QSet<QString> cbases; foreach(UserAccount ua, acc) { if (!ua.optionsBase.isEmpty()) { ua.toOptions(&accountTree); cbases += ua.optionsBase; } } // save new accounts int idx = 0; foreach(UserAccount ua, acc) { if (ua.optionsBase.isEmpty()) { QString base; do { base = "accounts.a"+QString::number(idx++); } while (cbases.contains(base)); cbases += base; ua.toOptions(&accountTree, base); } } QFile accountsFile(pathToProfile( activeProfile ) + "/accounts.xml"); accountTree.saveOptions(accountsFile.fileName(), "accounts", ApplicationInfo::optionsNS(), ApplicationInfo::version());; } private slots: void updateIconSelect() { Iconset iss; foreach(Iconset* iconset, PsiIconset::instance()->emoticons) { iss += *iconset; } iconSelect->setIconset(iss); QPixmapCache::clear(); } public: PsiCon* psi; PsiContactList* contactList; OptionsMigration optionsMigration; OptionsTree accountTree; MainWin *mainwin; Idle idle; QList<item_dialog*> dialogList; int eventId; QStringList recentNodeList; // FIXME move this to options system? EDB *edb; S5BServer *s5bServer; ProxyManager *proxy; IconSelectPopup *iconSelect; FileTransDlg *ftwin; PsiActionList *actionList; //GlobalAccelManager *globalAccelManager; TuneController* tuneController; QMenuBar* defaultMenuBar; CapsRegistry* capsRegistry; TabManager *tabManager; AutoUpdater *autoUpdater; }; //---------------------------------------------------------------------------- // PsiCon //---------------------------------------------------------------------------- PsiCon::PsiCon() :QObject(0) { //pdb(DEBUG_JABCON, QString("%1 v%2\n By Justin Karneges\n infiniti@affinix.com\n\n").arg(PROG_NAME).arg(PROG_VERSION)); d = new Private(this); d->tabManager = new TabManager(this); d->mainwin = 0; d->ftwin = 0; d->eventId = 0; d->edb = new EDBFlatFile; d->s5bServer = 0; d->proxy = 0; d->tuneController = 0; d->autoUpdater = 0; d->actionList = 0; d->defaultMenuBar = new QMenuBar(0); d->capsRegistry = new CapsRegistry(); connect(d->capsRegistry, SIGNAL(registered(const CapsSpec&)), SLOT(saveCapabilities())); } PsiCon::~PsiCon() { deinit(); saveCapabilities(); delete d->capsRegistry; delete d->autoUpdater; delete d->actionList; delete d->edb; delete d->defaultMenuBar; delete d->tabManager; delete d; } bool PsiCon::init() { // check active profiles if (!ActiveProfiles::instance()->setThisProfile(activeProfile)) return false; connect(qApp, SIGNAL(forceSavePreferences()), SLOT(forceSavePreferences())); // PGP initialization (needs to be before any gpg usage!) PGPUtil::instance(); d->contactList = new PsiContactList(this); connect(d->contactList, SIGNAL(accountAdded(PsiAccount*)), SIGNAL(accountAdded(PsiAccount*))); connect(d->contactList, SIGNAL(accountRemoved(PsiAccount*)), SIGNAL(accountRemoved(PsiAccount*))); connect(d->contactList, SIGNAL(accountCountChanged()), SIGNAL(accountCountChanged())); connect(d->contactList, SIGNAL(accountActivityChanged()), SIGNAL(accountActivityChanged())); connect(d->contactList, SIGNAL(saveAccounts()), SLOT(saveAccounts())); // do some backuping in case we are about to start migration from config.xml+options.xml // to options.xml only. QString backupfile = optionsFile() + "-preOptionsMigration"; if (QFile::exists(pathToProfileConfig(activeProfile)) && PsiOptions::exists(optionsFile()) && !QFile::exists(backupfile)) { QFile::copy(optionsFile(), backupfile); } // advanced widget GAdvancedWidget::setStickEnabled( false ); //until this is bugless GAdvancedWidget::setStickToWindows( false ); //again GAdvancedWidget::setStickAt( 5 ); // To allow us to upgrade from old hardcoded options gracefully, be careful about the order here PsiOptions *options=PsiOptions::instance(); //load the system-wide defaults, if they exist QString systemDefaults=ApplicationInfo::resourcesDir(); systemDefaults += "/options-default.xml"; //qWarning(qPrintable(QString("Loading system defaults from %1").arg(systemDefaults))); options->load(systemDefaults); #ifdef USE_PEP // Create the tune controller d->tuneController = new CombinedTuneController(); #endif // Auto updater initialization #ifdef HAVE_SPARKLE d->autoUpdater = new SparkleAutoUpdater(ApplicationInfo::getAppCastURL()); #endif if (d->autoUpdater && PsiOptions::instance()->getOption("options.auto-update.check-on-startup").toBool()) { d->autoUpdater->checkForUpdates(); } // calculate the small font size const int minimumFontSize = 7; common_smallFontSize = qApp->font().pointSize(); common_smallFontSize -= 2; if ( common_smallFontSize < minimumFontSize ) common_smallFontSize = minimumFontSize; FancyLabel::setSmallFontSize( common_smallFontSize ); if (!PsiOptions::exists(optionsFile())) { if (!options->newProfile()) { qWarning("ERROR: Failed to new profile default options"); } } // load the old profile d->optionsMigration.fromFile(pathToProfileConfig(activeProfile)); //load the new profile //Save every time an option is changed options->load(optionsFile()); options->autoSave(true, optionsFile()); //just set a dummy option to trigger saving options->setOption("trigger-save",false); options->setOption("trigger-save",true); // do some late migration work d->optionsMigration.lateMigration(); QFile accountsFile(pathToProfile( activeProfile ) + "/accounts.xml"); bool accountMigration = false; if (!accountsFile.exists()) { accountMigration = true; int idx = 0; foreach(UserAccount a, d->optionsMigration.accMigration) { QString base = "accounts.a"+QString::number(idx++); a.toOptions(&d->accountTree, base); } } else { d->accountTree.loadOptions(accountsFile.fileName(), "accounts", ApplicationInfo::optionsNS()); } // proxy d->proxy = new ProxyManager(&d->accountTree, this); if (accountMigration) d->proxy->migrateItemList(d->optionsMigration.proxyMigration); connect(d->proxy, SIGNAL(settingsChanged()), SLOT(proxy_settingsChanged())); connect(options, SIGNAL(optionChanged(const QString&)), SLOT(optionChanged(const QString&))); QDir profileDir( pathToProfile( activeProfile ) ); profileDir.rmdir( "info" ); // remove unused dir d->iconSelect = new IconSelectPopup(0); connect(PsiIconset::instance(), SIGNAL(emoticonsChanged()), d, SLOT(updateIconSelect())); // first thing, try to load the iconset if( !PsiIconset::instance()->loadAll() ) { //LEGOPTS.iconset = "stellar"; //if(!is.load(LEGOPTS.iconset)) { QMessageBox::critical(0, tr("Error"), tr("Unable to load iconset! Please make sure Psi is properly installed.")); return false; //} } if ( !d->actionList ) d->actionList = new PsiActionList( this ); new PsiConObject(this); Anim::setMainThread(QThread::currentThread()); // setup the main window d->mainwin = new MainWin(PsiOptions::instance()->getOption("options.ui.contactlist.always-on-top").toBool(), (PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() && PsiOptions::instance()->getOption("options.contactlist.use-toolwindow").toBool()), this); d->mainwin->setUseDock(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool()); connect(d->mainwin, SIGNAL(closeProgram()), SLOT(closeProgram())); connect(d->mainwin, SIGNAL(changeProfile()), SLOT(changeProfile())); connect(d->mainwin, SIGNAL(doManageAccounts()), SLOT(doManageAccounts())); connect(d->mainwin, SIGNAL(doGroupChat()), SLOT(doGroupChat())); connect(d->mainwin, SIGNAL(blankMessage()), SLOT(doNewBlankMessage())); connect(d->mainwin, SIGNAL(statusChanged(int)), SLOT(statusMenuChanged(int))); connect(d->mainwin, SIGNAL(doOptions()), SLOT(doOptions())); connect(d->mainwin, SIGNAL(doToolbars()), SLOT(doToolbars())); connect(d->mainwin, SIGNAL(doFileTransDlg()), SLOT(doFileTransDlg())); connect(d->mainwin, SIGNAL(recvNextEvent()), SLOT(recvNextEvent())); connect(this, SIGNAL(emitOptionsUpdate()), d->mainwin, SLOT(optionsUpdate())); connect(this, SIGNAL(emitOptionsUpdate()), d->mainwin->cvlist, SLOT(optionsUpdate())); d->mainwin->setGeometryOptionPath("options.ui.contactlist.saved-window-geometry"); if(!(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() && PsiOptions::instance()->getOption("options.contactlist.hide-on-start").toBool())) d->mainwin->show(); d->ftwin = new FileTransDlg(this); d->idle.start(); // S5B d->s5bServer = new S5BServer; s5b_init(); // Connect to the system monitor SystemWatch* sw = SystemWatch::instance(); connect(sw, SIGNAL(sleep()), this, SLOT(doSleep())); connect(sw, SIGNAL(wakeup()), this, SLOT(doWakeup())); #ifdef PSI_PLUGINS // Plugin Manager PluginManager::instance(); #endif // Global shortcuts setShortcuts(); // FIXME #ifdef __GNUC__ #warning "Temporary hard-coding caps registration of own version" #endif // client()->identity() registerCaps(ApplicationInfo::capsVersion(), QStringList() << "http://jabber.org/protocol/bytestreams" << "http://jabber.org/protocol/si" << "http://jabber.org/protocol/si/profile/file-transfer" << "http://jabber.org/protocol/disco#info" << "http://jabber.org/protocol/commands" << "http://jabber.org/protocol/rosterx" << "http://jabber.org/protocol/muc" << "jabber:x:data" ); registerCaps("ep", QStringList() << "http://jabber.org/protocol/mood" << "http://jabber.org/protocol/tune" << "http://jabber.org/protocol/physloc" << "http://jabber.org/protocol/geoloc" << "http://www.xmpp.org/extensions/xep-0084.html#ns-data" << "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata" ); registerCaps("ep-notify", QStringList() << "http://jabber.org/protocol/mood+notify" << "http://jabber.org/protocol/tune+notify" << "http://jabber.org/protocol/physloc+notify" << "http://jabber.org/protocol/geoloc+notify" << "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata+notify" ); registerCaps("html", QStringList("http://jabber.org/protocol/xhtml-im")); registerCaps("cs", QStringList("http://jabber.org/protocol/chatstates")); //I've commented out the automatic replies, so commenting out support as well - KIS registerCaps("mr", QStringList("urn:xmpp:receipts")); // load accounts { QList<UserAccount> accs; QStringList bases = d->accountTree.getChildOptionNames("accounts", true, true); foreach (QString base, bases) { UserAccount ua; ua.fromOptions(&d->accountTree, base); accs += ua; } // Disable accounts if necessary, and overwrite locked properties if (PsiOptions::instance()->getOption("options.ui.account.single").toBool() || !PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) { bool haveEnabled = false; for(UserAccountList::Iterator it = accs.begin(); it != accs.end(); ++it) { // With single accounts, only modify the first account if (PsiOptions::instance()->getOption("options.ui.account.single").toBool()) { if (!haveEnabled) { haveEnabled = it->opt_enabled; if (it->opt_enabled) { if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) it->jid = JIDUtil::accountFromString(Jid(it->jid).node()).bare(); } } else it->opt_enabled = false; } else { // Overwirte locked properties if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) it->jid = JIDUtil::accountFromString(Jid(it->jid).node()).bare(); } } } d->contactList->loadAccounts(accs); } checkAccountsEmpty(); // try autologin if needed foreach(PsiAccount* account, d->contactList->accounts()) { account->autoLogin(); } // show tip of the day if ( PsiOptions::instance()->getOption("options.ui.tip.show").toBool() ) { TipDlg::show(this); } #ifdef USE_DBUS addPsiConAdapter(this); #endif connect(ActiveProfiles::instance(), SIGNAL(setStatusRequested(const QString &, const QString &)), SLOT(setStatusFromCommandline(const QString &, const QString &))); connect(ActiveProfiles::instance(), SIGNAL(openUriRequested(const QString &)), SLOT(openUri(const QString &))); connect(ActiveProfiles::instance(), SIGNAL(raiseRequested()), SLOT(raiseMainwin())); DesktopUtil::setUrlHandler("xmpp", this, "openUri"); if(AvCallManager::isSupported()) { options_avcall_update(); AvCallManager::setAudioOutDevice(PsiOptions::instance()->getOption("options.media.devices.audio-output").toString()); AvCallManager::setAudioInDevice(PsiOptions::instance()->getOption("options.media.devices.audio-input").toString()); AvCallManager::setVideoInDevice(PsiOptions::instance()->getOption("options.media.devices.video-input").toString()); AvCallManager::setBasePort(PsiOptions::instance()->getOption("options.p2p.bytestreams.listen-port").toInt()); AvCallManager::setExternalAddress(PsiOptions::instance()->getOption("options.p2p.bytestreams.external-address").toString()); } return true; } bool PsiCon::haveAutoUpdater() const { return d->autoUpdater != 0; } void PsiCon::registerCaps(const QString& ext, const QStringList& features) { DiscoItem::Identity identity = { "client", ApplicationInfo::name(), "pc" }; DiscoItem::Identities identities; identities += identity; d->capsRegistry->registerCaps(CapsSpec(ApplicationInfo::capsNode(), ApplicationInfo::capsVersion(), ext), identities, Features(features)); } void PsiCon::deinit() { // this deletes all dialogs except for mainwin deleteAllDialogs(); d->idle.stop(); // shut down all accounts UserAccountList acc; if(d->contactList) { acc = d->contactList->getUserAccountList(); delete d->contactList; } // delete s5b server delete d->s5bServer; delete d->ftwin; if(d->mainwin) { delete d->mainwin; d->mainwin = 0; } // TuneController delete d->tuneController; // save profile if(d->contactList) d->saveProfile(acc); GlobalShortcutManager::clear(); DesktopUtil::unsetUrlHandler("xmpp"); } void PsiCon::setShortcuts() { // FIX-ME: GlobalShortcutManager::clear() is one big hack, // but people wanted to change global hotkeys without restarting in 0.11 GlobalShortcutManager::clear(); ShortcutManager::connect("global.event", this, SLOT(recvNextEvent())); ShortcutManager::connect("global.toggle-visibility", d->mainwin, SLOT(toggleVisible())); ShortcutManager::connect("global.bring-to-front", d->mainwin, SLOT(trayShow())); ShortcutManager::connect("global.new-blank-message", this, SLOT(doNewBlankMessage())); } ContactView *PsiCon::contactView() const { if(d->mainwin) return d->mainwin->cvlist; else return 0; } PsiContactList* PsiCon::contactList() const { return d->contactList; } EDB *PsiCon::edb() const { return d->edb; } ProxyManager *PsiCon::proxy() const { return d->proxy; } FileTransDlg *PsiCon::ftdlg() const { return d->ftwin; } TuneController *PsiCon::tuneController() const { return d->tuneController; } void PsiCon::closeProgram() { quit(QuitProgram); } void PsiCon::changeProfile() { ActiveProfiles::instance()->unsetThisProfile(); if(d->contactList->haveActiveAccounts()) { QMessageBox messageBox(QMessageBox::Information, CAP(tr("Error")), tr("Please disconnect before changing the profile.")); QPushButton* cancel = messageBox.addButton(QMessageBox::Cancel); QPushButton* disconnect = messageBox.addButton(tr("&Disconnect"), QMessageBox::AcceptRole); messageBox.setDefaultButton(disconnect); messageBox.exec(); if (messageBox.clickedButton() == cancel) return; setStatusFromDialog(XMPP::Status::Offline, false); } quit(QuitProfile); } void PsiCon::doManageAccounts() { if (!PsiOptions::instance()->getOption("options.ui.account.single").toBool()) { AccountManageDlg *w = (AccountManageDlg *)dialogFind("AccountManageDlg"); if(w) bringToFront(w); else { w = new AccountManageDlg(this); w->show(); } } else { PsiAccount *account = d->contactList->defaultAccount(); if(account) { account->modify(); } else { promptUserToCreateAccount(); } } } void PsiCon::doGroupChat() { PsiAccount *account = d->contactList->defaultAccount(); if(!account) return; MUCJoinDlg *w = new MUCJoinDlg(this, account); w->show(); } void PsiCon::doNewBlankMessage() { PsiAccount *account = d->contactList->defaultAccount(); if(!account) return; EventDlg *w = createEventDlg("", account); w->show(); } // FIXME: smells fishy. Refactor! Probably create a common class for all dialogs and // call optionsUpdate() automatically. EventDlg *PsiCon::createEventDlg(const QString &to, PsiAccount *pa) { EventDlg *w = new EventDlg(to, this, pa); connect(this, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate())); return w; } // FIXME: WTF? Refactor! Refactor! void PsiCon::updateContactGlobal(PsiAccount *pa, const Jid &j) { foreach(item_dialog* i, d->dialogList) { if(i->className == "EventDlg") { EventDlg *e = (EventDlg *)i->widget; if(e->psiAccount() == pa) e->updateContact(j); } } } // FIXME: make it work like QObject::findChildren<ChildName>() QWidget *PsiCon::dialogFind(const char *className) { foreach(item_dialog *i, d->dialogList) { // does the classname and jid match? if(i->className == className) { return i->widget; } } return 0; } QMenuBar* PsiCon::defaultMenuBar() const { return d->defaultMenuBar; } void PsiCon::dialogRegister(QWidget *w) { item_dialog *i = new item_dialog; i->widget = w; i->className = w->metaObject()->className(); d->dialogList.append(i); } void PsiCon::dialogUnregister(QWidget *w) { for (QList<item_dialog*>::Iterator it = d->dialogList.begin(); it != d->dialogList.end(); ) { item_dialog* i = *it; if(i->widget == w) { it = d->dialogList.erase(it); delete i; } else ++it; } } void PsiCon::deleteAllDialogs() { while(!d->dialogList.isEmpty()) { item_dialog* i = d->dialogList.takeFirst(); delete i->widget; delete i; } d->tabManager->deleteAll(); } AccountsComboBox *PsiCon::accountsComboBox(QWidget *parent, bool online_only) { AccountsComboBox* acb = new AccountsComboBox(parent); acb->setController(this); acb->setOnlineOnly(online_only); return acb; } void PsiCon::createAccount(const QString &name, const Jid &j, const QString &pass, bool opt_host, const QString &host, int port, bool legacy_ssl_probe, UserAccount::SSLFlag ssl, QString proxy, const QString &tlsOverrideDomain, const QByteArray &tlsOverrideCert) { d->contactList->createAccount(name, j, pass, opt_host, host, port, legacy_ssl_probe, ssl, proxy, tlsOverrideDomain, tlsOverrideCert); } PsiAccount *PsiCon::createAccount(const UserAccount& acc) { PsiAccount *pa = new PsiAccount(acc, d->contactList, d->capsRegistry, d->tabManager); connect(&d->idle, SIGNAL(secondsIdle(int)), pa, SLOT(secondsIdle(int))); connect(pa, SIGNAL(updatedActivity()), SLOT(pa_updatedActivity())); connect(pa, SIGNAL(updatedAccount()), SLOT(pa_updatedAccount())); connect(pa, SIGNAL(queueChanged()), SLOT(queueChanged())); connect(pa, SIGNAL(startBounce()), SLOT(startBounce())); if (d->s5bServer) { pa->client()->s5bManager()->setServer(d->s5bServer); } return pa; } void PsiCon::removeAccount(PsiAccount *pa) { d->contactList->removeAccount(pa); } void PsiCon::statusMenuChanged(int x) { if(x == STATUS_OFFLINE && !PsiOptions::instance()->getOption("options.status.ask-for-message-on-offline").toBool()) { setGlobalStatus(Status(Status::Offline, "Logged out", 0)); if(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() == true) d->mainwin->setTrayToolTip(Status(Status::Offline, "", 0)); } else { if(x == STATUS_ONLINE && !PsiOptions::instance()->getOption("options.status.ask-for-message-on-online").toBool()) { setGlobalStatus(Status()); if(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() == true) d->mainwin->setTrayToolTip(Status()); } else if(x == STATUS_INVISIBLE){ Status s("","",0,true); s.setIsInvisible(true); setGlobalStatus(s); if(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() == true) d->mainwin->setTrayToolTip(s); } else { // Create a dialog with the last status message StatusSetDlg *w = new StatusSetDlg(this, makeStatus(x, PsiOptions::instance()->getOption("options.status.last-message").toString())); connect(w, SIGNAL(set(const XMPP::Status &, bool)), SLOT(setStatusFromDialog(const XMPP::Status &, bool))); connect(w, SIGNAL(cancelled()), SLOT(updateMainwinStatus())); if(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() == true) connect(w, SIGNAL(set(const XMPP::Status &, bool)), d->mainwin, SLOT(setTrayToolTip(const XMPP::Status &, bool))); w->show(); } } } void PsiCon::setStatusFromDialog(const Status &s, bool withPriority) { PsiOptions::instance()->setOption("options.status.last-message", s.status()); setGlobalStatus(s, withPriority); } void PsiCon::setStatusFromCommandline(const QString &status, const QString &message) { PsiOptions::instance()->setOption("options.status.last-message", message); XMPP::Status s; s.setType(status); s.setStatus(message); // yes, a bit different naming convention.. setGlobalStatus(s, false); } void PsiCon::setGlobalStatus(const Status &s, bool withPriority) { // Check whether all accounts are logged off bool allOffline = true; foreach(PsiAccount* account, d->contactList->enabledAccounts()) { if ( account->isActive() ) { allOffline = false; break; } } // globally set each account which is logged in foreach(PsiAccount* account, d->contactList->enabledAccounts()) if (allOffline || account->isActive()) account->setStatus(s, withPriority); } void PsiCon::pa_updatedActivity() { PsiAccount *pa = (PsiAccount *)sender(); emit accountUpdated(pa); // update s5b server updateS5BServerAddresses(); updateMainwinStatus(); } void PsiCon::pa_updatedAccount() { PsiAccount *pa = (PsiAccount *)sender(); emit accountUpdated(pa); saveAccounts(); } void PsiCon::saveAccounts() { UserAccountList acc = d->contactList->getUserAccountList(); d->saveProfile(acc); } void PsiCon::saveCapabilities() { QFile file(ApplicationInfo::homeDir() + "/caps.xml"); d->capsRegistry->save(file); } void PsiCon::updateMainwinStatus() { bool active = false; bool loggedIn = false; int state = STATUS_ONLINE; foreach(PsiAccount* account, d->contactList->enabledAccounts()) { if(account->isActive()) active = true; if(account->loggedIn()) { loggedIn = true; state = makeSTATUS(account->status()); } } if(loggedIn) d->mainwin->decorateButton(state); else { if(active) d->mainwin->decorateButton(-1); else d->mainwin->decorateButton(STATUS_OFFLINE); } } void PsiCon::doOptions() { OptionsDlg *w = (OptionsDlg *)dialogFind("OptionsDlg"); if(w) bringToFront(w); else { w = new OptionsDlg(this); connect(w, SIGNAL(applyOptions()), SLOT(slotApplyOptions())); w->show(); } } void PsiCon::doFileTransDlg() { bringToFront(d->ftwin); } void PsiCon::checkAccountsEmpty() { if (d->contactList->accounts().count() == 0) { promptUserToCreateAccount(); } } void PsiCon::openUri(const QString &uri) { QUrl url; url.setEncodedUrl(uri.toLatin1()); openUri(url); } void PsiCon::openUri(const QUrl &uri) { //qDebug() << "uri: " << uri.toString(); // scheme if (uri.scheme() != "xmpp") { QMessageBox::critical(0, tr("Unsupported URI type"), QString("URI (link) type \"%1\" is not supported.").arg(uri.scheme())); return; } // authority PsiAccount *pa = 0; //if (uri.authority().isEmpty()) { pa = d->contactList->defaultAccount(); if (!pa) { QMessageBox::critical(0, tr("Error"), QString("You need to have an account configured and enabled to open URIs (links).")); return; } // // TODO: finish authority component handling // //} else { // qDebug() << "uri auth: [" << uri.authority() << "]"); // // is there such account ready to use? // Jid authJid = JIDUtil::fromString(uri.authority()); // foreach (PsiAccount* acc, d->contactList->enabledAccounts()) { // if (acc->jid().compare(authJid, false)) { // pa = acc; // } // } // // or maybe it is configured but not enabled? // if (!pa) { // foreach (PsiAccount* acc, d->contactList->accounts()) { // if (acc->jid().compare(authJid, false)) { // QMessageBox::error(0, tr("Error"), QString("The account for %1 JID is disabled right now.").arg(authJid.bare())); // return; // TODO: Should suggest enabling it now // } // } // } // // nope.. // if (!pa) { // QMessageBox::error(0, tr("Error"), QString("You don't have an account for %1.").arg(authJid.bare())); // return; // } //} pa->openUri(uri); } void PsiCon::doToolbars() { OptionsDlg *w = (OptionsDlg *)dialogFind("OptionsDlg"); if (w) { w->openTab("toolbars"); bringToFront(w); } else { w = new OptionsDlg(this); connect(w, SIGNAL(applyOptions()), SLOT(slotApplyOptions())); w->openTab("toolbars"); w->show(); } } void PsiCon::optionChanged(const QString& option) { bool notifyRestart = true; // Global shortcuts setShortcuts(); if (option == "options.ui.notifications.alert-style") { alertIconUpdateAlertStyle(); } if (option == "options.ui.tabs.use-tabs") { QMessageBox::information(0, tr("Information"), tr("Some of the options you changed will only have full effect upon restart.")); notifyRestart = false; } // update s5b if (option == "options.p2p.bytestreams.listen-port") { s5b_init(); } } void PsiCon::slotApplyOptions() { PsiIconset::instance()->reloadRoster(); #ifndef Q_WS_MAC PsiOptions *o = PsiOptions::instance(); if (!PsiOptions::instance()->getOption("options.ui.contactlist.show-menubar").toBool()) { // check if all toolbars are disabled bool toolbarsVisible = false; foreach(QString base, o->getChildOptionNames("options.ui.contactlist.toolbars", true, true)) { if (o->getOption( base + ".visible").toBool()) { toolbarsVisible = true; break; } } // Check whether it is legal to disable the menubar if ( !toolbarsVisible ) { QMessageBox::warning(0, tr("Warning"), tr("You can not disable <i>all</i> toolbars <i>and</i> the menubar. If you do so, you will be unable to enable them back, when you'll change your mind."), tr("I understand")); PsiOptions::instance()->setOption("options.ui.contactlist.show-menubar", true); } } #endif updateS5BServerAddresses(); if(AvCallManager::isSupported()) { AvCallManager::setAudioOutDevice(PsiOptions::instance()->getOption("options.media.devices.audio-output").toString()); AvCallManager::setAudioInDevice(PsiOptions::instance()->getOption("options.media.devices.audio-input").toString()); AvCallManager::setVideoInDevice(PsiOptions::instance()->getOption("options.media.devices.video-input").toString()); AvCallManager::setBasePort(PsiOptions::instance()->getOption("options.p2p.bytestreams.listen-port").toInt()); AvCallManager::setExternalAddress(PsiOptions::instance()->getOption("options.p2p.bytestreams.external-address").toString()); } // mainwin stuff d->mainwin->setWindowOpts(PsiOptions::instance()->getOption("options.ui.contactlist.always-on-top").toBool(), (PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool() && PsiOptions::instance()->getOption("options.contactlist.use-toolwindow").toBool())); d->mainwin->setUseDock(PsiOptions::instance()->getOption("options.ui.systemtray.enable").toBool()); d->mainwin->buildToolbars(); // notify about options change emit emitOptionsUpdate(); } int PsiCon::getId() { return d->eventId++; } void PsiCon::queueChanged() { PsiIcon *nextAnim = 0; int nextAmount = d->contactList->queueCount(); PsiAccount *pa = d->contactList->queueLowestEventId(); if(pa) nextAnim = PsiIconset::instance()->event2icon(pa->eventQueue()->peekNext()); #ifdef Q_WS_MAC { // Update the event count MacDock::overlay(nextAmount ? QString::number(nextAmount) : QString()); if (!nextAmount) { MacDock::stopBounce(); } } #endif d->mainwin->updateReadNext(nextAnim, nextAmount); } void PsiCon::startBounce() { #ifdef Q_WS_MAC if (PsiOptions::instance()->getOption("options.ui.notifications.bounce-dock").toString() != "never") { MacDock::startBounce(); if (PsiOptions::instance()->getOption("options.ui.notifications.bounce-dock").toString() == "once") { MacDock::stopBounce(); } } #endif } void PsiCon::recvNextEvent() { /*printf("--- Queue Content: ---\n"); PsiAccountListIt it(d->list); for(PsiAccount *pa; (pa = it.current()); ++it) { printf(" Account: [%s]\n", pa->name().latin1()); pa->eventQueue()->printContent(); }*/ PsiAccount *pa = d->contactList->queueLowestEventId(); if(pa) pa->openNextEvent(UserAction); } void PsiCon::playSound(const QString &str) { if(str.isEmpty() || !PsiOptions::instance()->getOption("options.ui.notifications.sounds.enable").toBool()) return; soundPlay(str); } void PsiCon::raiseMainwin() { d->mainwin->showNoFocus(); } QStringList PsiCon::recentGCList() const { return PsiOptions::instance()->getOption("options.muc.recent-joins.jids").toStringList(); } void PsiCon::recentGCAdd(const QString &str) { QStringList recentList = recentGCList(); // remove it if we have it foreach(const QString& s, recentList) { if(s == str) { recentList.removeAll(s); break; } } // put it in the front recentList.prepend(str); // trim the list if bigger than 10 while(recentList.count() > PsiOptions::instance()->getOption("options.muc.recent-joins.maximum").toInt()) { recentList.takeLast(); } PsiOptions::instance()->setOption("options.muc.recent-joins.jids", recentList); } QStringList PsiCon::recentBrowseList() const { return PsiOptions::instance()->getOption("options.ui.service-discovery.recent-jids").toStringList(); } void PsiCon::recentBrowseAdd(const QString &str) { QStringList recentList = recentBrowseList(); // remove it if we have it foreach(const QString& s, recentList) { if(s == str) { recentList.removeAll(s); break; } } // put it in the front recentList.prepend(str); // trim the list if bigger than 10 while(recentList.count() > 10) { recentList.takeLast(); } PsiOptions::instance()->setOption("options.ui.service-discovery.recent-jids", recentList); } const QStringList & PsiCon::recentNodeList() const { return d->recentNodeList; } void PsiCon::recentNodeAdd(const QString &str) { // remove it if we have it foreach(const QString& s, d->recentNodeList) { if(s == str) { d->recentNodeList.removeAll(s); break; } } // put it in the front d->recentNodeList.prepend(str); // trim the list if bigger than 10 while(d->recentNodeList.count() > 10) d->recentNodeList.takeLast(); } void PsiCon::proxy_settingsChanged() { saveAccounts(); } IconSelectPopup *PsiCon::iconSelectPopup() const { return d->iconSelect; } void PsiCon::processEvent(PsiEvent *e, ActivationType activationType) { if ( e->type() == PsiEvent::PGP ) { e->account()->eventQueue()->dequeue(e); e->account()->queueChanged(); return; } if ( !e->account() ) return; UserListItem *u = e->account()->find(e->jid()); if ( !u ) { qWarning("SYSTEM MESSAGE: Bug #1. Contact the developers and tell them what you did to make this message appear. Thank you."); e->account()->eventQueue()->dequeue(e); e->account()->queueChanged(); return; } if( e->type() == PsiEvent::File ) { FileEvent *fe = (FileEvent *)e; FileTransfer *ft = fe->takeFileTransfer(); e->account()->eventQueue()->dequeue(e); e->account()->queueChanged(); e->account()->cpUpdate(*u); if(ft) { FileRequestDlg *w = new FileRequestDlg(fe->timeStamp(), ft, e->account()); bringToFront(w); } return; } if(e->type() == PsiEvent::AvCallType) { AvCallEvent *ae = (AvCallEvent *)e; AvCall *sess = ae->takeAvCall(); e->account()->eventQueue()->dequeue(e); e->account()->queueChanged(); e->account()->cpUpdate(*u); if(sess) { if(!sess->jid().isEmpty()) { CallDlg *w = new CallDlg(e->account(), 0); w->setAttribute(Qt::WA_DeleteOnClose); w->setIncoming(sess); bringToFront(w); } else { QMessageBox::information(0, tr("Call ended"), tr("Other party canceled call.")); delete sess; } } return; } bool isChat = false; bool sentToChatWindow = false; if ( e->type() == PsiEvent::Message ) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); bool emptyForm = m.getForm().fields().empty(); if ( m.type() == "chat" && emptyForm ) { isChat = true; sentToChatWindow = me->sentToChatWindow(); } } if ( isChat ) { PsiAccount* account = e->account(); XMPP::Jid from = e->from(); if ( PsiOptions::instance()->getOption("options.ui.chat.alert-for-already-open-chats").toBool() && sentToChatWindow ) { // Message already displayed, need only to pop up chat dialog, so that // it will be read (or marked as read) ChatDlg *c = account->findChatDialog(from); if(!c) c = account->findChatDialog(e->jid()); if(!c) return; // should never happen account->processChats(from); // this will delete all events, corresponding to that chat dialog } // as the event could be deleted just above, we're using cached account and from values account->openChat(from, activationType); } else { // search for an already opened eventdlg EventDlg *w = e->account()->findDialog<EventDlg*>(u->jid()); if ( !w ) { // create the eventdlg w = e->account()->ensureEventDlg(u->jid()); // load next message e->account()->processReadNext(*u); } bringToFront(w); } } void PsiCon::updateS5BServerAddresses() { if(!d->s5bServer) return; QList<QHostAddress> list; // grab all IP addresses foreach(PsiAccount* account, d->contactList->accounts()) { QHostAddress *a = account->localAddress(); if(!a) continue; // don't take dups bool found = false; for(QList<QHostAddress>::ConstIterator hit = list.begin(); hit != list.end(); ++hit) { const QHostAddress &ha = *hit; if(ha == (*a)) { found = true; break; } } if(!found) list += (*a); } // convert to stringlist QStringList slist; for(QList<QHostAddress>::ConstIterator hit = list.begin(); hit != list.end(); ++hit) slist += (*hit).toString(); // add external if(!PsiOptions::instance()->getOption("options.p2p.bytestreams.external-address").toString().isEmpty()) { bool found = false; for(QStringList::ConstIterator sit = slist.begin(); sit != slist.end(); ++sit) { const QString &s = *sit; if(s == PsiOptions::instance()->getOption("options.p2p.bytestreams.external-address").toString()) { found = true; break; } } if(!found) slist += PsiOptions::instance()->getOption("options.p2p.bytestreams.external-address").toString(); } // set up the server d->s5bServer->setHostList(slist); } void PsiCon::s5b_init() { if(d->s5bServer->isActive()) d->s5bServer->stop(); if (PsiOptions::instance()->getOption("options.p2p.bytestreams.listen-port").toInt()) { if(!d->s5bServer->start(PsiOptions::instance()->getOption("options.p2p.bytestreams.listen-port").toInt())) { QMessageBox::warning(0, tr("Warning"), tr("Unable to bind to port %1 for Data Transfer.\nThis may mean you are already running another instance of Psi. You may experience problems sending and/or receiving files.").arg(PsiOptions::instance()->getOption("options.p2p.bytestreams.listen-port").toInt())); } } } void PsiCon::doSleep() { setGlobalStatus(Status(Status::Offline, tr("Computer went to sleep"), 0)); } void PsiCon::doWakeup() { // TODO: Restore the status from before the log out. Make it an (hidden) option for people with a bad wireless connection. //setGlobalStatus(Status()); foreach(PsiAccount* account, d->contactList->enabledAccounts()) { if (account->userAccount().opt_connectAfterSleep) { // Should we do this when the network comes up ? account->setStatus(Status("", "", account->userAccount().priority)); } } } PsiActionList *PsiCon::actionList() const { return d->actionList; } /** * Prompts user to create new account, if none are currently present in system. */ void PsiCon::promptUserToCreateAccount() { QMessageBox msgBox(QMessageBox::Question,tr("Account setup"),tr("You need to set up an account to start. Would you like to register a new account, or use an existing account?")); QPushButton *registerButton = msgBox.addButton(tr("Register new account"), QMessageBox::AcceptRole); QPushButton *existingButton = msgBox.addButton(tr("Use existing account"),QMessageBox::AcceptRole); msgBox.addButton(QMessageBox::Cancel); msgBox.exec(); if (msgBox.clickedButton() == existingButton) { AccountModifyDlg w(this); w.exec(); } else if (msgBox.clickedButton() == registerButton) { AccountRegDlg w(proxy()); int n = w.exec(); if (n == QDialog::Accepted) { contactList()->createAccount(w.jid().node(),w.jid(),w.pass(),w.useHost(),w.host(),w.port(),w.legacySSLProbe(),w.ssl(),w.proxy(),w.tlsOverrideDomain(), w.tlsOverrideCert(), false); } } } QString PsiCon::optionsFile() const { return pathToProfile(activeProfile) + "/options.xml"; } void PsiCon::forceSavePreferences() { PsiOptions::instance()->save(optionsFile()); } #include "psicon.moc" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/infodlg.h������������������������������������������������������������������������������0000644�0001750�0001750�00000004330�11305557613�012723� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * infodlg.h - handle vcard * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef INFODLG_H #define INFODLG_H #include "ui_info.h" namespace XMPP { class Jid; class VCard; class Resource; } using namespace XMPP; class PsiAccount; class InfoDlg : public QDialog { Q_OBJECT public: enum { Self, Contact }; InfoDlg(int type, const XMPP::Jid &, const XMPP::VCard &, PsiAccount *, QWidget *parent=0, bool cacheVCard = true); ~InfoDlg(); protected: // reimplemented //void closeEvent(QCloseEvent *); void showEvent ( QShowEvent * event ); bool updatePhoto(); public slots: void doRefresh(); void updateStatus(); void closeEvent ( QCloseEvent * e ); void setStatusVisibility(bool visible); private slots: void contactAvailable(const Jid &, const Resource &); void contactUnavailable(const Jid &, const Resource &); void contactUpdated(const Jid &); void clientVersionFinished(); void requestLastActivityFinished(); void jt_finished(); void doSubmit(); void doDisco(); void doUpdateFromCalendar(); void doBDCheck(); void textChanged(); void selectPhoto(); void clearPhoto(); void showPhoto(); private: class Private; Private *d; Ui::Info ui_; QPushButton* pb_refresh_; QPushButton* pb_close_; QPushButton* pb_submit_; void setData(const XMPP::VCard &); XMPP::VCard makeVCard(); void fieldsEnable(bool); void setReadOnly(bool); bool edited(); void setEdited(bool); void setPreviewPhoto(const QString& str); void requestClientVersion(const XMPP::Jid& j); void requestLastActivity(); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pixmaputil.h���������������������������������������������������������������������������0000644�0001750�0001750�00000000226�11305557613�013475� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef PIXMAPUTIL_H #define PIXMAPUTIL_H class QPixmap; namespace PixmapUtil { QPixmap createTransparentPixmap(int width, int height); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/searchdlg.h����������������������������������������������������������������������������0000644�0001750�0001750�00000003132�11305557613�013234� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * searchdlg.h * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SEARCHDLG_H #define SEARCHDLG_H #include <QDialog> #include "ui_search.h" class PsiAccount; class QString; class QStringList; namespace XMPP { class Jid; } using namespace XMPP; class SearchDlg : public QDialog, public Ui::Search { Q_OBJECT public: SearchDlg(const XMPP::Jid &, PsiAccount *); ~SearchDlg(); signals: void aInfo(const Jid &); void add(const XMPP::Jid &, const QString &, const QStringList &, bool authReq); private slots: void doSearchGet(); void doSearchSet(); void selectionChanged(); void itemActivated(QTreeWidgetItem* item, int column); void jt_finished(); void doStop(); void doAdd(); void doInfo(); private: class Private; Private *d; void addEntry(const QString &jid, const QString &nick, const QString &first, const QString &last, const QString &email); void clear(); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/alerticon.h����������������������������������������������������������������������������0000644�0001750�0001750�00000003025�11305557613�013261� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * alerticon.h - class for handling animating alert icons * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ALERTICON_H #define ALERTICON_H #include "iconset.h" class QPixmap; class Impix; class QString; class QIcon; class QImage; class AlertIcon : public PsiIcon { Q_OBJECT public: AlertIcon(const PsiIcon *icon); ~AlertIcon(); // reimplemented virtual bool isAnimated() const; virtual const QPixmap &pixmap() const; virtual const QImage &image() const; virtual const QIcon & icon() const; virtual const Impix &impix() const; virtual int frameNumber() const; virtual const QString &name() const; virtual PsiIcon *copy() const; public slots: void activated(bool playSound = true); void stop(); public: class Private; private: Private *d; friend class Private; }; void alertIconUpdateAlertStyle(); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psievent.h�����������������������������������������������������������������������������0000644�0001750�0001750�00000017053�11305557613�013144� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psievent.h - events * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIEVENT_H #define PSIEVENT_H #include <QList> #include <QDateTime> #include <QObject> #include <QDomDocument> #include <QDomElement> #include <QPointer> #include "xmpp_jid.h" #include "xmpp_rosterx.h" #include "xmpp_message.h" #include "psihttpauthrequest.h" namespace XMPP { class FileTransfer; }; class PsiCon; class PsiAccount; class QDomElement; class AvCall; class PsiEvent : public QObject { Q_OBJECT public: PsiEvent(PsiAccount *); PsiEvent(const PsiEvent &); virtual ~PsiEvent() = 0; enum { Message, Auth, PGP, File, RosterExchange, //Status HttpAuth, AvCallType }; virtual int type() const = 0; virtual XMPP::Jid from() const = 0; virtual void setFrom(const XMPP::Jid &j) = 0; XMPP::Jid jid() const; void setJid(const XMPP::Jid &); bool originLocal() const; bool late() const; QDateTime timeStamp() const; void setOriginLocal(bool b); void setLate(bool b); void setTimeStamp(const QDateTime &t); PsiAccount *account() const; virtual QDomElement toXml(QDomDocument *) const; virtual bool fromXml(PsiCon *, PsiAccount *, const QDomElement *); virtual int priority() const; virtual QString description() const; virtual PsiEvent *copy() const; private: bool v_originLocal, v_late; QDateTime v_ts; XMPP::Jid v_jid; PsiAccount *v_account; }; // normal, chat, error, headline, etc class MessageEvent : public PsiEvent { Q_OBJECT public: MessageEvent(PsiAccount *acc); MessageEvent(const MessageEvent &from); MessageEvent(const XMPP::Message &, PsiAccount *acc); ~MessageEvent(); int type() const; XMPP::Jid from() const; void setFrom(const XMPP::Jid &j); const QString& nick() const; void setNick(const QString&); bool sentToChatWindow() const; const XMPP::Message & message() const; void setSentToChatWindow(bool b); void setMessage(const XMPP::Message &m); QDomElement toXml(QDomDocument *) const; bool fromXml(PsiCon *, PsiAccount *, const QDomElement *); virtual int priority() const; virtual QString description() const; virtual PsiEvent *copy() const; private: XMPP::Message v_m; bool v_sentToChatWindow; }; // subscribe, subscribed, unsubscribe, unsubscribed class AuthEvent : public PsiEvent { Q_OBJECT public: AuthEvent(const XMPP::Jid &j, const QString &authType, PsiAccount *acc); AuthEvent(const AuthEvent &from); ~AuthEvent(); int type() const; XMPP::Jid from() const; void setFrom(const XMPP::Jid &j); const QString& nick() const; void setNick(const QString&); QString authType() const; QDomElement toXml(QDomDocument *) const; bool fromXml(PsiCon *, PsiAccount *, const QDomElement *); virtual int priority() const; virtual QString description() const; virtual PsiEvent *copy() const; private: XMPP::Jid v_from; QString v_nick; QString v_at; }; // request pgp passphrase class PGPEvent : public PsiEvent { Q_OBJECT public: PGPEvent(PsiAccount *acc) : PsiEvent(acc) {} PGPEvent(const PGPEvent &from) : PsiEvent(from) {} ~PGPEvent() {} int type() const { return PGP; } XMPP::Jid from() const { return QString(); } void setFrom(const XMPP::Jid &) {} }; // incoming file transfer class FileEvent : public PsiEvent { Q_OBJECT public: FileEvent(const XMPP::Jid &j, XMPP::FileTransfer *ft, PsiAccount *acc); FileEvent(const FileEvent &from); ~FileEvent(); int type() const { return File; } XMPP::Jid from() const; void setFrom(const XMPP::Jid &); XMPP::FileTransfer *takeFileTransfer(); virtual int priority() const; virtual QString description() const; virtual PsiEvent *copy() const; private: XMPP::Jid v_from; QPointer<XMPP::FileTransfer> ft; }; // roster item exchange event class RosterExchangeEvent : public PsiEvent { Q_OBJECT public: RosterExchangeEvent(const XMPP::Jid &j, const XMPP::RosterExchangeItems& i, const QString& body, PsiAccount *acc); int type() const { return RosterExchange; } XMPP::Jid from() const; void setFrom(const XMPP::Jid &); const XMPP::RosterExchangeItems& rosterExchangeItems() const; void setRosterExchangeItems(const XMPP::RosterExchangeItems&); const QString& text() const; void setText(const QString& text); virtual int priority() const; virtual QString description() const; private: XMPP::Jid v_from; XMPP::RosterExchangeItems v_items; QString v_text; }; /*class StatusEvent : public PsiEvent { Q_OBJECT public: StatusEvent(const XMPP::Jid &j, const XMPP::Status& i, PsiAccount *acc); int type() const { return Status; } XMPP::Jid from() const; void setFrom(const XMPP::Jid &); const XMPP::Status& status() const; void setStatus(const XMPP::Status&); virtual int priority() const; private: XMPP::Jid v_from; XMPP::Status v_status; };*/ // http auth class HttpAuthEvent : public MessageEvent { Q_OBJECT public: HttpAuthEvent(const PsiHttpAuthRequest &req, PsiAccount *acc); ~HttpAuthEvent(); int type() const { return HttpAuth; } const PsiHttpAuthRequest & request() { return v_req; } virtual QString description() const; private: PsiHttpAuthRequest v_req; }; // incoming avcall class AvCallEvent : public PsiEvent { Q_OBJECT public: AvCallEvent(const XMPP::Jid &j, AvCall *sess, PsiAccount *acc); AvCallEvent(const AvCallEvent &from); ~AvCallEvent(); int type() const { return AvCallType; } XMPP::Jid from() const; void setFrom(const XMPP::Jid &); AvCall *takeAvCall(); virtual int priority() const; virtual QString description() const; virtual PsiEvent *copy() const; private: XMPP::Jid v_from; QPointer<AvCall> sess; }; class EventItem { public: EventItem(PsiEvent *_e, int i); EventItem(const EventItem &from); ~EventItem(); int id() const; PsiEvent *event() const; private: PsiEvent *e; int v_id; }; // event queue class EventQueue : public QObject { Q_OBJECT public: EventQueue(PsiAccount *); EventQueue(const EventQueue &); ~EventQueue(); EventQueue &operator= (const EventQueue &); int nextId() const; int count() const; int count(const XMPP::Jid &, bool compareRes=true) const; void enqueue(PsiEvent *); void dequeue(PsiEvent *); PsiEvent *dequeue(const XMPP::Jid &, bool compareRes=true); PsiEvent *peek(const XMPP::Jid &, bool compareRes=true) const; PsiEvent *dequeueNext(); PsiEvent *peekNext() const; bool hasChats(const XMPP::Jid &, bool compareRes=true) const; PsiEvent *peekFirstChat(const XMPP::Jid &, bool compareRes=true) const; void extractMessages(QList<PsiEvent*> *list); void extractChats(QList<PsiEvent*> *list, const XMPP::Jid &, bool compareRes=true); void printContent() const; void clear(); void clear(const XMPP::Jid &, bool compareRes=true); QDomElement toXml(QDomDocument *) const; // these work with pointers, to save inclusion of qdom.h, which is pretty large bool fromXml(const QDomElement *); bool toFile(const QString &fname); bool fromFile(const QString &fname); signals: void eventFromXml(PsiEvent *); void queueChanged(); private: class Private; Private *d; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pgpkey.ui������������������������������������������������������������������������������0000644�0001750�0001750�00000004036�11305557613�012771� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>PGPKey</class> <widget class="QDialog" name="PGPKey"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>522</width> <height>318</height> </rect> </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>219</width> <height>20</height> </size> </property> </spacer> </item> <item row="0" column="1"> <widget class="QLabel" name="label"> <property name="text"> <string>Filter:</string> </property> </widget> </item> <item row="0" column="2"> <widget class="QLineEdit" name="le_filter"/> </item> <item row="1" column="0" colspan="3"> <widget class="QTreeView" name="lv_keys"> <property name="editTriggers"> <set>QAbstractItemView::NoEditTriggers</set> </property> <property name="indentation"> <number>0</number> </property> <property name="rootIsDecorated"> <bool>false</bool> </property> <property name="uniformRowHeights"> <bool>true</bool> </property> <property name="itemsExpandable"> <bool>false</bool> </property> <property name="sortingEnabled"> <bool>true</bool> </property> <property name="allColumnsShowFocus"> <bool>true</bool> </property> <attribute name="headerCascadingSectionResizes"> <bool>true</bool> </attribute> </widget> </item> <item row="2" column="0" colspan="3"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <resources/> <connections/> </ui> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/about.ui�������������������������������������������������������������������������������0000644�0001750�0001750�00000017657�11305557613�012621� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <author></author> <comment></comment> <exportmacro></exportmacro> <class>AboutDlg</class> <widget class="QDialog" name="AboutDlg" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>504</width> <height>320</height> </rect> </property> <property name="windowTitle" > <string>About Psi</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="IconLabel" name="lb_icon" > <property name="frameShape" > <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow" > <enum>QFrame::Plain</enum> </property> <property name="psiIconName" stdset="0" > <string>psi/logo_48</string> </property> </widget> </item> <item> <widget class="QLabel" name="lb_name" > <property name="sizePolicy" > <sizepolicy> <hsizetype>7</hsizetype> <vsizetype>5</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="textFormat" > <enum>Qt::RichText</enum> </property> </widget> </item> </layout> </item> <item> <widget class="QTabWidget" name="tw_tabs" > <widget class="QWidget" name="tab_about" > <attribute name="title" > <string>About</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> <item> <widget class="QLabel" name="lb_about" > <property name="sizePolicy" > <sizepolicy> <hsizetype>7</hsizetype> <vsizetype>7</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text" > <string>A cross-platform Jabber client designed for the Jabber power user.<br> <br> Copyright © 2001-2009 The Psi Team.<br> </string> </property> <property name="textFormat" > <enum>Qt::RichText</enum> </property> </widget> </item> <item> <widget class="URLLabel" name="uRLLabel1" > <property name="alignment" > <set>Qt::AlignCenter</set> </property> <property name="url" > <string>http://psi-im.org</string> </property> <property name="title" > <string>http://psi-im.org</string> </property> </widget> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> </layout> </widget> <widget class="QWidget" name="tab_authors" > <attribute name="title" > <string>Authors</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="PsiTextView" name="te_authors" /> </item> </layout> </widget> <widget class="QWidget" name="tab_thanks" > <attribute name="title" > <string>Thanks To</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="PsiTextView" name="te_thanks" /> </item> </layout> </widget> <widget class="QWidget" name="tab_translation" > <attribute name="title" > <string>Translation</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="PsiTextView" name="te_translation" > <property name="sizePolicy" > <sizepolicy> <hsizetype>5</hsizetype> <vsizetype>7</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> </item> </layout> </widget> <widget class="QWidget" name="tab_license" > <attribute name="title" > <string>License</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QTextEdit" name="te_license" > <property name="readOnly" > <bool>true</bool> </property> </widget> </item> </layout> </widget> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>418</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="IconButton" name="pb_close" > <property name="text" > <string>&Close</string> </property> <property name="default" > <bool>true</bool> </property> </widget> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11" /> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <customwidgets> <customwidget> <class>IconButton</class> <extends></extends> <header>iconbutton.h</header> <container>0</container> <pixmap></pixmap> </customwidget> <customwidget> <class>IconLabel</class> <extends></extends> <header>iconlabel.h</header> <container>0</container> <pixmap></pixmap> </customwidget> <customwidget> <class>PsiTextView</class> <extends></extends> <header>psitextview.h</header> <container>0</container> <pixmap></pixmap> </customwidget> <customwidget> <class>URLLabel</class> <extends></extends> <header>urllabel.h</header> <container>0</container> <pixmap></pixmap> </customwidget> </customwidgets> <resources/> <connections> <connection> <sender>pb_close</sender> <signal>clicked(bool)</signal> <receiver>AboutDlg</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel" > <x>436</x> <y>295</y> </hint> <hint type="destinationlabel" > <x>369</x> <y>299</y> </hint> </hints> </connection> </connections> </ui> ���������������������������������������������������������������������������������psi-0.14/src/xmlconsole.ui��������������������������������������������������������������������������0000644�0001750�0001750�00000007275�11305557613�013665� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <class>XMLConsole</class> <widget class="QWidget" name="XMLConsole" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>539</width> <height>447</height> </rect> </property> <property name="windowTitle" > <string>XML Console</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QTextEdit" name="te" /> </item> <item> <widget class="QGroupBox" name="gb_filter" > <property name="enabled" > <bool>false</bool> </property> <property name="title" > <string>Filter</string> </property> <layout class="QHBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QCheckBox" name="ck_message" > <property name="text" > <string>Message</string> </property> <property name="checked" > <bool>true</bool> </property> </widget> </item> <item> <widget class="QCheckBox" name="ck_presence" > <property name="text" > <string>Presence</string> </property> <property name="checked" > <bool>true</bool> </property> </widget> </item> <item> <widget class="QCheckBox" name="ck_iq" > <property name="text" > <string>IQ</string> </property> <property name="checked" > <bool>true</bool> </property> </widget> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" > <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QLabel" name="label" > <property name="text" > <string>JID:</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="le_jid" /> </item> </layout> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QCheckBox" name="ck_enable" > <property name="text" > <string>Enable</string> </property> </widget> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" > <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="pb_dumpRingbuf" > <property name="text" > <string>Dump Ringbuf</string> </property> </widget> </item> <item> <widget class="QPushButton" name="pb_clear" > <property name="text" > <string>Clear</string> </property> </widget> </item> <item> <widget class="QPushButton" name="pb_input" > <property name="text" > <string>XML Input...</string> </property> </widget> </item> <item> <widget class="QPushButton" name="pb_close" > <property name="text" > <string>Close</string> </property> </widget> </item> </layout> </item> </layout> </widget> <resources/> <connections/> </ui> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/ahcommanddlg.ui������������������������������������������������������������������������0000644�0001750�0001750�00000002455�11305557613�014113� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>AHCommandDlg</class> <widget class="QWidget" name="AHCommandDlg"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>300</width> <height>84</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Command:</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> <item row="0" column="1"> <widget class="QComboBox" name="cb_commands"/> </item> <item row="1" column="0"> <widget class="BusyWidget" name="busy" native="true"/> </item> <item row="1" column="1"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="standardButtons"> <set>QDialogButtonBox::Cancel</set> </property> </widget> </item> </layout> </widget> <customwidgets> <customwidget> <class>BusyWidget</class> <extends>QWidget</extends> <header>busywidget.h</header> <container>1</container> </customwidget> </customwidgets> <resources/> <connections/> </ui> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/info.ui��������������������������������������������������������������������������������0000644�0001750�0001750�00000036333�11305557613�012432� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <author></author> <comment></comment> <exportmacro></exportmacro> <class>Info</class> <widget class="QDialog" name="Info" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>477</width> <height>337</height> </rect> </property> <property name="windowTitle" > <string>User Info</string> </property> <property name="sizeGripEnabled" > <bool>true</bool> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>8</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QTabWidget" name="tabwidget" > <widget class="QWidget" name="tab_general" > <attribute name="title" > <string>General</string> </attribute> <layout class="QGridLayout" > <property name="margin" > <number>8</number> </property> <property name="spacing" > <number>6</number> </property> <item row="1" column="1" > <widget class="QLineEdit" name="le_nickname" > <property name="minimumSize" > <size> <width>120</width> <height>0</height> </size> </property> </widget> </item> <item row="7" column="1" > <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>20</width> <height>60</height> </size> </property> </spacer> </item> <item row="5" column="0" > <widget class="QLabel" name="TextLabel1_2_2_2_2" > <property name="text" > <string>E-Mail:</string> </property> </widget> </item> <item row="0" column="1" colspan="2" > <widget class="ActionLineEdit" name="le_fullname" /> </item> <item row="2" column="0" > <widget class="QLabel" name="TextLabel1_3_2_3_2" > <property name="text" > <string>Birthday:</string> </property> </widget> </item> <item rowspan="5" row="1" column="2" > <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QToolButton" name="tb_photo" native="true"> <property name="shortcut" > <string>Alt+V</string> </property> <property name="toolTip" > <string>View in real size</string> </property> <property name="autoRaise" > <bool>true</bool> </property> <property name="sizePolicy" > <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize" > <size> <width>129</width> <height>129</height> </size> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QPushButton" name="pb_open" > <property name="sizePolicy" > <sizepolicy> <hsizetype>1</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text" > <string>&Open...</string> </property> <property name="shortcut" > <string>Alt+O</string> </property> <property name="autoDefault" > <bool>false</bool> </property> <property name="flat" > <bool>false</bool> </property> </widget> </item> <item> <widget class="QPushButton" name="pb_clear" > <property name="sizePolicy" > <sizepolicy> <hsizetype>1</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text" > <string>&Clear</string> </property> <property name="shortcut" > <string>Alt+C</string> </property> <property name="autoDefault" > <bool>false</bool> </property> <property name="flat" > <bool>false</bool> </property> </widget> </item> </layout> </item> </layout> </item> <item row="0" column="0" > <widget class="QLabel" name="TextLabel1_2_2" > <property name="text" > <string>Full Name:</string> </property> </widget> </item> <item row="3" column="0" > <widget class="QLabel" name="TextLabel1_3_2_2_2_2" > <property name="text" > <string>Phone #:</string> </property> </widget> </item> <item row="4" column="0" > <widget class="QLabel" name="TextLabel1_2_3_2" > <property name="text" > <string>Homepage:</string> </property> </widget> </item> <item row="1" column="0" > <widget class="QLabel" name="TextLabel1_2" > <property name="text" > <string>Nickname:</string> </property> </widget> </item> <item row="3" column="1" > <widget class="QLineEdit" name="le_phone" /> </item> <item row="2" column="1" > <widget class="ActionLineEdit" name="le_bday"> <property name="readOnly"> <bool>true</bool> </property> </widget> </item> <item row="4" column="1" > <widget class="QLineEdit" name="le_homepage" /> </item> <item row="5" column="1" > <widget class="QLineEdit" name="le_email" /> </item> </layout> </widget> <widget class="QWidget" name="tab_work" > <attribute name="title" > <string>Work</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>8</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QGridLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item row="2" column="1" > <widget class="QLineEdit" name="le_title" /> </item> <item row="0" column="0" > <widget class="QLabel" name="TextLabel1_2_2_2_3" > <property name="text" > <string>Company:</string> </property> </widget> </item> <item row="2" column="0" > <widget class="QLabel" name="TextLabel1_3_2_2_2_3_2" > <property name="text" > <string>Position:</string> </property> </widget> </item> <item row="0" column="1" > <widget class="QLineEdit" name="le_orgName" /> </item> <item row="1" column="0" > <widget class="QLabel" name="TextLabel1_2_3_3" > <property name="text" > <string>Department:</string> </property> </widget> </item> <item row="1" column="1" > <widget class="QLineEdit" name="le_orgUnit" /> </item> <item row="3" column="1" > <widget class="QLineEdit" name="le_role" /> </item> <item row="3" column="0" > <widget class="QLabel" name="TextLabel1_3_2_2_2_4" > <property name="text" > <string>Role:</string> </property> </widget> </item> </layout> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>0</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> <widget class="QWidget" name="tab_location" > <attribute name="title" > <string>Location</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>8</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QGridLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item row="5" column="0" > <widget class="QLabel" name="TextLabel1_3_2_2_2" > <property name="text" > <string>Country:</string> </property> </widget> </item> <item row="4" column="0" > <widget class="QLabel" name="TextLabel1_3_2_2_2_3" > <property name="text" > <string>Postal Code:</string> </property> </widget> </item> <item row="1" column="1" > <widget class="QLineEdit" name="le_ext" /> </item> <item row="5" column="1" > <widget class="QLineEdit" name="le_country" /> </item> <item row="4" column="1" > <widget class="QLineEdit" name="le_pcode" /> </item> <item row="3" column="0" > <widget class="QLabel" name="TextLabel1_2_3" > <property name="text" > <string>State:</string> </property> </widget> </item> <item row="2" column="0" > <widget class="QLabel" name="TextLabel1_2_2_2" > <property name="text" > <string>City:</string> </property> </widget> </item> <item row="0" column="1" > <widget class="QLineEdit" name="le_street" /> </item> <item row="0" column="0" > <widget class="QLabel" name="TextLabel1_3_2_3" > <property name="text" > <string>Street:</string> </property> </widget> </item> <item row="3" column="1" > <widget class="QLineEdit" name="le_state" /> </item> <item row="2" column="1" > <widget class="QLineEdit" name="le_city" /> </item> </layout> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>0</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> <widget class="QWidget" name="tab_about" > <attribute name="title" > <string>About</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>8</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QTextEdit" name="te_desc" /> </item> </layout> </widget> <widget class="QWidget" name="tab_status" > <attribute name="title" > <string>Status</string> </attribute> <layout class="QVBoxLayout" > <property name="margin" > <number>8</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="PsiTextView" name="te_status" /> </item> </layout> </widget> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="BusyWidget" name="busy" /> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>190</width> <height>16</height> </size> </property> </spacer> </item> <item> <widget class="IconButton" name="pb_disco" > <property name="shortcut" > <string>Alt+D</string> </property> <property name="psiIconName" stdset="0" > <string>psi/disco</string> </property> </widget> </item> <item> <widget class="IconButton" name="pb_submit" > <property name="text" > <string>&Publish</string> </property> </widget> </item> <item> <widget class="IconButton" name="pb_refresh" > <property name="text" > <string>&Retrieve</string> </property> <property name="psiIconName" stdset="0" > <string>psi/reload</string> </property> </widget> </item> <item> <widget class="IconButton" name="pb_close" > <property name="text" > <string>&Close</string> </property> <property name="psiIconName" stdset="0" > <string>psi/close</string> </property> </widget> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11" /> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <tabstops> <tabstop>tabwidget</tabstop> <tabstop>le_fullname</tabstop> <tabstop>le_nickname</tabstop> <tabstop>le_bday</tabstop> <tabstop>le_phone</tabstop> <tabstop>le_homepage</tabstop> <tabstop>le_email</tabstop> <tabstop>tb_photo</tabstop> <tabstop>pb_open</tabstop> <tabstop>pb_clear</tabstop> <tabstop>pb_disco</tabstop> <tabstop>pb_submit</tabstop> <tabstop>pb_refresh</tabstop> <tabstop>pb_close</tabstop> <tabstop>le_orgName</tabstop> <tabstop>le_orgUnit</tabstop> <tabstop>le_title</tabstop> <tabstop>le_role</tabstop> <tabstop>le_street</tabstop> <tabstop>le_ext</tabstop> <tabstop>le_city</tabstop> <tabstop>le_state</tabstop> <tabstop>le_pcode</tabstop> <tabstop>le_country</tabstop> <tabstop>te_desc</tabstop> </tabstops> <includes/> <customwidgets> <customwidget> <class>ActionLineEdit</class> <extends>QLineEdit</extends> <header>actionlineedit.h</header> </customwidget> </customwidgets> <resources/> <connections/> </ui> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/accountadddlg.h������������������������������������������������������������������������0000644�0001750�0001750�00000002356�11305557613�014103� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * accountadddlg.h - dialogs for manipulating PsiAccounts * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACCOUNTADDDLG_H #define ACCOUNTADDDLG_H #include <QDialog> #include "ui_accountadd.h" class PsiCon; class QWidget; class QString; class AccountAddDlg : public QDialog, public Ui::AccountAdd { Q_OBJECT public: AccountAddDlg(PsiCon *, QWidget *parent=0); ~AccountAddDlg(); private slots: void add(); void setAddButton(const QString &); private: PsiCon *psi; QString createNewAccountName(QString def); }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/changepw.ui����������������������������������������������������������������������������0000644�0001750�0001750�00000006103�11305557613�013263� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>ChangePassword</class> <widget class="QDialog" name="ChangePassword"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>331</width> <height>179</height> </rect> </property> <property name="windowTitle"> <string>Change Password</string> </property> <layout class="QVBoxLayout" name="_2"> <item> <layout class="QGridLayout" name="_3"> <item row="2" column="1"> <widget class="QLineEdit" name="le_pwver"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> <item row="0" column="1"> <widget class="QLineEdit" name="le_pwcur"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="lb_pwver"> <property name="text"> <string>Confirm new password:</string> </property> </widget> </item> <item row="0" column="0"> <widget class="QLabel" name="lb_pwcur"> <property name="text"> <string>Current password:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLineEdit" name="le_pwnew"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="lb_pwnew"> <property name="text"> <string>New password:</string> </property> </widget> </item> </layout> </item> <item> <spacer name="Spacer2"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>16</height> </size> </property> </spacer> </item> <item> <widget class="Line" name="Line1"> <property name="frameShape"> <enum>QFrame::HLine</enum> </property> <property name="frameShadow"> <enum>QFrame::Sunken</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout"> <item> <widget class="BusyWidget" name="busy" native="true"/> </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <customwidgets> <customwidget> <class>BusyWidget</class> <extends>QWidget</extends> <header>busywidget.h</header> <container>1</container> </customwidget> </customwidgets> <tabstops> <tabstop>le_pwcur</tabstop> <tabstop>le_pwnew</tabstop> <tabstop>le_pwver</tabstop> </tabstops> <resources/> <connections/> </ui> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/shortcutmanager.cpp��������������������������������������������������������������������0000644�0001750�0001750�00000011210�11305557613�015035� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QAction> #include <QCoreApplication> #include "psioptions.h" #include "shortcutmanager.h" #include "globalshortcutmanager.h" /** * \brief The Construtor of the Shortcutmanager */ ShortcutManager::ShortcutManager() : QObject(QCoreApplication::instance()) { // Make sure that there is at least one shortcut for sending messages if (shortcuts("chat.send").isEmpty()) { qWarning("Restoring chat.send shortcut"); QVariantList vl; vl << qVariantFromValue(QKeySequence(Qt::Key_Enter)) << qVariantFromValue(QKeySequence(Qt::Key_Return)); PsiOptions::instance()->setOption("options.shortcuts.chat.send",vl); } } /** * "The one and only instance" of the ShortcutManager */ ShortcutManager* ShortcutManager::instance_ = NULL; /** * \brief The Instantiator of the Shortcutmanager */ ShortcutManager* ShortcutManager::instance() { if(!instance_) instance_ = new ShortcutManager(); return instance_; } /** * \brief get the QKeySequence associated with the keyname "name" * \param the shortcut name e.g. "misc.sendmessage" which is in the options xml then * mirrored as options.shortcuts.misc.sendmessage * \return QKeySequence, the Keysequence associated with the keyname, or * the first key sequence if there are multiple */ QKeySequence ShortcutManager::shortcut(const QString& name) { QVariant variant = PsiOptions::instance()->getOption(QString("options.shortcuts.%1").arg(name)); QList<QKeySequence> list = shortcuts(name); if (!list.isEmpty()) return list.first(); return variant.value<QKeySequence>(); } /** * Users tend to get really confused when they see 'Return' in menu * shortcuts. 'Enter' is much more common, so we'd better use it. * * Examples: * 'Enter' should be preferred over 'Return' and 'Ctrl+Enter' should be * preferred over 'Ctrl+Return'. */ static bool shortcutManagerKeySequenceLessThan(const QKeySequence& k1, const QKeySequence& k2) { bool e1 = k1.toString(QKeySequence::PortableText).contains("Enter"); bool e2 = k2.toString(QKeySequence::PortableText).contains("Enter"); return e1 && !e2; } /** * \brief get the QVariantList associated with the keyname "name" * \param the shortcut name e.g. "misc.sendmessage" which is in the options xml then * mirrored as options.shortcuts.misc.sendmessage * \return List of sequences */ QList<QKeySequence> ShortcutManager::shortcuts(const QString& name) { return readShortcutsFromOptions(name, PsiOptions::instance()); } /** * \brief read the QVariantList associated with the keyname "name" in given PsiOptions * \param name, the shortcut name e.g. "misc.sendmessage" which is in the options xml then * mirrored as options.shortcuts.misc.sendmessage * \param options, options instance to read from * \return List of sequences */ QList<QKeySequence> ShortcutManager::readShortcutsFromOptions(const QString& name, const PsiOptions* options) { QList<QKeySequence> list; QVariant variant = options->getOption(QString("options.shortcuts.%1").arg(name)); QString type = variant.typeName(); if (type == "QVariantList") { foreach(QVariant variant, variant.toList()) { QKeySequence k = variant.value<QKeySequence>(); if (!k.isEmpty() && !list.contains(k)) list += k; } } else { QKeySequence k = variant.value<QKeySequence>(); if (!k.isEmpty()) list += k; } qStableSort(list.begin(), list.end(), shortcutManagerKeySequenceLessThan); return list; } /** * \brief this function connects the Key or Keys associated with the keyname "path" with the slot "slot" * of the Widget "parent" * \param path, the shortcut name e.g. "misc.sendmessage" which is in the options xml then * mirrored as options.shortcuts.misc.sendmessage * \param parent, the widget to which the new QAction should be connected to * \param slot, the SLOT() of the parent which should be triggered if the KeySequence is activated */ void ShortcutManager::connect(const QString& path, QObject* parent, const char* slot) { if (parent == NULL || slot == NULL) return; if (!path.startsWith("global.")) { QList<QKeySequence> shortcuts = ShortcutManager::instance()->shortcuts(path); if (!shortcuts.isEmpty()) { bool appWide = path.startsWith("appwide."); QAction* act = new QAction(parent); act->setShortcuts(shortcuts); act->setShortcutContext(appWide ? Qt::ApplicationShortcut : Qt::WindowShortcut); if (parent->isWidgetType()) ((QWidget*) parent)->addAction(act); parent->connect(act, SIGNAL(activated()), slot); } } else { foreach(QKeySequence sequence, ShortcutManager::instance()->shortcuts(path)) { if (!sequence.isEmpty()) { GlobalShortcutManager::instance()->connect(sequence, parent, slot); } } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/��������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�013535� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/Certificates.pri����������������������������������������������������������0000644�0001750�0001750�00000000511�11305557613�016653� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INCLUDEPATH *= $$PWD/.. DEPENDPATH *= $$PWD/.. $$PWD INTERFACES += \ $$PWD/CertificateDisplay.ui HEADERS += \ $$PWD/CertificateDisplayDialog.h \ $$PWD/CertificateErrorDialog.h \ $$PWD/CertificateHelpers.h SOURCES += \ $$PWD/CertificateDisplayDialog.cpp \ $$PWD/CertificateErrorDialog.cpp \ $$PWD/CertificateHelpers.cpp ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/CertificateHelpers.cpp����������������������������������������������������0000644�0001750�0001750�00000013347�11305557613�020016� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * Licensed under the GNU GPL license. * See COPYING for details. */ #include <QtDebug> #include <QtCrypto> #include <QStringList> #include <QDomDocument> #include <QDebug> #include <QDir> #include <QFile> #include <QMessageBox> #include "Certificates/CertificateHelpers.h" #include "xmpp.h" #include "Certificates/CertificateErrorDialog.h" using namespace QCA; /** * \class CertificateHelpers * \brief A class providing utility functions for Certificates. */ /** * \brief Returns the collection of all available certificates. * This collection includes the system-wide certificates, as well as any * custom certificate in the Psi-specific cert dirs. */ CertificateCollection CertificateHelpers::allCertificates(const QStringList& storeDirs) { CertificateCollection certs(systemStore()); for (QStringList::ConstIterator s = storeDirs.begin(); s != storeDirs.end(); ++s) { QDir store(*s); // Read in PEM certificates store.setNameFilters(QStringList("*.crt") + QStringList("*.pem")); QStringList cert_files = store.entryList(); for (QStringList::ConstIterator c = cert_files.begin(); c != cert_files.end(); ++c) { //qDebug() << "certutil.cpp: Reading " << store.filePath(*c); ConvertResult result; Certificate cert = Certificate::fromPEMFile(store.filePath(*c),&result); if (result == ConvertGood) { certs.addCertificate(cert); } else { qWarning() << QString("certutil.cpp: Invalid PEM certificate: %1").arg(store.filePath(*c)); } } // Read in old XML format certificates (DEPRECATED) store.setNameFilters(QStringList("*.xml")); cert_files = store.entryList(); for(QStringList::ConstIterator it = cert_files.begin(); it != cert_files.end(); ++it) { qWarning() << "Loading certificate in obsolete XML format: " << store.filePath(*it); QFile f(store.filePath(*it)); if(!f.open(QIODevice::ReadOnly)) continue; QDomDocument doc; bool ok = doc.setContent(&f); f.close(); if(!ok) continue; QDomElement base = doc.documentElement(); if(base.tagName() != "store") continue; QDomNodeList cl = base.elementsByTagName("certificate"); for(int n = 0; n < (int)cl.count(); ++n) { QDomElement data = cl.item(n).toElement().elementsByTagName("data").item(0).toElement(); if(!data.isNull()) { ConvertResult result; Certificate cert = Certificate::fromDER(Base64().stringToArray(data.text()).toByteArray(),&result); if (result == ConvertGood) { certs.addCertificate(cert); } else { qWarning() << "certutil.cpp: Invalid XML certificate: %1" << store.filePath(*it); } } } } } return certs; } QString CertificateHelpers::validityToString(QCA::Validity v) { QString s; switch(v) { case QCA::ValidityGood: s = "Validated"; break; case QCA::ErrorRejected: s = "Root CA is marked to reject the specified purpose"; break; case QCA::ErrorUntrusted: s = "Certificate not trusted for the required purpose"; break; case QCA::ErrorSignatureFailed: s = "Invalid signature"; break; case QCA::ErrorInvalidCA: s = "Invalid CA certificate"; break; case QCA::ErrorInvalidPurpose: s = "Invalid certificate purpose"; break; case QCA::ErrorSelfSigned: s = "Certificate is self-signed"; break; case QCA::ErrorRevoked: s = "Certificate has been revoked"; break; case QCA::ErrorPathLengthExceeded: s = "Maximum certificate chain length exceeded"; break; case QCA::ErrorExpired: s = "Certificate has expired"; break; case QCA::ErrorExpiredCA: s = "CA has expired"; break; case QCA::ErrorValidityUnknown: default: s = "General certificate validation error"; break; } return s; } QString CertificateHelpers::resultToString(int result, QCA::Validity validity) { QString s; switch(result) { case QCA::TLS::NoCertificate: s = QObject::tr("The server did not present a certificate."); break; case QCA::TLS::Valid: s = QObject::tr("Certificate is valid."); break; case QCA::TLS::HostMismatch: s = QObject::tr("The hostname does not match the one the certificate was issued to."); break; case QCA::TLS::InvalidCertificate: s = validityToString(validity); break; default: s = QObject::tr("General certificate validation error."); break; } return s; } // shared by PsiAccount and MiniClient bool CertificateHelpers::checkCertificate(QCA::TLS* tls, XMPP::QCATLSHandler *tlsHandler, QString &tlsOverrideDomain, QByteArray &tlsOverrideCert, QObject * canceler, const QString &title, const QString &host) { QCA::Certificate cert = tls->peerCertificateChain().primary(); int result = tls->peerIdentityResult(); QString hostnameOverrideable; if (result == QCA::TLS::Valid && !tlsHandler->certMatchesHostname()) { QList<QString> lst = cert.subjectInfo().values(QCA::CommonName); if (lst.size() == 1) { hostnameOverrideable = lst[0]; } if (lst.size() != 1 || lst[0].isEmpty() || lst[0] != tlsOverrideDomain) { result = QCA::TLS::HostMismatch; } } // if this cert equals the user trusted certificate, just trust the user's choice. if (result != QCA::TLS::Valid && !tlsOverrideCert.isEmpty()) { if (cert.toDER() == tlsOverrideCert) { result = QCA::TLS::Valid; } } if (result != QCA::TLS::Valid) { CertificateErrorDialog errorDialog( title, host, cert, result, tls->peerCertificateValidity(), hostnameOverrideable, tlsOverrideDomain, tlsOverrideCert); if (canceler) { QObject::connect(canceler, SIGNAL(disconnected()), &errorDialog, SLOT(reject()), Qt::AutoConnection); QObject::connect(canceler, SIGNAL(reconnecting()), &errorDialog, SLOT(reject()), Qt::AutoConnection); } if (errorDialog.exec() == QDialog::Accepted) { return true; } else { return false; } } else { return true; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/CertificateDisplayDialog.cpp����������������������������������������������0000644�0001750�0001750�00000007512�11305557613�021136� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QtCrypto> #include <QDateTime> #include <QLabel> #include <QPushButton> #include "Certificates/CertificateHelpers.h" #include "Certificates/CertificateDisplayDialog.h" CertificateDisplayDialog::CertificateDisplayDialog(const QCA::Certificate &cert, int result, QCA::Validity validity, QWidget *parent) : QDialog(parent) { ui_.setupUi(this); setModal(true); connect(ui_.pb_close, SIGNAL(clicked()), SLOT(close())); ui_.pb_close->setDefault(true); ui_.pb_close->setFocus(); if(cert.isNull()) { return; } if (result == QCA::TLS::Valid) { ui_.lb_valid->setText(tr("The certificate is valid.")); setLabelStatus(*ui_.lb_valid, true); } else { ui_.lb_valid->setText(tr("The certificate is NOT valid!") + "\n" + QString(tr("Reason: %1.")).arg(CertificateHelpers::resultToString(result, validity))); setLabelStatus(*ui_.lb_valid, false); } QDateTime now = QDateTime::currentDateTime(); QDateTime notBefore = cert.notValidBefore(); QDateTime notAfter = cert.notValidAfter(); ui_.lb_notBefore->setText(cert.notValidBefore().toString()); setLabelStatus(*ui_.lb_notBefore, now > notBefore); ui_.lb_notAfter->setText(cert.notValidAfter().toString()); setLabelStatus(*ui_.lb_notAfter, now < notAfter); ui_.lb_sn->setText(cert.serialNumber().toString()); QString str; str += "<table>"; str += makePropTable(tr("Subject Details:"), cert.subjectInfo()); str += makePropTable(tr("Issuer Details:"), cert.issuerInfo()); str += "</table>"; for (int i=0; i < 2; i++) { QString hashstr = QCA::Hash(i == 0 ? "md5" : "sha1").hashToString(cert.toDER()).toUpper().replace(QRegExp("(..)"), ":\\1").mid(1); str += QString("Fingerprint(%1): %2<br>").arg(i == 0 ? "MD5" : "SHA-1").arg(hashstr); } ui_.tb_cert->setText(str); } QString CertificateDisplayDialog::makePropTable(const QString &heading, const QCA::CertificateInfo &list) { QString str; str += "<tr><td><i>" + heading + "</i><br>"; str += "<table>"; str += makePropEntry(QCA::Organization, tr("Organization:"), list); str += makePropEntry(QCA::OrganizationalUnit, tr("Organizational unit:"), list); str += makePropEntry(QCA::Locality, tr("Locality:"), list); str += makePropEntry(QCA::State, tr("State:"), list); str += makePropEntry(QCA::Country, tr("Country:"), list); str += makePropEntry(QCA::CommonName, tr("Common name:"), list); str += makePropEntry(QCA::DNS, tr("Domain name:"), list); str += makePropEntry(QCA::XMPP, tr("XMPP name:"), list); str += makePropEntry(QCA::Email, tr("Email:"), list); str += "</table></td></tr>"; return str; } void CertificateDisplayDialog::setLabelStatus(QLabel& l, bool ok) { QPalette palette; palette.setColor(l.foregroundRole(), ok ? QColor("#2A993B") : QColor("#810000")); l.setPalette(palette); } QString CertificateDisplayDialog::makePropEntry(QCA::CertificateInfoType var, const QString &name, const QCA::CertificateInfo &list) { QString val; QList<QString> values = list.values(var); for (int i = 0; i < values.size(); ++i) val += values.at(i) + "<br>"; if(val.isEmpty()) return ""; else return QString("<tr><td><nobr><b>") + name + "</b></nobr></td><td>" + val + "</td></tr>"; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/unittest/�����������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�015414� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/unittest/unittest.pri�����������������������������������������������������0000644�0001750�0001750�00000000057�11305557613�020011� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SOURCES += \ $$PWD/CertificateHelpersTest.cpp ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/unittest/unittest.pro�����������������������������������������������������0000644�0001750�0001750�00000000345�11305557613�020017� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$PSI_MOCKQCA_MODULE) include(unittest.pri) QT += xml gui INCLUDEPATH += $$PWD/../.. DEPENDPATH += $$PWD/../.. SOURCES += \ ../CertificateHelpers.cpp �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/unittest/CertificateHelpersTest.cpp���������������������������������������0000644�0001750�0001750�00000000777�11305557613�022540� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * Licensed under the GNU GPL. * See COPYING for license details. */ #include <QObject> #include <QtTest/QtTest> #include "qttestutil/qttestutil.h" #include "QtCrypto" #include "Certificates/CertificateHelpers.h" using namespace QCA; class CertificateHelpersTest : public QObject { Q_OBJECT private slots: void initTestCase() { } void cleanupTestCase() { } }; QTTESTUTIL_REGISTER_TEST(CertificateHelpersTest); #include "CertificateHelpersTest.moc" �psi-0.14/src/Certificates/CertificateErrorDialog.h��������������������������������������������������0000644�0001750�0001750�00000001672�11305557613�020270� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #ifndef CERTIFICATEERRORDIALOG_H #define CERTIFICATEERRORDIALOG_H #include <QtCrypto> #include <QString> class QMessageBox; class QPushButton; class CertificateErrorDialog : public QObject { Q_OBJECT public: CertificateErrorDialog(const QString& title, const QString& host, const QCA::Certificate& cert, int result, QCA::Validity validity, const QString &domainOverride, QString &tlsOverrideDomain, QByteArray &tlsOverrideCert); ~CertificateErrorDialog(); int exec(); public slots: void reject(); private: QMessageBox* messageBox_; QPushButton* detailsButton_; QPushButton* continueButton_; QPushButton* cancelButton_; QPushButton* saveButton_; QCA::Certificate certificate_; int result_; QCA::Validity validity_; QString &tlsOverrideDomain_; QByteArray &tlsOverrideCert_; QString domainOverride_; QString host_; }; #endif ����������������������������������������������������������������������psi-0.14/src/Certificates/CertificateErrorDialog.cpp������������������������������������������������0000644�0001750�0001750�00000004650�11305557613�020622� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #include <QtDebug> #include <QFile> #include <QMessageBox> #include <QPushButton> #include "Certificates/CertificateHelpers.h" #include "Certificates/CertificateErrorDialog.h" #include "Certificates/CertificateDisplayDialog.h" CertificateErrorDialog::CertificateErrorDialog(const QString& title, const QString& host, const QCA::Certificate& cert, int result, QCA::Validity validity, const QString &domainOverride, QString &tlsOverrideDomain, QByteArray &tlsOverrideCert) : certificate_(cert), result_(result), validity_(validity), tlsOverrideDomain_(tlsOverrideDomain), tlsOverrideCert_(tlsOverrideCert), domainOverride_(domainOverride), host_(host) { messageBox_ = new QMessageBox(QMessageBox::Warning, title, QObject::tr("The %1 certificate failed the authenticity test.").arg(host)); messageBox_->setInformativeText(CertificateHelpers::resultToString(result, validity)); detailsButton_ = messageBox_->addButton(QObject::tr("&Details..."), QMessageBox::ActionRole); continueButton_ = messageBox_->addButton(QObject::tr("&Connect anyway"), QMessageBox::AcceptRole); if (domainOverride.isEmpty()) { saveButton_ = messageBox_->addButton(QObject::tr("&Trust this certificate"), QMessageBox::AcceptRole); } else { saveButton_ = messageBox_->addButton(QObject::tr("&Trust this domain"), QMessageBox::AcceptRole); } cancelButton_ = messageBox_->addButton(QMessageBox::Cancel); messageBox_->setDefaultButton(detailsButton_); } CertificateErrorDialog::~CertificateErrorDialog() { delete messageBox_; } int CertificateErrorDialog::exec() { while (true) { messageBox_->exec(); if (messageBox_->clickedButton() == detailsButton_) { messageBox_->setResult(QDialog::Accepted); CertificateDisplayDialog dlg(certificate_, result_, validity_); dlg.exec(); } else if (messageBox_->clickedButton() == continueButton_) { messageBox_->setResult(QDialog::Accepted); break; } else if (messageBox_->clickedButton() == cancelButton_) { messageBox_->setResult(QDialog::Rejected); break; } else if (messageBox_->clickedButton() == saveButton_) { messageBox_->setResult(QDialog::Accepted); if (domainOverride_.isEmpty()) { tlsOverrideCert_ = certificate_.toDER(); } else { tlsOverrideDomain_ = domainOverride_; } break; } } return messageBox_->result(); } void CertificateErrorDialog::reject() { messageBox_->reject(); } ����������������������������������������������������������������������������������������psi-0.14/src/Certificates/CertificateDisplayDialog.h������������������������������������������������0000644�0001750�0001750�00000002545�11305557613�020604� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CERTIFICATEDISPLAYDIALOG_H #define CERTIFICATEDISPLAYDIALOG_H #include <QtCrypto> #include "ui_CertificateDisplay.h" class CertificateDisplayDialog : public QDialog { Q_OBJECT public: CertificateDisplayDialog(const QCA::Certificate &, int result, QCA::Validity, QWidget *parent=0); protected: static void setLabelStatus(QLabel& l, bool ok); static QString makePropEntry(QCA::CertificateInfoType var, const QString &name, const QCA::CertificateInfo &list); QString makePropTable(const QString &heading, const QCA::CertificateInfo &props); private: Ui::CertificateDisplay ui_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/CertificateHelpers.h������������������������������������������������������0000644�0001750�0001750�00000001326�11305557613�017455� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * Licensed under the GNU GPL license. * See COPYING for details. */ #ifndef CERTUTIL_H #define CERTUTIL_H #include <QtCrypto> class QString; namespace QCA { class CertificateCollection; } namespace XMPP { class QCATLSHandler; } class CertificateHelpers { public: static QCA::CertificateCollection allCertificates(const QStringList& dirs); static QString resultToString(int result, QCA::Validity); static bool checkCertificate(QCA::TLS* tls, XMPP::QCATLSHandler *tlsHandler, QString &tlsOverrideDomain, QByteArray &tlsOverrideCert, QObject * canceler, const QString &title, const QString &host); protected: static QString validityToString(QCA::Validity); }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/CertificateDisplay.ui�����������������������������������������������������0000644�0001750�0001750�00000010643�11305557613�017650� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <class>CertificateDisplay</class> <widget class="QDialog" name="CertificateDisplay" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>518</width> <height>369</height> </rect> </property> <property name="windowTitle" > <string>Certificate Information</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>11</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="textLabel4" > <property name="text" > <string>Certificate Validation:</string> </property> </widget> </item> <item> <widget class="QLabel" name="lb_valid" > <property name="text" > <string/> </property> </widget> </item> <item> <widget class="QLabel" name="textLabel2" > <property name="text" > <string>Valid From:</string> </property> </widget> </item> <item> <widget class="QLabel" name="lb_notBefore" > <property name="text" > <string/> </property> </widget> </item> <item> <widget class="QLabel" name="textLabel3" > <property name="text" > <string>Valid Until:</string> </property> </widget> </item> <item> <widget class="QLabel" name="lb_notAfter" > <property name="text" > <string/> </property> </widget> </item> <item> <widget class="QLabel" name="textLabel1" > <property name="text" > <string>Serial Number:</string> </property> </widget> </item> <item> <widget class="QLabel" name="lb_sn" > <property name="text" > <string/> </property> </widget> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>20</width> <height>106</height> </size> </property> </spacer> </item> </layout> </item> <item> <widget class="QTextBrowser" name="tb_cert" > <property name="minimumSize" > <size> <width>350</width> <height>300</height> </size> </property> <property name="horizontalScrollBarPolicy" > <enum>Qt::ScrollBarAlwaysOff</enum> </property> </widget> </item> </layout> </item> <item> <widget class="Line" name="line1" > <property name="frameShape" > <enum>QFrame::HLine</enum> </property> <property name="frameShadow" > <enum>QFrame::Sunken</enum> </property> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>421</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" native="1" name="pb_close"> <property name="text"> <string>Close</string> </property> </widget> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11" /> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <tabstops> <tabstop>tb_cert</tabstop> </tabstops> <resources/> <connections/> </ui> ���������������������������������������������������������������������������������������������psi-0.14/src/Certificates/guitest/������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�015221� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/guitest/cert.pem����������������������������������������������������������0000644�0001750�0001750�00000001264�11305557613�016664� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIIB0zCCATygAwIBAgIICDX58jQ8OrAwDQYJKoZIhvcNAQEEBQAwFjEUMBIGA1UE AwwLZWwtdHJhbW8uYmUwHhcNMDgwNDA5MTY0MjA1WhcNMTMwMzE0MTY0MjA1WjAW MRQwEgYDVQQDDAtlbC10cmFtby5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC gYEAgmBnqeqpqFGjQw0jVDDSa0kr0TcGZC6FlPdjW6uVw0vheHGhc4VIREn22nxF X8aa7p9fbgOpu0REp6dGaApw8Uj3O3jTkNhA9NrQV910qegVds8Ur4IOGrqWDtUb dWTRABodNw2J7Ed+IO0+ck6MG83LtuCSfq4VjIFg3/OBHxECAwEAAaMqMCgwJgYD VR0RBB8wHaAbBggrBgEFBQcIBaAPDA0qLmVsLXRyYW1vLmJlMA0GCSqGSIb3DQEB BAUAA4GBACSLsmW/FSQCdTPMHV7pML3cc9B1UK69LISvyerDRfWLwBFJjh4PKZxu EtiZ8n4NvJmJTbFEAxiYl3cXwmeTO0ERRcrEiKUerJYWDpcM1EPurBBkNsAck9QP SJOreAAYkHQox3I4sHNR6tyCRhAmYlb2ECZYmgJAQK733ljfd38a -----END CERTIFICATE----- ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/guitest/guitest.qrc�������������������������������������������������������0000644�0001750�0001750�00000000136�11305557613�017414� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE RCC> <RCC version="1.0"> <qresource> <file>cert.pem</file> </qresource> </RCC> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/guitest/guitest.pro�������������������������������������������������������0000644�0001750�0001750�00000000321�11305557613�017423� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������QT += xml include(../../../conf.pri) include(../Certificates.pri) qca-static { include(../../../third-party/qca/qca.pri) } else { CONFIG += crypto } SOURCES += \ $$PWD/main.cpp RESOURCES += guitest.qrc ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/Certificates/guitest/main.cpp����������������������������������������������������������0000644�0001750�0001750�00000000507�11305557613�016653� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QApplication> #include "Certificates/CertificateErrorDialog.h" int main(int argc, char* argv[]) { QApplication app(argc, argv); QCA::Certificate cert; CertificateErrorDialog dlg("Certificate error", "untrusted-host.com", cert, QCA::TLS::HostMismatch, QCA::ErrorRejected, "."); dlg.exec(); return app.exec(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/chatdlg.h������������������������������������������������������������������������������0000644�0001750�0001750�00000012054�11305557613�012711� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * chatdlg.h - dialog for handling chats * Copyright (C) 2001-2007 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CHATDLG_H #define CHATDLG_H #include <QContextMenuEvent> #include <QDragEnterEvent> #include <QShowEvent> #include <QKeyEvent> #include <QResizeEvent> #include <QDropEvent> #include <QCloseEvent> #include "advwidget.h" #include "tabbablewidget.h" namespace XMPP { class Jid; class Message; } using namespace XMPP; class PsiAccount; class UserListItem; class QDropEvent; class QDragEnterEvent; class ChatView; class ChatEdit; class ChatDlg : public TabbableWidget { Q_OBJECT protected: ChatDlg(const Jid& jid, PsiAccount* account, TabManager* tabManager); virtual void init(); public: static ChatDlg* create(const Jid& jid, PsiAccount* account, TabManager* tabManager); ~ChatDlg(); // reimplemented void setJid(const Jid &); const QString & getDisplayName(); static QSize defaultSize(); // reimplemented virtual bool readyToHide(); virtual TabbableWidget::State state() const; virtual int unreadMessageCount() const; virtual QString desiredCaption() const; virtual void ensureTabbedCorrectly(); public: PsiAccount* account() const; signals: void aInfo(const Jid &); void aHistory(const Jid &); void aVoice(const Jid &); void messagesRead(const Jid &); void aSend(const Message &); void aFile(const Jid &); /** * Signals if user (re)started/stopped composing */ void composing(bool); protected: virtual void setShortcuts(); // reimplemented void closeEvent(QCloseEvent *); void resizeEvent(QResizeEvent *); void hideEvent(QHideEvent *); void showEvent(QShowEvent *); void dropEvent(QDropEvent* event); void dragEnterEvent(QDragEnterEvent* event); bool eventFilter(QObject *obj, QEvent *event); public slots: // reimplemented virtual void deactivated(); virtual void activated(); virtual void optionsUpdate(); void updateContact(const Jid &, bool); void incomingMessage(const Message &); virtual void updateAvatar() = 0; void updateAvatar(const Jid&); protected slots: void scrollUp(); void scrollDown(); void doInfo(); virtual void doHistory(); virtual void doClear(); virtual void doSend(); void doVoice(); void doFile(); private slots: void setKeepOpenFalse(); void setWarnSendFalse(); virtual void updatePGP(); virtual void setPGPEnabled(bool enabled); void encryptedMessageSent(int, bool, int, const QString &); void slotScroll(); void setChatState(XMPP::ChatState s); void updateIsComposing(bool); void setContactChatState(ChatState s); void logSelectionChanged(); void capsChanged(const Jid&); void addEmoticon(QString text); void initComposing(); void setComposing(); protected slots: void checkComposing(); protected: // reimplemented virtual void invalidateTab(); void resetComposing(); void doneSend(); virtual void setLooks(); void setSelfDestruct(int); void deferredScroll(); bool isEmoteMessage(const XMPP::Message& m); QString messageText(const XMPP::Message& m); virtual void chatEditCreated(); enum SpooledType { Spooled_None, Spooled_OfflineStorage }; virtual void initUi() = 0; virtual void capsChanged(); virtual void contactUpdated(UserListItem* u, int status, const QString& statusString); virtual QString colorString(bool local, SpooledType spooled) const = 0; void appendMessage(const Message &, bool local = false); virtual bool isEncryptionEnabled() const; virtual void appendSysMsg(const QString& txt) = 0; virtual void appendEmoteMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt) = 0; virtual void appendNormalMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt) = 0; virtual void appendMessageFields(const Message& m) = 0; virtual void nicksChanged(); QString whoNick(bool local) const; virtual ChatView* chatView() const = 0; virtual ChatEdit* chatEdit() const = 0; private: bool highlightersInstalled_; QString dispNick_; int status_; QString statusString_; void initActions(); QAction* act_send_; QAction* act_scrollup_; QAction* act_scrolldown_; QAction* act_close_; int pending_; bool keepOpen_; bool warnSend_; QTimer* selfDestruct_; QString key_; int transid_; Message m_; bool lastWasEncrypted_; // Message Events & Chat States QTimer* composingTimer_; bool isComposing_; bool sendComposingEvents_; QString eventId_; ChatState contactChatState_; ChatState lastChatState_; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/MockQCA/�������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�012346� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/MockQCA/QtCrypto�����������������������������������������������������������������������0000644�0001750�0001750�00000000026�11305557613�014054� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "QtCrypto.h" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/MockQCA/MockQCA.cpp��������������������������������������������������������������������0000644�0001750�0001750�00000000217�11305557613�014270� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "QtCrypto.h" namespace QCA { CertificateCollection gSystemStore; CertificateCollection systemStore() { return gSystemStore; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/MockQCA/MockQCA.pri��������������������������������������������������������������������0000644�0001750�0001750�00000000104�11305557613�014273� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INCLUDEPATH *= $$PWD DEPENDPATH *= $$PWD SOURCES += \ MockQCA.cpp ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/MockQCA/QtCrypto.h���������������������������������������������������������������������0000644�0001750�0001750�00000003122�11305557613�014302� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef MOCKQCA_QTCRYPTO #define MOCKQCA_QTCRYPTO #include <QList> #include <QByteArray> #include <QString> namespace QCA { enum Validity { ValidityGood, ErrorRejected, ErrorUntrusted, ErrorSignatureFailed, ErrorInvalidCA, ErrorInvalidPurpose, ErrorSelfSigned, ErrorRevoked, ErrorPathLengthExceeded, ErrorExpired, ErrorExpiredCA, ErrorValidityUnknown = 64 }; enum ConvertResult { ConvertGood }; class Certificate { public: Certificate(const QString& id = "") { id_ = id; } bool operator==(const Certificate& other) { return other.id_ == id_; } static Certificate fromPEMFile(const QString&, ConvertResult* result) { *result = ConvertGood; return Certificate(); } static Certificate fromDER(const QString&, ConvertResult* result) { *result = ConvertGood; return Certificate(); } private: QString id_; }; class CertificateCollection : public QList<Certificate> { public: CertificateCollection() {} void addCertificate(const Certificate& c) { *this += c; } QList<Certificate> certificates() const { return *this; } }; class SecureArray { public: SecureArray() {} QByteArray toByteArray() { return QByteArray(); } }; class Base64 { public: Base64() {} SecureArray stringToArray(const QString&) { return SecureArray(); } }; class TLS { public: enum Result { NoCertificate, Valid, HostMismatch, InvalidCertificate }; }; extern CertificateCollection gSystemStore; CertificateCollection systemStore(); } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pixmaputil.cpp�������������������������������������������������������������������������0000644�0001750�0001750�00000000757�11305557613�014041� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "pixmaputil.h" #include <QBitmap> #include <QImage> QPixmap PixmapUtil::createTransparentPixmap(int width, int height) { // Now there's third alternative: // QPainter p(&pixmap); // p.fillRect(pixmap.rect(), Qt::transparent); #if 1 QPixmap pix(width, height); QBitmap mask(width, height); pix.fill(); mask.clear(); pix.setMask(mask); #else QImage img(width, height, QImage::Format_ARGB32); img.fill(0x00000000); QPixmap pix = QPixmap::fromImage(img); #endif return pix; } �����������������psi-0.14/src/psiactionlist.h������������������������������������������������������������������������0000644�0001750�0001750�00000002366�11305557613�014175� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psiactionlist.h - the customizeable action list for Psi * Copyright (C) 2004 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIACTIONLIST_H #define PSIACTIONLIST_H #include "actionlist.h" class PsiCon; class PsiActionList : public MetaActionList { public: PsiActionList(PsiCon *psi); ~PsiActionList(); enum ActionsType { Actions_Common = (1 << 0), Actions_MainWin = (1 << 1), // Actions_Message = (1 << 2), // Actions_Chat = (1 << 3), // Actions_Groupchat = (1 << 4) }; public: class Private; private: Private *d; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/vcardfactory.cpp�����������������������������������������������������������������������0000644�0001750�0001750�00000011200�11305557613�014315� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * vcardfactory.cpp - class for caching vCards * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QObject> #include <QApplication> #include <QMap> #include <QDomDocument> #include <QFile> #include <QTextStream> #include <QDir> #include "profiles.h" #include "applicationinfo.h" #include "vcardfactory.h" #include "jidutil.h" #include "psiaccount.h" #include "xmpp_vcard.h" #include "xmpp_tasks.h" /** * \brief Factory for retrieving and changing VCards. */ VCardFactory::VCardFactory() : QObject(qApp), dictSize_(5) { } /** * \brief Destroys all cached VCards. */ VCardFactory::~VCardFactory() { foreach (VCard *vcard, vcardDict_) delete vcard; } /** * \brief Returns the VCardFactory instance. */ VCardFactory* VCardFactory::instance() { if (!instance_) { instance_ = new VCardFactory(); } return instance_; } /** * Adds a vcard to the cache (and removes other items if necessary) */ void VCardFactory::checkLimit(QString jid, VCard *vcard) { if (vcardList_.contains(jid)) { vcardList_.removeAll(jid); delete vcardDict_.take(jid); } else if (vcardList_.size() > dictSize_) { QString j = vcardList_.takeLast(); delete vcardDict_.take(j); } vcardDict_[jid] = vcard; vcardList_.push_front(jid); } void VCardFactory::taskFinished() { JT_VCard *task = (JT_VCard *)sender(); if ( task->success() ) { Jid j = task->jid(); saveVCard(j, task->vcard()); } } void VCardFactory::saveVCard(const Jid& j, const VCard& _vcard) { VCard *vcard = new VCard; *vcard = _vcard; checkLimit(j.bare(), vcard); // save vCard to disk // ensure that there's a vcard directory to save into QDir p(pathToProfile(activeProfile)); QDir v(pathToProfile(activeProfile) + "/vcard"); if(!v.exists()) p.mkdir("vcard"); QFile file ( ApplicationInfo::vCardDir() + '/' + JIDUtil::encode(j.bare()).toLower() + ".xml" ); file.open ( QIODevice::WriteOnly ); QTextStream out ( &file ); out.setCodec("UTF-8"); QDomDocument doc; doc.appendChild( vcard->toXml ( &doc ) ); out << doc.toString(4); Jid jid = j; emit vcardChanged(jid); } /** * \brief Call this, when you need a cached vCard. */ const VCard* VCardFactory::vcard(const Jid &j) { // first, try to get vCard from runtime cache if (vcardDict_.contains(j.bare())) { return vcardDict_[j.bare()]; } // then try to load from cache on disk QFile file ( ApplicationInfo::vCardDir() + '/' + JIDUtil::encode(j.bare()).toLower() + ".xml" ); file.open (QIODevice::ReadOnly); QDomDocument doc; VCard *vcard = new VCard; if ( doc.setContent(&file, false) ) { vcard->fromXml( doc.documentElement() ); checkLimit(j.bare(), vcard); return vcard; } delete vcard; return 0; } /** * \brief Call this when you need to update vCard in cache. */ void VCardFactory::setVCard(const Jid &j, const VCard &v) { saveVCard(j, v); } /** * \brief Updates vCard on specified \a account. */ void VCardFactory::setVCard(const PsiAccount* account, const VCard &v, QObject* obj, const char* slot) { JT_VCard* jtVCard_ = new JT_VCard(account->client()->rootTask()); if (obj) connect(jtVCard_, SIGNAL(finished()), obj, slot); connect(jtVCard_, SIGNAL(finished()), SLOT(updateVCardFinished())); jtVCard_->set(account->jid(), v); jtVCard_->go(true); } void VCardFactory::updateVCardFinished() { JT_VCard* jtVCard = static_cast<JT_VCard*> (sender()); if (jtVCard && jtVCard->success()) { setVCard(jtVCard->jid(), jtVCard->vcard()); } if (jtVCard) { jtVCard->deleteLater(); } } /** * \brief Call this when you need to retrieve fresh vCard from server (and store it in cache afterwards) */ JT_VCard* VCardFactory::getVCard(const Jid &jid, Task *rootTask, const QObject *obj, const char *slot, bool cacheVCard) { JT_VCard *task = new JT_VCard( rootTask ); if ( cacheVCard ) task->connect(task, SIGNAL(finished()), this, SLOT(taskFinished())); task->connect(task, SIGNAL(finished()), obj, slot); task->get(Jid(jid.full())); task->go(true); return task; } VCardFactory* VCardFactory::instance_ = NULL; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/mucaffiliationsmodel.h�����������������������������������������������������������������0000644�0001750�0001750�00000004064�11305557613�015503� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * mucaffiliationsmodel.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MUCAFFILIATIONSMODEL_H #define MUCAFFILIATIONSMODEL_H #include <QStandardItemModel> #include <QList> #include <QMap> #include "xmpp_muc.h" class QMimeData; class MUCAffiliationsModel : public QStandardItemModel { Q_OBJECT public: MUCAffiliationsModel(); virtual Qt::ItemFlags flags(const QModelIndex &index) const; virtual Qt::DropActions supportedDropActions() const; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); QStringList mimeTypes () const; QMimeData* mimeData(const QModelIndexList &indexes) const; void resetAffiliationLists(); void setAffiliationListEnabled(XMPP::MUCItem::Affiliation, bool = true); QModelIndex affiliationListIndex(XMPP::MUCItem::Affiliation); void addItems(const QList<XMPP::MUCItem>&); QList<XMPP::MUCItem> changes() const; protected: enum AffiliationListIndex { Owners = 0, Admins = 1, Members = 2, Outcast = 3 , Unknown = 4 }; void resetAffiliationList(XMPP::MUCItem::Affiliation); static QString affiliationlistindexToString(AffiliationListIndex); AffiliationListIndex affiliationToIndex(XMPP::MUCItem::Affiliation); static XMPP::MUCItem::Affiliation indexToAffiliation(int); private: QList<XMPP::MUCItem> items_; QMap<AffiliationListIndex,bool> enabled_; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psigrowlnotifier.h���������������������������������������������������������������������0000644�0001750�0001750�00000003743�11305557613�014716� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psigrowlnotifier.h: Psi's interface to Growl * Copyright (C) 2005 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIGROWLNOTIFIER_H #define PSIGROWLNOTIFIER_H #include <QObject> #include "psipopup.h" class GrowlNotifier; class PsiAccount; class NotificationContext; /** * An interface for Psi to Growl. * This class uses GrowlNotifier to interface with Growl. * There is at most 1 PsiGrowlNotifier per Psi session (Singleton). This * notifier can be retrieved using instance(). * * \see GrowlNotifier */ class PsiGrowlNotifier : public QObject { Q_OBJECT public: static PsiGrowlNotifier* instance(); void popup(PsiAccount* account, PsiPopup::PopupType type, const Jid& j, const Resource& r, const UserListItem* = 0, PsiEvent* = 0); public slots: void notificationClicked(void*); void notificationTimedOut(void*); private slots: void cleanup(); private: PsiGrowlNotifier(); void tryDeleteContext(NotificationContext* context); static PsiGrowlNotifier* instance_; GrowlNotifier* gn_; QList<NotificationContext*> contexts_; }; #endif �����������������������������psi-0.14/src/msgmle.cpp�����������������������������������������������������������������������������0000644�0001750�0001750�00000030433�11305557613�013123� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * msgmle.cpp - subclass of PsiTextView to handle various hotkeys * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "msgmle.h" #include <QAbstractTextDocumentLayout> #include <QAction> #include <QApplication> #include <QDesktopWidget> #include <QEvent> #include <QKeyEvent> #include <QLayout> #include <QMenu> #include <QResizeEvent> #include <QScrollBar> #include <QTextCharFormat> #include <QTextDocument> #include <QTimer> #include <QDateTime> #include "shortcutmanager.h" #include "spellhighlighter.h" #include "spellchecker.h" #include "psioptions.h" //---------------------------------------------------------------------------- // ChatView //---------------------------------------------------------------------------- ChatView::ChatView(QWidget *parent) : PsiTextView(parent) , dialog_(0) { setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); setReadOnly(true); setUndoRedoEnabled(false); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); #ifndef Q_WS_X11 // linux has this feature built-in connect(this, SIGNAL(selectionChanged()), SLOT(autoCopy())); connect(this, SIGNAL(cursorPositionChanged()), SLOT(autoCopy())); #endif } ChatView::~ChatView() { } void ChatView::setDialog(QWidget* dialog) { dialog_ = dialog; } QSize ChatView::sizeHint() const { return minimumSizeHint(); } bool ChatView::focusNextPrevChild(bool next) { return QWidget::focusNextPrevChild(next); } void ChatView::keyPressEvent(QKeyEvent *e) { /* if(e->key() == Qt::Key_Escape) e->ignore(); #ifdef Q_WS_MAC else if(e->key() == Qt::Key_W && e->modifiers() & Qt::ControlModifier) e->ignore(); else #endif else if(e->key() == Qt::Key_Return && ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::AltModifier)) ) e->ignore(); else if(e->key() == Qt::Key_H && (e->modifiers() & Qt::ControlModifier)) e->ignore(); else if(e->key() == Qt::Key_I && (e->modifiers() & Qt::ControlModifier)) e->ignore(); */ /*else*/ if(e->key() == Qt::Key_M && (e->modifiers() & Qt::ControlModifier) && !isReadOnly()) // newline append("\n"); /* else if(e->key() == Qt::Key_U && (e->modifiers() & Qt::ControlModifier) && !isReadOnly()) setText(""); */ else if ((e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) && ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::AltModifier))) { e->ignore(); } else { PsiTextView::keyPressEvent(e); } } /** * Copies any selected text to the clipboard * if autoCopy is enabled and ChatView is in read-only mode. */ void ChatView::autoCopy() { if (isReadOnly() && PsiOptions::instance()->getOption("options.ui.automatically-copy-selected-text").toBool()) { copy(); } } /** * Handle KeyPress events that happen in ChatEdit widget. This is used * to 'fix' the copy shortcut. * \param object object that should receive the event * \param event received event * \param chatEdit pointer to the dialog's ChatEdit widget that receives user input */ bool ChatView::handleCopyEvent(QObject *object, QEvent *event, ChatEdit *chatEdit) { if (object == chatEdit && event->type() == QEvent::KeyPress) { QKeyEvent *e = (QKeyEvent *)event; if ((e->key() == Qt::Key_C && (e->modifiers() & Qt::ControlModifier)) || (e->key() == Qt::Key_Insert && (e->modifiers() & Qt::ControlModifier))) { if (!chatEdit->textCursor().hasSelection() && this->textCursor().hasSelection()) { this->copy(); return true; } } } return false; } void ChatView::appendText(const QString &text) { bool doScrollToBottom = atBottom(); // prevent scrolling back to selected text when // restoring selection int scrollbarValue = verticalScrollBar()->value(); PsiTextView::appendText(text); if (doScrollToBottom) scrollToBottom(); else verticalScrollBar()->setValue(scrollbarValue); } /** * \brief Common function for ChatDlg and GCMainDlg. FIXME: Extract common * chat window from both dialogs and move this function to that class. */ QString ChatView::formatTimeStamp(const QDateTime &time) { // TODO: provide an option for user to customize // time stamp format return QString().sprintf("%02d:%02d:%02d", time.time().hour(), time.time().minute(), time.time().second());; } //---------------------------------------------------------------------------- // ChatEdit //---------------------------------------------------------------------------- ChatEdit::ChatEdit(QWidget *parent) : QTextEdit(parent) , dialog_(0) , check_spelling_(false) , spellhighlighter_(0) { setWordWrapMode(QTextOption::WordWrap); setAcceptRichText(false); setReadOnly(false); setUndoRedoEnabled(true); setMinimumHeight(48); previous_position_ = 0; setCheckSpelling(checkSpellingGloballyEnabled()); connect(PsiOptions::instance(),SIGNAL(optionChanged(const QString&)),SLOT(optionsChanged())); } ChatEdit::~ChatEdit() { delete spellhighlighter_; } void ChatEdit::setDialog(QWidget* dialog) { dialog_ = dialog; } QSize ChatEdit::sizeHint() const { return minimumSizeHint(); } bool ChatEdit::checkSpellingGloballyEnabled() { return (SpellChecker::instance()->available() && PsiOptions::instance()->getOption("options.ui.spell-check.enabled").toBool()); } void ChatEdit::setCheckSpelling(bool b) { check_spelling_ = b; if (check_spelling_) { if (!spellhighlighter_) spellhighlighter_ = new SpellHighlighter(document()); } else { delete spellhighlighter_; spellhighlighter_ = 0; } } bool ChatEdit::focusNextPrevChild(bool next) { return QWidget::focusNextPrevChild(next); } // Qt text controls are quite greedy to grab key events. // disable that. bool ChatEdit::event(QEvent * event) { if (event->type() == QEvent::ShortcutOverride) { return false; } return QTextEdit::event(event); } void ChatEdit::keyPressEvent(QKeyEvent *e) { /* if(e->key() == Qt::Key_Escape || (e->key() == Qt::Key_W && e->modifiers() & Qt::ControlModifier)) e->ignore(); else if(e->key() == Qt::Key_Return && ((e->modifiers() & Qt::ControlModifier) #ifndef Q_WS_MAC || (e->modifiers() & Qt::AltModifier) #endif )) e->ignore(); else if(e->key() == Qt::Key_M && (e->modifiers() & Qt::ControlModifier)) // newline insert("\n"); else if(e->key() == Qt::Key_H && (e->modifiers() & Qt::ControlModifier)) // history e->ignore(); else if(e->key() == Qt::Key_S && (e->modifiers() & Qt::AltModifier)) e->ignore(); else*/ if(e->key() == Qt::Key_U && (e->modifiers() & Qt::ControlModifier)) setText(""); /* else if((e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) && !((e->modifiers() & Qt::ShiftModifier) || (e->modifiers() & Qt::AltModifier)) && LEGOPTS.chatSoftReturn) e->ignore(); else if((e->key() == Qt::Key_PageUp || e->key() == Qt::Key_PageDown) && (e->modifiers() & Qt::ShiftModifier)) e->ignore(); else if((e->key() == Qt::Key_PageUp || e->key() == Qt::Key_PageDown) && (e->modifiers() & Qt::ControlModifier)) e->ignore(); */ #ifdef Q_WS_MAC else if (e->key() == Qt::Key_QuoteLeft && e->modifiers() == Qt::ControlModifier) { e->ignore(); } #endif else { QTextEdit::keyPressEvent(e); } } /** * Work around Qt bug, that QTextEdit doesn't accept() the * event, so it could result in another context menu popping * out after the first one. */ void ChatEdit::contextMenuEvent(QContextMenuEvent *e) { last_click_ = e->pos(); if (check_spelling_ && textCursor().selectedText().isEmpty() && SpellChecker::instance()->available()) { // Check if the word under the cursor is misspelled QTextCursor tc = cursorForPosition(last_click_); tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); QString selected_word = tc.selectedText(); if (!selected_word.isEmpty() && !SpellChecker::instance()->isCorrect(selected_word)) { QList<QString> suggestions = SpellChecker::instance()->suggestions(selected_word); if (!suggestions.isEmpty() || SpellChecker::instance()->writable()) { QMenu spell_menu; if (!suggestions.isEmpty()) { foreach(QString suggestion, suggestions) { QAction* act_suggestion = spell_menu.addAction(suggestion); connect(act_suggestion,SIGNAL(triggered()),SLOT(applySuggestion())); } spell_menu.addSeparator(); } if (SpellChecker::instance()->writable()) { QAction* act_add = spell_menu.addAction(tr("Add to dictionary")); connect(act_add,SIGNAL(triggered()),SLOT(addToDictionary())); } spell_menu.exec(QCursor::pos()); e->accept(); return; } } } // Do normal menu QTextEdit::contextMenuEvent(e); e->accept(); } /*! * \brief handles a click on a suggestion * \param the action is just the container which holds the suggestion. * * This method is called by the framework whenever a user clicked on the child popupmenu * to select a suggestion for a missspelled word. It exchanges the missspelled word with the * suggestion which is the text of the QAction parameter. */ void ChatEdit::applySuggestion() { QAction* act_suggestion = (QAction*) sender(); int current_position = textCursor().position(); // Replace the word QTextCursor tc = cursorForPosition(last_click_); tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); int old_length = tc.position() - tc.anchor(); tc.insertText(act_suggestion->text()); tc.clearSelection(); // Put the cursor where it belongs int new_length = act_suggestion->text().length(); tc.setPosition(current_position - old_length + new_length); setTextCursor(tc); } /*! * \brief handles a click on the add2dict action of the parent popupmenu * \param Never used bool parameter * * The method sets the cursor to the last mouseclick position and looks for the word which is placed there. * This word is than added to the dictionary of aspell. */ void ChatEdit::addToDictionary() { QTextCursor tc = cursorForPosition(last_click_); int current_position = textCursor().position(); // Get the selected word tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); SpellChecker::instance()->add(tc.selectedText()); // Put the cursor where it belongs tc.clearSelection(); tc.setPosition(current_position); setTextCursor(tc); } void ChatEdit::optionsChanged() { setCheckSpelling(checkSpellingGloballyEnabled()); } //---------------------------------------------------------------------------- // LineEdit //---------------------------------------------------------------------------- LineEdit::LineEdit( QWidget *parent) : ChatEdit(parent) { setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); // no need for horizontal scrollbar with this setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setMinimumHeight(0); connect(this, SIGNAL(textChanged()), SLOT(recalculateSize())); } LineEdit::~LineEdit() { } QSize LineEdit::minimumSizeHint() const { QSize sh = QTextEdit::minimumSizeHint(); sh.setHeight(fontMetrics().height() + 1); sh += QSize(0, QFrame::lineWidth() * 2); return sh; } QSize LineEdit::sizeHint() const { QSize sh = QTextEdit::sizeHint(); sh.setHeight(int(document()->documentLayout()->documentSize().height())); sh += QSize(0, QFrame::lineWidth() * 2); ((QTextEdit*)this)->setMaximumHeight(sh.height()); return sh; } void LineEdit::resizeEvent(QResizeEvent* e) { ChatEdit::resizeEvent(e); QTimer::singleShot(0, this, SLOT(updateScrollBar())); } void LineEdit::recalculateSize() { updateGeometry(); QTimer::singleShot(0, this, SLOT(updateScrollBar())); } void LineEdit::updateScrollBar() { setVerticalScrollBarPolicy(sizeHint().height() > height() ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); ensureCursorVisible(); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/�����������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�011727� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxenewedit.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000011277�11305557613�014622� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxenewedit.cpp - An single SXE edit that creates a new node * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxenewedit.h" #include "sxesession.h" //---------------------------------------------------------------------------- // SxeNewEdit //---------------------------------------------------------------------------- SxeNewEdit::SxeNewEdit(const QString rid, const QDomNode &node, const QString parent, double primaryWeight, bool remote) : SxeEdit(rid, remote) { parent_ = parent; primaryWeight_ = primaryWeight; switch(node.nodeType()) { case QDomNode::ElementNode: type_ = "element"; identifier_ = node.nodeName(); ns_ = node.namespaceURI(); break; case QDomNode::AttributeNode: type_ = "attr"; identifier_ = node.nodeName(); data_ = node.nodeValue(); ns_ = node.namespaceURI(); break; case QDomNode::TextNode: type_ = "text"; data_ = node.toText().data(); break; case QDomNode::ProcessingInstructionNode: type_ = "processinginstruction"; identifier_ = node.toProcessingInstruction().target(); data_ = node.toProcessingInstruction().data(); break; case QDomNode::CommentNode: type_ = "comment"; data_ = node.toComment().data(); break; // case QDomNode::DocumentTypeNode: // type_ = "documenttype"; // // break; default: qDebug() << QString("unknown QDomNode::NodeType encountered in SxeNewEdit::SxeNewEdit(). nodeType: %1.").arg(node.nodeType()).toAscii(); break; } } SxeNewEdit::SxeNewEdit(const QDomElement &sxeElement, bool remote) : SxeEdit(sxeElement.attribute("rid"), remote) { type_ = sxeElement.attribute("type"); parent_ = sxeElement.attribute("parent"); primaryWeight_ = sxeElement.attribute("primary-weight").toDouble(); if(type_ == "processinginstruction") { identifier_ = sxeElement.attribute("pitarget"); data_ = sxeElement.attribute("pidata"); } else { identifier_ = sxeElement.attribute("name"); ns_ = sxeElement.attribute("ns"); data_ = sxeElement.attribute("chdata"); } } SxeEdit::EditType SxeNewEdit::type() const { return SxeEdit::New; }; QDomElement SxeNewEdit::xml(QDomDocument &doc) const { QDomElement edit = doc.createElementNS(SXENS, "new"); edit.setAttribute("rid", rid_); edit.setAttribute("type", type_); edit.setAttribute("parent", parent_); edit.setAttribute("primary-weight", primaryWeight_); if(type_ == "element" || type_ == "attr") { edit.setAttribute("name", identifier_); if(!ns_.isEmpty()) edit.setAttribute("ns", ns_); } if(type_ == "text" || type_ == "attr" || type_ == "comment") edit.setAttribute("chdata", data_); if(type_ == "processinginstruction") { edit.setAttribute("pitarget", identifier_); edit.setAttribute("pidata", data_); } return edit; } QDomNode::NodeType SxeNewEdit::nodeType() const { if(type_ == "element") return QDomNode::ElementNode; else if(type_ == "attr") return QDomNode::AttributeNode; else if(type_ == "text") return QDomNode::TextNode; else if(type_ == "comment") return QDomNode::CommentNode; else if(type_ == "processinginstruction") return QDomNode::ProcessingInstructionNode; else return QDomNode::BaseNode; } QString SxeNewEdit::parent() const { return parent_; } double SxeNewEdit::primaryWeight() const { return primaryWeight_; } QString SxeNewEdit::name() const { return identifier_; } QString SxeNewEdit::nameSpace() const { return ns_; } QString SxeNewEdit::chdata() const { return data_; } QString SxeNewEdit::processingInstructionTarget() const { return identifier_; } QString SxeNewEdit::processingInstructionData() const { return data_; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxemanager.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000070703�11305557613�014574� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxemanager.cpp - Whiteboard manager * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxemanager.h" #include "psipopup.h" #include "psioptions.h" #include "common.h" #include "capsmanager.h" #include <QUrl> #define ONETOONEPREFIXSELF "0" #define ONETOONEPREFIXOTHER "1" using namespace XMPP; //---------------------------------------------------------------------------- // SxeManager //---------------------------------------------------------------------------- SxeManager::SxeManager(Client* client, PsiAccount* pa) : client_(client) { sxeId_ = QTime::currentTime().toString("z").toInt(); pa_ = pa; client_->addExtension("sxe", Features(SXENS)); connect(client_, SIGNAL(messageReceived(const Message &)), SLOT(messageReceived(const Message &))); connect(client_, SIGNAL(groupChatLeft(const Jid &)), SLOT(groupChatLeft(const Jid &))); // connect(client_, SIGNAL(groupChatJoined(const Jid &, const Jid &)), SLOT(groupChatJoined(const Jid &, const Jid &))); negotiationTimer_.setSingleShot(true); negotiationTimer_.setInterval(120000); connect(&negotiationTimer_, SIGNAL(timeout()), SLOT(negotiationTimeout())); } void SxeManager::addInvitationCallback(bool (*callback)(const Jid &peer, const QList<QString> &features)) { invitationCallbacks_ += callback; } void SxeManager::messageReceived(const Message &message) { // only process messages that contain a <sxe/> with a nonempty // 'session' attribute and that are addressed to this particular account if(!message.sxe().attribute("session").isEmpty()) { // skip messages from self if(ownJids_.contains(message.from().full())) { qDebug("from self"); return; } // Check if the <sxe/> contains a <negotiation/> if(message.sxe().elementsByTagName("negotiation").length() > 0) { processNegotiationMessage(message); // processNegotiationMessage() will also pass regular SXE edits in the message // to the session so we're done return; } // otherwise, try finding a matching session for the session if new one not negotiated SxeSession* w = findSession(message.sxe().attribute("session")); if(w) { // pass the message to the session if already established w->processIncomingSxeElement(message.sxe(), message.sxe().attribute("id")); } else { // otherwise record the session id as a "detected session" recordDetectedSession(message); } } } void SxeManager::recordDetectedSession(const Message &message) { // check if a record of the session exists foreach(DetectedSession d, DetectedSessions_) { if(d.session == message.sxe().attribute("session") && d.jid.compare(message.from(), message.type() != "groupchat")) return; } // store a record of a detected session DetectedSession detected; detected.session = message.sxe().attribute("session"); if(message.type() == "groupchat") detected.jid = message.from().bare(); else detected.jid = message.from(); detected.time = QTime::currentTime(); DetectedSessions_.append(detected); } void SxeManager::removeSession(SxeSession* session) { sessions_.removeAll(session); // cancel possible negotiations foreach(SxeNegotiation* negotiation, negotiations_.values(session->session())) { if(negotiation->target.compare(session->target(), true)) abortNegotiation(negotiation); } // notify the target QDomDocument doc; QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", session->session()); QDomElement negotiation = doc.createElementNS(SXENS, "negotiation"); negotiation.appendChild(doc.createElementNS(SXENS, "left-session")); sxe.appendChild(negotiation); sendSxe(sxe, session->target(), session->groupChat()); // delete the session session->deleteLater(); } bool SxeManager::processNegotiationAsParticipant(const QDomNode &negotiationElement, SxeNegotiation* negotiation, QDomNode response) { QDomDocument doc = QDomDocument(); if(negotiationElement.nodeName() == "left-session") { if(negotiation->state == SxeNegotiation::Finished) emit negotiation->session->peerLeftSession(negotiation->peer); } else if(negotiationElement.nodeName() == "abort-negotiation") { if(negotiation->state < SxeNegotiation::HistoryOffered && negotiation->state != SxeNegotiation::DocumentBegan) { // Abort, as in delete session, if still establishing it and not trying to create a new groupchat session if(!(negotiation->groupChat && negotiation->peer.resource().isEmpty())) { removeNegotiation(negotiation); return false; } } else { // Just remove the "negotation" but keep the session negotiation->state = SxeNegotiation::Finished; } } else if(negotiationElement.nodeName() == "connect-request" && negotiation->state == SxeNegotiation::Finished) { // accept all <connect-request/>'s automatically // if currently not negotiating with someone else negotiation->state = SxeNegotiation::HistoryOffered; response.appendChild(doc.createElementNS(SXENS, "history-offer")); } else if((negotiationElement.nodeName() == "accept-history" && negotiation->state == SxeNegotiation::HistoryOffered) || (negotiationElement.nodeName() == "accept-invitation" && negotiation->state == SxeNegotiation::InvitationSent)) { // If this is a new session (negotiation->state == SxeNegotiation::HistoryOffered), // create a new SxeSession if(!negotiation->session) { negotiation->session = createSxeSession(negotiation->target, negotiation->sessionId, negotiation->ownJid, negotiation->groupChat, negotiation->features); negotiation->session->setUUIDPrefix(ONETOONEPREFIXSELF); negotiation->session->initializeDocument(negotiation->initialDoc); } if(!negotiation->session) { // Creating a new session failed for some reason. abortNegotiation(negotiation); return false; } // Retrieve all the edits to the session so far and start queueing new edits QList<const SxeEdit*> snapshot = negotiation->session->startQueueing(); // append <document-begin/> QDomElement documentBegin = doc.createElementNS(SXENS, "document-begin"); response.appendChild(documentBegin); QString prolog = SxeSession::parseProlog(negotiation->session->document()); if(!prolog.isEmpty()) { QUrl::encode(prolog); documentBegin.setAttribute("prolog", QString("data:text/xml,%1").arg(prolog)); } if(!negotiation->groupChat) { // It's safe to give the other participant a prefix to use in 1-to-1 sessions documentBegin.setAttribute("available-uuid-prefix", ONETOONEPREFIXOTHER); } response.appendChild(documentBegin); // append all the SxeEdit's returned by startQueueing() foreach(const SxeEdit* e, snapshot) { response.appendChild(e->xml(doc)); } // append <documend-end/> QDomElement documentEnd = doc.createElementNS(SXENS, "document-end"); QString usedIds; foreach(const QString usedId, negotiation->session->usedSxeIds()) usedIds += usedId + ";"; if(usedIds.size() > 0) usedIds = usedIds.left(usedIds.size() - 1); // strip the last ";" documentEnd.setAttribute("used-sxe-ids", usedIds); response.appendChild(documentEnd); // Need to "flush" the sxe here before stopping queueing if(response.hasChildNodes()) { QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", negotiation->sessionId); sxe.appendChild(response); sendSxe(sxe.toElement(), negotiation->peer, negotiation->groupChat); sxe.removeChild(response); } while(response.hasChildNodes()) response.removeChild(response.firstChild()); // we're all set and can stop queueing new edits to the session negotiation->state = SxeNegotiation::Finished; negotiation->session->stopQueueing(); // signal that a peer joined emit negotiation->session->peerJoinedSession(negotiation->peer); } else if(negotiationElement.nodeName() == "decline-invitation" && negotiation->state == SxeNegotiation::InvitationSent) { QDomNodeList alternatives = negotiationElement.toElement().elementsByTagName("alternative-session"); for(int i = 0; i < alternatives.size(); i++) { emit alternativeSession(negotiation->target, alternatives.at(i).toElement().text()); } if(!negotiation->groupChat || alternatives.size() > 0) { abortNegotiation(negotiation); return false; } } return true; } bool SxeManager::processNegotiationAsJoiner(const QDomNode &negotiationElement, SxeNegotiation* negotiation, QDomNode response, const Message &message) { QDomDocument doc = QDomDocument(); if(negotiationElement.nodeName() == "abort-negotiation") { // Abort, as in delete session, if not trying to join a groupchat session if(!(negotiation->groupChat && negotiation->peer.resource().isEmpty())) { removeNegotiation(negotiation); return false; } } else if(negotiationElement.nodeName() == "invitation" && negotiation->state == SxeNegotiation::NotStarted) { // copy the feature strings to negotiation-features for(uint k = 0; k < negotiationElement.childNodes().length(); k++) { if(negotiationElement.childNodes().at(k).nodeName() == "feature") { negotiation->features += negotiationElement.childNodes().at(k).toElement().text(); } } // check if one of the invitation callbacks accepts the invitation. foreach(bool (*callback)(const Jid &peer, const QList<QString> &features), invitationCallbacks_) { if(callback(negotiation->peer, negotiation->features)) { response.appendChild(doc.createElementNS(SXENS, "accept-invitation")); negotiation->state = SxeNegotiation::InvitationAccepted; return true; } } // othewise abort negotiation abortNegotiation(negotiation); return false; } else if(negotiationElement.nodeName() == "history-offer" && negotiation->state == SxeNegotiation::ConnectionRequested) { // accept the first <history-offer/> that arrives in response to a <connect-request/> negotiation->state = SxeNegotiation::HistoryAccepted; negotiation->peer = message.from(); response.appendChild(doc.createElementNS(SXENS, "accept-history")); } else if(negotiationElement.nodeName() == "document-begin" && (negotiation->state == SxeNegotiation::HistoryAccepted || negotiation->state == SxeNegotiation::InvitationAccepted)) { // Create the new SxeSession if(!negotiation->session) { negotiation->session = createSxeSession(negotiation->target, negotiation->sessionId, negotiation->ownJid, negotiation->groupChat, negotiation->features); // The offer may contain a UUID prefix reserved for us if(negotiationElement.toElement().hasAttribute("available-uuid-prefix")) negotiation->session->setUUIDPrefix(negotiationElement.toElement().attribute("available-uuid-prefix")); } if(negotiation->session) { // set the session to "importing" state which bypasses some version control QDomDocument doc; if(negotiationElement.toElement().hasAttribute("prolog")) { QString prolog = negotiationElement.toElement().attribute("prolog"); if(prolog.startsWith("data:")) { // Assuming non-base64 prolog = prolog.mid(prolog.indexOf(",") + 1); QUrl::decode(prolog); doc.setContent(prolog); } } negotiation->session->startImporting(doc); negotiation->state = SxeNegotiation::DocumentBegan; } else { // creating the session failed for some reason qDebug("Failed to create session."); abortNegotiation(negotiation); return false; } } else if(negotiationElement.nodeName() != "document-end" && negotiation->state == SxeNegotiation::DocumentBegan) { // pass the edit to the session QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", negotiation->sessionId); sxe.appendChild(negotiationElement.cloneNode()); negotiation->session->processIncomingSxeElement(sxe, QString()); } else if(negotiationElement.nodeName() == "document-end" && negotiation->state == SxeNegotiation::DocumentBegan) { // The initial document has been received and we're done negotiation->state = SxeNegotiation::Finished; // Decode the 'used-sxe-ids' field foreach(QString usedId, negotiationElement.toElement().attribute("used-sxe-ids").split(";")) if (usedId.size() > 0) negotiation->session->addUsedSxeId(usedId); // Exit the "importing" state so that normal version control resumes negotiation->session->stopImporting(); } return true; } QPointer<SxeSession> SxeManager::processNegotiationMessage(const Message &message) { if(PsiOptions::instance()->getOption("options.messages.ignore-non-roster-contacts").toBool() && message.type() != "groupchat") { // Ignore the message if contact not in roster if(!pa_->find(message.from())) { qDebug("SXE invitation received from contact that is not in roster."); return 0; } } // Find or create a negotiation object SxeNegotiation* negotiation = findNegotiation(message.from(), message.sxe().attribute("session")); if(negotiation) { // Only accept further negotiation messages from the source we are already negotiationing with or if we've requested connection to a groupchat session if(!negotiation->peer.compare(message.from()) && !(negotiation->groupChat && negotiation->peer.resource().isEmpty())) { abortNegotiation(negotiation->sessionId, message.from(), true); return 0; } } else negotiation = createNegotiation(message); // Prepare the response <sxe/> QDomDocument doc; QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", negotiation->sessionId); QDomElement response = doc.createElementNS(SXENS, "negotiation"); // Process each child of the <sxe/> QDomNode n; for(int i = 0; i < message.sxe().childNodes().count(); i++) { n = message.sxe().childNodes().at(i); // skip non-elements if(!n.isElement()) continue; if(n.nodeName() == "negotiation") { // Process each child element of <negotiation/> for(int j = 0; j < n.childNodes().count(); j++) { if(negotiation->role == SxeNegotiation::Participant) { if(!processNegotiationAsParticipant(n.childNodes().at(j), negotiation, response)) return 0; } else if(negotiation->role == SxeNegotiation::Joiner) { if(!processNegotiationAsJoiner(n.childNodes().at(j), negotiation, response, message)) return 0; } else { Q_ASSERT(false); } // Send any responses that were generated if(response.hasChildNodes()) { sxe.appendChild(response); sendSxe(sxe.cloneNode().toElement(), negotiation->peer, negotiation->groupChat); sxe.removeChild(response); } while(response.hasChildNodes()) response.removeChild(response.firstChild()); } } else if(negotiation->state == SxeNegotiation::Finished && negotiation->session) { // There should be no more children after <negotiation/>... qDebug("Children after <negotiation/> in <sxe/>."); } } // Cleanup: // Delete negotation objects that are no longer needed if(negotiation) { if(negotiation->state == SxeNegotiation::NotStarted) { removeNegotiation(negotiation); } else if(negotiation->state == SxeNegotiation::Finished) { // Save session for successful negotiations but delete the negotiation object SxeSession* sxesession = negotiation->session; if(sxesession) { if(!sessions_.contains(sxesession)) { // store and emit a signal about the session only if it's new sessions_.append(sxesession); emit sessionNegotiated(sxesession); } } removeNegotiation(negotiation); // return a handle to the session return sxesession; } } return 0; } SxeManager::SxeNegotiation* SxeManager::findNegotiation(const Jid &jid, const QString &session) { QList<SxeNegotiation*> negotiations = negotiations_.values(session); foreach(SxeNegotiation* negotiation, negotiations) { if(negotiation->state != SxeNegotiation::Aborted && negotiation->peer.compare(jid, negotiation->state != SxeNegotiation::ConnectionRequested)) return negotiation; } return 0; } void SxeManager::removeNegotiation(SxeNegotiation* negotiation) { negotiations_.remove(negotiation->sessionId, negotiation); delete negotiation; } SxeManager::SxeNegotiation* SxeManager::createNegotiation(SxeNegotiation::Role role, SxeNegotiation::State state, const QString &sessionId, const Jid &target, const Jid &ownJid, bool groupChat) { SxeNegotiation* negotiation = new SxeNegotiation; negotiation->role = role; negotiation->state = state; negotiation->sessionId = sessionId; negotiation->target = target; negotiation->peer = target; negotiation->ownJid = ownJid; negotiation->groupChat = groupChat; negotiation->session = 0; negotiations_.insert(sessionId, negotiation); return negotiation; } SxeManager::SxeNegotiation* SxeManager::createNegotiation(const Message &message) { // Create a new negotiation object SxeNegotiation* negotiation = new SxeNegotiation; negotiation->sessionId = message.sxe().attribute("session"); negotiation->session = findSession(negotiation->sessionId); negotiation->peer = message.from(); if(negotiation->session) { // If negotiation exists, we're going to be the "server" for the negotiation negotiation->role = SxeNegotiation::Participant; negotiation->state = SxeNegotiation::Finished; negotiation->target = negotiation->session->target(); negotiation->groupChat = negotiation->session->groupChat(); negotiation->ownJid = negotiation->session->ownJid(); negotiation->features = negotiation->session->features(); } else { // Otherwise we're joining a session negotiation->role = SxeNegotiation::Joiner; negotiation->state = SxeNegotiation::NotStarted; if(message.type() == "groupchat") { // If we're being invited from a groupchat, // ownJid is determined based on the bare part of ownJids_ negotiation->groupChat = true; foreach(QString j, ownJids_) { if(message.from().bare() == j.left(j.indexOf("/"))) { negotiation->ownJid = j; break; } } // Also, the target is just the bare JID in a groupchat negotiation->target = message.from().bare(); } else { negotiation->groupChat = false; negotiation->target = negotiation->peer; } if(negotiation->ownJid.isEmpty()) negotiation->ownJid = message.to(); } // Reset the timeout negotiationTimer_.start(); // Store the session negotiations_.insert(negotiation->sessionId, negotiation); return negotiation; } void SxeManager::joinSession(const Jid &target, const Jid &ownJid, bool groupChat, const QString &session) { // Prepare the <connect-request/> QDomDocument doc; QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", session); QDomElement negotiationElement = doc.createElementNS(SXENS, "negotiation"); QDomElement request = doc.createElementNS(SXENS, "connect-request"); negotiationElement.appendChild(request); sxe.appendChild(negotiationElement); // Create the negotiation object createNegotiation(SxeNegotiation::Joiner, SxeNegotiation::ConnectionRequested, session, target, ownJid, groupChat); sendSxe(sxe, target, groupChat); // Reset the timeout for negotiations negotiationTimer_.start(); return; } void SxeManager::startNewSession(const Jid &target, const Jid &ownJid, bool groupChat, const QDomDocument &initialDoc, QList<QString> features) { // check that the target supports SXE and all specified features if(!checkSupport(target, features)) { qDebug() << QString("Tried to start an SXE session with %1 but the client doesn't support all features.").arg(target.full()).toAscii(); return; } // generate a session identifier QString session; do { session = SxeSession::generateUUID(); } while (findSession(session)); if(features.size() == 0) { // some features must be specified return; } // Prepare the <invitation/> QDomDocument doc; QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", session); QDomElement negotiationElement = doc.createElementNS(SXENS, "negotiation"); QDomElement request = doc.createElementNS(SXENS, "invitation"); QDomElement feature = doc.createElementNS(SXENS, "feature"); foreach(QString f, features) { feature = feature.cloneNode(false).toElement(); feature.appendChild(doc.createTextNode(f)); request.appendChild(feature); } negotiationElement.appendChild(request); sxe.appendChild(negotiationElement); // Create the negotiation object SxeNegotiation* negotiation = createNegotiation(SxeNegotiation::Participant, SxeNegotiation::InvitationSent, session, target, ownJid, groupChat); negotiation->initialDoc = initialDoc; negotiation->features = features; sendSxe(sxe, target, groupChat); // Reset the timeout for negotiations negotiationTimer_.start(); return; } void SxeManager::negotiationTimeout() { foreach(SxeNegotiation* negotiation, negotiations_.values()){ if(negotiation->role == SxeNegotiation::Participant && negotiation->state < SxeNegotiation::HistoryOffered && negotiation->state != SxeNegotiation::DocumentBegan) { if(negotiation->session) negotiation->session->endSession(); abortNegotiation(negotiation->sessionId, negotiation->peer, negotiation->groupChat); } delete negotiation; } negotiations_.clear(); } // #include <QTextStream> void SxeManager::sendSxe(QDomElement sxe, const Jid & receiver, bool groupChat) { SxeSession* session = qobject_cast<SxeSession*>(sender()); // Add a unique id to each sent sxe element if(session) { QString id = session->generateUUIDForSession(); sxe.setAttribute("id", id); session->addUsedSxeId(id); } else sxe.setAttribute("id", SxeSession::generateUUID()); Message m(receiver); m.setSxe(sxe); if(groupChat && receiver.resource().isEmpty()) m.setType("groupchat"); if(client_->isActive()) { // send queued messages first while(!queuedMessages_.isEmpty()) client_->sendMessage(queuedMessages_.takeFirst()); client_->sendMessage(m); } else { queuedMessages_.append(m); } } QList< QPointer<SxeSession> > SxeManager::findSession(const Jid &jid) { // find if a session for the jid already exists QList< QPointer<SxeSession> > matching; foreach(QPointer<SxeSession> w, sessions_) { // does the jid match? if(w->target().compare(jid)) { matching.append(w); } } return matching; } QPointer<SxeSession> SxeManager::findSession(const QString &session) { // find if a session for the session already exists foreach(SxeSession* w, sessions_) { // does the session match? if(w->session() == session) return w; } return 0; } QPointer<SxeSession> SxeManager::createSxeSession(const Jid &target, QString session, const Jid &ownJid, bool groupChat, const QList<QString> &features) { if(session.isEmpty() || !target.isValid()) return 0; if(!ownJids_.contains(ownJid.full())) ownJids_.append(ownJid.full()); // FIXME: detect serverside support bool serverSupport = false; // create the SxeSession QPointer<SxeSession> w = new SxeSession(target, session, ownJid, groupChat, serverSupport, features); // connect the signals connect(w, SIGNAL(newSxeElement(QDomElement, Jid, bool)), SLOT(sendSxe(const QDomElement &, const Jid &, bool))); connect(w, SIGNAL(sessionEnded(SxeSession*)), SLOT(removeSession(SxeSession*))); removeDetectedSession(w); return w; // Note: the session should be added to sessions_ once negotiation is finished } void SxeManager::abortNegotiation(QString session, const Jid &peer, bool groupChat) { QDomDocument doc = QDomDocument(); QDomElement sxe = doc.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", session); QDomElement negotiationElement = doc.createElementNS(SXENS, "negotiation"); negotiationElement.appendChild(doc.createElementNS(SXENS, "abort-negotiation")); sxe.appendChild(negotiationElement); sendSxe(sxe, peer, groupChat); } void SxeManager::abortNegotiation(SxeNegotiation* negotiation) { abortNegotiation(negotiation->sessionId, negotiation->peer, negotiation->groupChat); removeNegotiation(negotiation); } void SxeManager::removeDetectedSession(SxeSession* session) { for(int i = 0; i < DetectedSessions_.size(); i++) { DetectedSession detected = DetectedSessions_.at(i); // Remove the specified session from the list if(detected.session == session->session() && detected.jid.compare(session->target(), true)) DetectedSessions_.removeAt(i); else if(detected.time.secsTo(QTime::currentTime()) > 1800) // Remove detected session that are old DetectedSessions_.removeAt(i); } } void SxeManager::groupChatLeft(const Jid &jid) { for(int i = 0; i < ownJids_.size(); i++) { if(jid.bare() == ownJids_.at(i).left(ownJids_.at(i).indexOf("/"))) ownJids_.removeAt(i); } QList< QPointer<SxeSession> > matching = findSession(jid); foreach(QPointer<SxeSession> w, matching) w->endSession(); } void SxeManager::groupChatJoined(const Jid &, const Jid &ownJid) { if(!ownJids_.contains(ownJid.full())) ownJids_.append(ownJid.full()); } bool SxeManager::checkSupport(const Jid &jid, const QList<QString> &features) { QStringList supported = pa_->capsManager()->features(jid).list(); if(!supported.contains(SXENS)) return false; foreach(QString f, features) { if(!supported.contains(f)) return false; } return true; } �������������������������������������������������������������psi-0.14/src/sxe/sxenewedit.h�����������������������������������������������������������������������0000644�0001750�0001750�00000005130�11305557613�014256� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxenewedit.h - An single SXE edit that creates a new node * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDENEWEDIT_H #define SXDENEWEDIT_H #include "sxeedit.h" /*! \brief A class used for storing SXE edits that create nodes in the undo stacks and in the queue of outgoing edits.*/ class SxeNewEdit : public SxeEdit { public: /*! \brief Constructor * Constructs a SxeNewEdit for \a node. */ SxeNewEdit(const QString rid, const QDomNode &node, const QString parent, double primaryWeight, bool remote); /*! \brief Constructor * Parses a SxeNewEdit from \a sxeElement. */ SxeNewEdit(const QDomElement &sxeElement, bool remote = true); /*! \brief The type of edit.*/ SxeEdit::EditType type() const; /*! \brief The XML (the SXE) representing the edit.*/ QDomElement xml(QDomDocument &doc) const; /*! \brief Returns the type of the node.*/ QDomNode::NodeType nodeType() const; /*! \brief Returns the rid of the parent.*/ QString parent() const; /*! \brief Returns the primary-weight of the node.*/ double primaryWeight() const; /*! \brief Returns the name of the node, if any.*/ QString name() const; /*! \brief Returns the namespace of the node, if any.*/ QString nameSpace() const; /*! \brief Returns the chdata of the node, if any.*/ QString chdata() const; /*! \brief Returns the target of the processing instruction, if any.*/ QString processingInstructionTarget() const; /*! \brief Returns the target of the processing instruction, if any.*/ QString processingInstructionData() const; private: QString type_; QString parent_; double primaryWeight_; QString ns_; QString identifier_; QString data_; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxerecordedit.h��������������������������������������������������������������������0000644�0001750�0001750�00000004470�11305557613�014751� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxeedit.h - A class for SXE edits that change a node * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDEMETADATAEDIT_H #define SXDEMETADATAEDIT_H #include "sxeedit.h" #include <QHash> /*! \brief A class used for storing SXE edits that change nodes in the undo stacks and in the queue of outgoing edits.*/ class SxeRecordEdit : public SxeEdit { public: /*! \brief The possible keys for record.*/ enum Key {Parent, PrimaryWeight, Name, Chdata, ReplaceFrom, ReplaceN, ProcessingInstructionTarget, ProcessingInstructionData}; /*! \brief Constructor * Constructs a SxeRecordEdit for \a node. */ SxeRecordEdit(const QString rid, int version, QHash<Key, QString> changes, bool remote = false); /*! \brief Constructor * Parses a SxeRecordEdit from \a sxeElement. */ SxeRecordEdit(const QDomElement &sxeElement, bool remote = true); /*! \brief The type of edit.*/ SxeEdit::EditType type() const; /*! \brief The XML (the SXE) representing the edit.*/ QDomElement xml(QDomDocument &doc) const; /*! \brief The version of the edit.*/ int version() const; /*! \brief The keys for the record entries that the edit modifies. */ QList<Key> keys() const; /*! \brief The value that the edit will set for the given record entry. */ QString value(Key key) const; /*! \brief Turns the edit into a no-op.*/ void nullify(); private: static QString keyToString(Key key); int version_; QHash<Key, QString> changes_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxesession.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000057332�11305557613�014650� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxesession.cpp - Sxe Session * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxesession.h" #include "QTimer" #include "QUuid" // The maxlength of a chdata that gets put in one edit enum {MAXCHDATA = 1024}; using namespace XMPP; //---------------------------------------------------------------------------- // SxeSession //---------------------------------------------------------------------------- SxeSession::SxeSession(const Jid &target, const QString &session, const Jid &ownJid, bool groupChat, bool serverSupport, const QList<QString> &features) { serverSupport_ = serverSupport; groupChat_ = groupChat; target_ = target; ownJid_ = ownJid; session_ = session; features_ = features; queueing_ = false; importing_ = false; uuidMaxPostfix_ = 0; setUUIDPrefix(); } SxeSession::~SxeSession() { emit sessionEnded(this); } void SxeSession::initializeDocument(const QDomDocument &doc) { bool origImporting = importing_; importing_ = true; // reset the document doc_ = QDomDocument(); foreach(SxeRecord* meta, recordByNodeId_.values()) meta->deleteLater(); // recordByNode_.clear(); recordByNodeId_.clear(); queuedIncomingEdits_.clear(); queuedOutgoingEdits_.clear(); // import prolog doc_.setContent(parseProlog(doc)); // import other nodes // create all nodes recursively from root QDomNodeList children = doc.childNodes(); for(int i = 0; i < children.size(); i++) { // skip the XML declaration <?xml ...?> because it isn't a processing instruction if(!(children.at(i).isProcessingInstruction() && children.at(i).toProcessingInstruction().target().toLower() == "xml")) generateNewNode(children.at(i), QString(), i); } importing_ = origImporting; } void SxeSession::processIncomingSxeElement(const QDomElement &sxe, const QString &id) { if(id.isEmpty() && !importing_) { qDebug("Trying to process an SXE element without an associated id!"); return; } if(processSxe(sxe, id)) emit documentUpdated(true); } bool SxeSession::processSxe(const QDomElement &sxe, const QString &id) { // Don't accept duplicates if(!id.isEmpty() && usedSxeIds_.contains(id)) { qDebug() << QString("Tried to process a duplicate %1 (received: %2).").arg(sxe.attribute("id")).arg(usedSxeIds_.size()).toAscii(); return false; } if(!id.isEmpty()) usedSxeIds_ += id; // store incoming edits when queueing if(queueing_) { // Make sure the element is not already in the queue. foreach(IncomingEdit i, queuedIncomingEdits_) if(i.xml == sxe) return false; IncomingEdit incoming; incoming.id = id; incoming.xml = sxe.cloneNode(true).toElement(); queuedIncomingEdits_.append(incoming); return false; } // create an SxeEdit for each child of the <sxe/> QDomNodeList children = sxe.childNodes(); QList<SxeEdit*> edits; for(uint i=0; i < children.length(); i++) { if(children.item(i).nodeName() == "new") edits.append(new SxeNewEdit(children.item(i).toElement())); else if(children.item(i).nodeName() == "set") edits.append(new SxeRecordEdit(children.item(i).toElement())); else if(children.item(i).nodeName() == "remove") edits.append(new SxeRemoveEdit(children.item(i).toElement())); } if (edits.size() == 0) return false; // process all the edits foreach(SxeEdit* e, edits) { SxeRecord* meta; if(e->type() == SxeEdit::New) meta = createRecord(e->rid()); else meta = record(e->rid()); if(meta) meta->apply(doc_, e); } return true; } const QDomDocument& SxeSession::document() const { return doc_; } bool SxeSession::groupChat() const { return groupChat_; } bool SxeSession::serverSupport() const { return serverSupport_; } const Jid SxeSession::target() const { return target_; } const QString SxeSession::session() const { return session_; } const Jid SxeSession::ownJid() const { return ownJid_; } const QList<QString> SxeSession::features() const { return features_; } QList<const SxeEdit*> SxeSession::startQueueing() { // do nothing if already queueing if(queueing_) return QList<const SxeEdit*>(); queueing_ = true; // Return all the effective Edits to the session so far (snapshot) // make sure that they are added in the right order (parents first) QString rootid; QList<const SxeEdit*> nonDocElementEdits; QMultiHash<QString, QString> ridByParent; // first collect all nodes into a hash by their parent foreach(SxeRecord* m, recordByNodeId_.values()) { if(!m->parent().isEmpty()) { ridByParent.insert(m->parent(), m->rid()); } else if(!m->node().isElement()) { nonDocElementEdits += m->edits(); } else rootid = m->rid(); } // starting from the root, add all edits to a list recursively QList<const SxeEdit*> edits; if(!rootid.isNull()) arrangeEdits(ridByParent, edits, rootid); return nonDocElementEdits + edits; } void SxeSession::arrangeEdits(QHash<QString, QString> &ridByParent, QList<const SxeEdit*> &output, const QString &iterator) { // add the edits to this node if(recordByNodeId_.contains(iterator)) output += recordByNodeId_.value(iterator)->edits(); // process all the children QString child; while(!(child = ridByParent.take(iterator)).isNull()) { arrangeEdits(ridByParent, output, child); } } void SxeSession::stopQueueing() { // do nothing if not queueing if(!queueing_) return; queueing_ = false; // Process queued elements flush(); if(!queuedIncomingEdits_.isEmpty()) { while(!queuedIncomingEdits_.isEmpty()) { IncomingEdit queued = queuedIncomingEdits_.takeFirst(); processSxe(queued.xml, queued.id); } emit documentUpdated(true); } } void SxeSession::startImporting(const QDomDocument &doc) { importing_ = true; // reset the document initializeDocument(doc); // start queueing outgoing edits startQueueing(); } void SxeSession::stopImporting() { stopQueueing(); importing_ = false; } void SxeSession::endSession() { deleteLater(); } const QDomNode SxeSession::insertNodeBefore(const QDomNode &node, const QDomNode &parent, const QDomNode &referenceNode) { if(referenceNode.isNull() || referenceNode.previousSibling().isNull()) { // insert as the first node SxeRecord* firstMeta = record(parent.firstChild()); double primaryWeight; if(firstMeta) primaryWeight = firstMeta->primaryWeight() - 1; else primaryWeight = 0; // find out the rid of the parent node QString parentId; SxeRecord* parentMeta = record(parent); if(parentMeta) parentId = parentMeta->rid(); else { qDebug("Trying to insert a node to parent without an id"); return QDomNode(); } return insertNode(node, parentId, primaryWeight); } else return insertNodeAfter(node, parent, referenceNode.previousSibling()); } const QDomNode SxeSession::insertNodeAfter(const QDomNode &node, const QDomNode &parent, const QDomNode &referenceNode) { if(node.isNull()) return QDomNode(); // process each child of a document fragment separately if(node.isDocumentFragment()) { // insert the first node relative to the specified referenceNode QDomNode reference = referenceNode; QDomNodeList children = node.childNodes(); for(int i = 0; i < children.size(); i++) { QDomNode newNode = children.at(i); insertNodeAfter(newNode, parent, reference); // and the rest relative to the previous sibling reference = newNode; } return QDomNode(); } // find out the rid of the parent node QString parentId; SxeRecord* parentMeta = record(parent); if(parentMeta) parentId = parentMeta->rid(); else { qDebug("Trying to insert a node to parent without an id"); return QDomNode(); } // find out the appropriate weight for the node double primaryWeight; SxeRecord* referenceMeta = record(referenceNode); SxeRecord* nextReferenceMeta = record(referenceNode.nextSibling()); if(parent.childNodes().count() == 0) primaryWeight = 0; else if(referenceMeta && nextReferenceMeta && referenceNode.parentNode() == parent) { // get the average of the weights of the reference and it's next sibling primaryWeight = (referenceMeta->primaryWeight() + nextReferenceMeta->primaryWeight()) / 2; } else { // insert as the last node referenceMeta = record(parent.lastChild()); if(referenceMeta) primaryWeight = referenceMeta->primaryWeight() + 1; else primaryWeight = 0; } return insertNode(node, parentId, primaryWeight); } const QDomNode SxeSession::insertNode(const QDomNode &node, const QString &parentId, double primaryWeight) { QDomNode newNode; SxeRecord* meta = record(node); if(meta) { // move an existing node // figure out what's to be changed QHash<SxeRecordEdit::Key, QString> changes; if(meta->parent() != parentId) changes.insert(SxeRecordEdit::Parent, parentId); if(meta->primaryWeight() != primaryWeight) changes.insert(SxeRecordEdit::PrimaryWeight, QString::number(primaryWeight)); if(changes.size() > 0) { // create the edit SxeRecordEdit* edit = new SxeRecordEdit(meta->rid(), meta->version() + 1, changes); // apply it meta->apply(doc_, edit); // send the edit to others queueOutgoingEdit(edit); emit documentUpdated(false); } return node; } else { QList<SxeEdit*> edits; // create a new node QDomNode result = generateNewNode(node, parentId, primaryWeight); emit documentUpdated(false); return result; } } void SxeSession::removeNode(const QDomNode &node) { if(node.isNull()) return; // create SxeRemoveEdits for all child nodes generateRemoves(node); flush(); emit documentUpdated(false); } void SxeSession::setAttribute(const QDomNode &node, const QString &attribute, const QString &value, int from, int n) { if(!node.isElement() || attribute.isEmpty()) return; if(value.isNull()) { if(from < 0) { // Interpret passing QString() as value as wishing to remove the attribute if(node.toElement().hasAttribute(attribute)) removeNode(node.toElement().attributeNode(attribute)); } return; } if(node.toElement().hasAttribute(attribute)) { setNodeValue(node.attributes().namedItem(attribute), value, from, n); } else { if(from >= 0) { qDebug("from > 0 although attribute doesn't exist yet."); return; } QDomAttr domattr = document_.createAttribute(attribute); domattr.setValue(value); insertNodeAfter(domattr, node, QDomNode()); } } void SxeSession::setNodeValue(const QDomNode &node, const QString &value, int from, int n) { SxeRecord* meta = record(node); if(!meta) { qDebug() << "Trying to set value of " << node.nodeName() << " (a non-existent node) to \"" << value << "\""; return; } if(!(node.isAttr() || node.isText())) { qDebug() << "Trying to set value of a non-attr/text node " << node.nodeName(); return; } // Check whether anythings changing: QString newValue; if(from >= 0 && n >= 0) { if((from + n) > node.nodeValue().length()) { qDebug() << QString("from (%1) + n (%2) > (length of existing node value) (%3).").arg(from).arg(n).arg(node.nodeValue().length()); return; } newValue = node.nodeValue().replace(from, n, value); } else newValue = value; if(newValue == node.nodeValue()) return; // Create the appropriate RecordEdit QHash<SxeRecordEdit::Key, QString> changes; changes.insert(SxeRecordEdit::Chdata, value); if(from >= 0 && n >= 0) { changes.insert(SxeRecordEdit::ReplaceFrom, QString("%1").arg(from)); changes.insert(SxeRecordEdit::ReplaceN, QString("%1").arg(n)); } // create the edit SxeRecordEdit* edit = new SxeRecordEdit(meta->rid(), meta->version() + 1, changes); // apply it meta->apply(doc_, edit); // send the edit to others queueOutgoingEdit(edit); emit documentUpdated(false); } void SxeSession::flush() { if(queuedOutgoingEdits_.isEmpty()) return; // create the sxe element QDomElement sxe = doc_.createElementNS(SXENS, "sxe"); sxe.setAttribute("session", session_); // append all queued edits while(!queuedOutgoingEdits_.isEmpty()) { sxe.appendChild(queuedOutgoingEdits_.takeFirst()); } // pass the bundle to SxeManager emit newSxeElement(sxe, target(), groupChat_); } QDomNode SxeSession::generateNewNode(const QDomNode &node, const QString &parent, double primaryWeight) { if(!record(node)) { // generate the appropriate edit(s) for the node QString rid = generateUUIDForSession(); // create the SxeRecord SxeRecord* meta = createRecord(rid); if(!meta) return QDomNode(); if((node.isAttr() || node.isText()) && node.nodeValue().length() > MAXCHDATA) { // Generate a "stub" of the new node QDomNode clone = node.cloneNode(); QString full = clone.nodeValue(); clone.setNodeValue(""); QDomNode newNode = generateNewNode(clone, parent, primaryWeight); flush(); // append the value for(int i = 0; i < full.length(); i += MAXCHDATA) { setNodeValue(newNode, full.mid(i, MAXCHDATA), i, 0); flush(); } } else { SxeEdit* edit = new SxeNewEdit(rid, node, parent, primaryWeight, false); meta->apply(doc_, edit); queueOutgoingEdit(edit); } // process all the attributes and child nodes recursively if(node.isElement()) { // attributes QDomNamedNodeMap attributes = node.attributes(); for(int i = 0; i < attributes.count(); i++) generateNewNode(attributes.item(i), rid, i); // child nodes QDomNodeList children = node.childNodes(); for(int i = 0; i < children.count(); i++) generateNewNode(children.at(i), rid, i); } return meta->node(); } return QDomNode(); } void SxeSession::generateRemoves(const QDomNode &node) { SxeRecord* meta = record(node); if(meta) { // process all the attributes and child nodes recursively if(node.isElement()) { // attributes QDomNamedNodeMap attributes = node.attributes(); for(int i = 0; i < attributes.count(); i++) generateRemoves(attributes.item(i)); // child nodes QDomNodeList children = node.childNodes(); for(int i = 0; i < children.count(); i++) generateRemoves(children.at(i)); } // generate the appropriate edit for the node SxeRemoveEdit* edit = new SxeRemoveEdit(meta->rid()); queueOutgoingEdit(edit); meta->apply(doc_, edit); } } void SxeSession::reposition(const QDomNode &node, bool remote) { Q_UNUSED(remote); SxeRecord* meta = record(node); if(!meta) { qDebug("Trying to reposition a node without record."); return; } // inserting nodes to the document node is a special case if(meta->parent().isEmpty()) { if(node.isElement() && !(doc_.documentElement().isNull() || doc_.documentElement() == node)) { qDebug("Trying to add a root node when one already exists."); removeNode(node); flush(); return; } doc_.appendChild(node); return; } // find the parent node SxeRecord* parentMeta = record(meta->parent()); QDomNode parentNode; if(!parentMeta || (parentNode = parentMeta->node()).isNull()) { qDebug("non-existent parent. Deleting node."); removeNode(node); flush(); return; } // simply insert if an attribute if(node.isAttr()) { QDomElement parentElement = parentNode.toElement(); if(parentElement.isNull()) { qDebug("Trying to insert an attribute to a non-element."); return; } // unless an attribute with the same name already exists if(parentElement.hasAttribute(node.nodeName()) && node != parentElement.attributeNode(node.nodeName())) { // qDebug() << QString("Removing an attribute node '%1' because one already exists").arg(node.nodeName()); // delete the node with smaller secondary weight if(removeSmaller(meta, record(parentElement.attributeNode(node.nodeName())))) return; } parentElement.setAttributeNode(node.toAttr()); return; } // get the list of siblings QDomNodeList children = parentNode.childNodes(); // default to appending QDomNode before; bool insertLast = true; if(children.length() > 0) { // find the child with the smallest weight greater than the weight of the node itself // if any, insert the node before that node for(uint i=0; i < children.length(); i++) { if(children.item(i) != node) { SxeRecord* siblingMeta = record(children.item(i)); if(siblingMeta && *meta < *siblingMeta) { // qDebug() << QString("%1 (pw: %2) is less than %3 (pw: %4)").arg(meta->name()).arg(meta->primaryWeight()).arg(siblingMeta->name()).arg(siblingMeta->primaryWeight()).toAscii(); before = children.item(i); insertLast = false; break; } } } } if(insertLast) { // qDebug() << QString("Repositioning '%1' (pw: %2) as last.").arg(node.nodeName()).arg(meta->primaryWeight()).toAscii(); parentNode.appendChild(node); } else { // qDebug() << QString("Repositioning '%1' (pw: %2) before '%3' (pw: %4).").arg(node.nodeName()).arg(meta->primaryWeight()).arg(before.nodeName()).arg(record(before)->primaryWeight()).toAscii(); parentNode.insertBefore(node, before); } } // void SxeSession::addToLookup(const QDomNode &node, bool, const QString &rid) { // recordByNode_[node] // = recordByNodeId_[rid]; // } void SxeSession::handleNodeToBeAdded(const QDomNode &node, bool remote) { emit nodeToBeAdded(node, remote); reposition(node, remote); emit nodeAdded(node, remote); } void SxeSession::handleNodeToBeMoved(const QDomNode &node, bool remote) { emit nodeToBeMoved(node, remote); reposition(node, remote); emit nodeMoved(node, remote); } void SxeSession::handleNodeToBeRemoved(const QDomNode &node, bool remote) { emit nodeToBeRemoved(node, remote); removeRecord(node); } void SxeSession::removeRecord(const QDomNode &node) { QMutableHashIterator<QString, SxeRecord*> i(recordByNodeId_); while(i.hasNext()) { if(node == i.next().value()->node()) { i.remove(); return; } } } bool SxeSession::removeSmaller(SxeRecord* meta1, SxeRecord* meta2) { if(!meta1) return true; if(!meta2) return false; if(meta1->hasSmallerSecondaryWeight(*meta2)) { removeNode(meta1->node()); flush(); return true; } else { removeNode(meta2->node()); flush(); return false; } } void SxeSession::addUsedSxeId(QString id) { usedSxeIds_ += id; } QList<QString> SxeSession::usedSxeIds() { return usedSxeIds_; } void SxeSession::queueOutgoingEdit(SxeEdit* edit) { if(!importing_) queuedOutgoingEdits_.append(edit->xml(doc_)); } SxeRecord* SxeSession::createRecord(const QString &id) { if(recordByNodeId_.contains(id)) { qDebug() << QString("record by id '%1' already exists.").arg(id).toAscii(); return NULL; } SxeRecord* m = new SxeRecord(id); recordByNodeId_[id] = m; // once the node is actually created, add it to the lookup table // connect(m, SIGNAL(nodeAdded(QDomNode, bool, QString)), SLOT(addToLookup(const QDomNode &, bool, const QString &))); // remove the node in case of a conflicting edit connect(m, SIGNAL(nodeRemovalRequired(QDomNode)), SLOT(removeNode(QDomNode))); // reposition and emit public signals as needed when record is changed connect(m, SIGNAL(nodeToBeAdded(QDomNode, bool, QString)), SLOT(handleNodeToBeAdded(const QDomNode &, bool))); connect(m, SIGNAL(nodeToBeMoved(QDomNode, bool)), SLOT(handleNodeToBeMoved(const QDomNode &, bool))); connect(m, SIGNAL(nodeToBeRemoved(QDomNode, bool)), SLOT(handleNodeToBeRemoved(const QDomNode &, bool))); connect(m, SIGNAL(chdataToBeChanged(QDomNode, bool)), SIGNAL(chdataToBeChanged(const QDomNode &, bool))); connect(m, SIGNAL(chdataChanged(QDomNode, bool)), SIGNAL(chdataChanged(const QDomNode &, bool))); // connect(m, SIGNAL(nameChanged(QDomNode, bool)), SIGNAL(nameChanged(const QDomNode &, bool))); return m; } SxeRecord* SxeSession::record(const QString &id) { return recordByNodeId_.value(id); } SxeRecord* SxeSession::record(const QDomNode &node) const { if(node.isNull()) return NULL; // go through all the SxeRecord's foreach(SxeRecord* meta, recordByNodeId_.values()) { // qDebug() << QString("id: %1").arg(meta->rid()).toAscii(); if(node == meta->node()) return meta; } return NULL; } void SxeSession::setUUIDPrefix(const QString uuidPrefix) { if(!uuidPrefix.isNull()) uuidPrefix_ = uuidPrefix; else uuidPrefix_ = generateUUID(); } QString SxeSession::generateUUIDForSession() { return QString("%1.%2").arg(uuidPrefix_).arg(++uuidMaxPostfix_, 0, 36); // 36 is the max allowed base } QString SxeSession::generateUUID() { QString fullstring = QUuid::createUuid().toString(); // return the string between "{" and "}" int start = fullstring.indexOf("{") + 1; return fullstring.mid(start, fullstring.lastIndexOf("}") - start); } QString SxeSession::parseProlog(const QDomDocument &doc) { QString prolog; QTextStream stream(&prolog); // check for the XML declaration if(doc.childNodes().at(0).isProcessingInstruction() && doc.childNodes().at(0).toProcessingInstruction().target().toLower() == "xml") doc.childNodes().at(0).save(stream, 1); if(!doc.doctype().isNull()) doc.doctype().save(stream, 1); return prolog; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxemanager.h�����������������������������������������������������������������������0000644�0001750�0001750�00000021333�11305557613�014234� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxemanager.h - Whiteboard manager * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDEMANAGER_H #define SXDEMANAGER_H #include "QTimer" #include "sxesession.h" namespace XMPP { class Client; class Jid; class Message; } using namespace XMPP; /*! \brief The manager for SXE sessions and negotiations. * This class listens to incoming messages and picks up any that contain an * SxdE element. If the element belongs to an already established session, * the element is passed to the session. If the element is a negotiation element, * the manager handles it. Accepting invitations is determined based on callback * functions provided to the class. * * The manager also provides a possibillity for the local client to start * a new session negotiation with the desired contact. * * One instance per PsiAccount should be created. * * \sa SxeSession */ class SxeManager : public QObject { Q_OBJECT /*! \brief A simple struct used to keep track of the detected SXE sessions.*/ struct DetectedSession { QString session; Jid jid; QTime time; }; /*! \brief A simple class to keep track of the state of a session negotiation process.*/ class SxeNegotiation{ public: enum Role {Participant, Joiner}; enum State {NotStarted, InvitationSent, ConnectionRequested, InvitationAccepted, DocumentBegan, /*DocumentEnded,*/ HistoryOffered, HistoryAccepted, Finished, Aborted}; /*! \brief Describes our role in the negotiation.*/ Role role; /*! \brief Describes the current state of the negotiation.*/ State state; /*! \brief The identifier for the session.*/ QString sessionId; /*! \brief The JID that will be used for delivering the sxe messages once session is established.*/ Jid target; /*! \brief The JID where negotiation messages are sent.*/ Jid peer; /*! \brief The user's own JID used in the session.*/ Jid ownJid; /*! \brief Set if the target is a groupchat.*/ bool groupChat; /*! \brief The document to be sent as the initial document during the negotiation. * This is only relevant when Role == Participant. */ QDomDocument initialDoc; /*! \brief A list of features proposed for the session.*/ QList<QString> features; /*! \brief The session created for this negotiation.*/ QPointer<SxeSession> session; }; public: /*! \brief Constructor. * Creates a new manager for the specified Client and PsiAccount */ SxeManager(XMPP::Client* client, PsiAccount* pa); /*! \brief Return a list of pointers to sessions to the specified contact. * If no such session exits, returns 0. */ QList< QPointer<SxeSession> > findSession(const Jid &target); /*! \brief Return a pointer to the specified session. * If such session doesn't exits, returns 0. */ QPointer<SxeSession> findSession(const QString &session); /*! \brief Add a callback for invitations.*/ void addInvitationCallback(bool (*callback)(const Jid &peer, const QList<QString> &features)); /*! \brief Starts a new session negotiation to the specified contact with given list of features.*/ void startNewSession(const Jid &target, const Jid &ownJid, bool groupChat, const QDomDocument &initialDoc, QList<QString> features = QList<QString>()); /*! \brief Join an existing session.*/ void joinSession(const Jid &target, const Jid &ownJid, bool groupChat, const QString &session); /*! \brief Checks that \a jid supports SXE and \a features. */ bool checkSupport(const Jid &jid, const QList<QString> &features); signals: /*! \brief Emitted when \a session has been established.*/ void sessionNegotiated(SxeSession* session); /*! \brief Emitted when \a an invitation to \a jid was declined and joining an alternative session \a session was suggested.*/ void alternativeSession(const Jid &jid, const QString &session); private: /*! \brief Process a message that contains a negotiation element. * Returns a pointer to the new session if negotiation finished. */ QPointer<SxeSession> processNegotiationMessage(const Message &message); /*! \brief Process a negotiation element as a Participant. Appends the appropriate responses to \a response. Returns false iff the negotiation object was deleted. */ bool processNegotiationAsParticipant(const QDomNode &negotiationElement, SxeNegotiation* negotiation, QDomNode response); /*! \brief Process a negotiation element as a Joiner. Appends the appropriate responses to \a response. Returns false iff the negotiation object was deleted. */ bool processNegotiationAsJoiner(const QDomNode &negotiationElement, SxeNegotiation* negotiation, QDomNode response, const Message &message); /*! \brief Returns a pointer to a new session instance.*/ QPointer<SxeSession> createSxeSession(const Jid &target, QString session, const Jid &ownJid, bool groupChat, const QList<QString> &features); /*! \brief Aborts the negotiation of \a session started with \a peer.*/ void abortNegotiation(QString session, const Jid &peer, bool groupChat); /*! \brief Aborts the negotiation with the peer and deletes the session.*/ void abortNegotiation(SxeNegotiation* negotiation); /*! \brief Records the session that the message refers to as a DetectedSession if no entry for the session exists yet.*/ void recordDetectedSession(const Message &message); /*! \brief Returns a pointer to a new negotiation instance based on \a message.*/ SxeNegotiation* createNegotiation(const Message &message); /*! \brief Returns a pointer to a new negotiation instance.*/ SxeNegotiation* createNegotiation(SxeNegotiation::Role role, SxeNegotiation::State state, const QString &sessionId, const Jid &target, const Jid &ownJid, bool groupChat); /*! \brief Returns a pointer to an existing negotiation object of \a session with \a jid.*/ SxeNegotiation* findNegotiation(const Jid &jid, const QString &session); /*! \brief Remove the negotiation object of \a session with \a jid.*/ void removeNegotiation(SxeNegotiation* negotiation); /*! \brief A pointer to the Client to listen to.*/ XMPP::Client* client_; /*! \brief A pointer to the PsiAccount to listen to.*/ PsiAccount* pa_; /*! \brief A list of of established sessions.*/ QList< QPointer<SxeSession> > sessions_; /*! \brief A list of negotiations in process.*/ QMultiHash<QString, SxeNegotiation* > negotiations_; /*! \brief A timer used to remove unfinished negotiations after a timeout.*/ QTimer negotiationTimer_; /*! \brief A list of of detected sessions.*/ QList<DetectedSession> DetectedSessions_; /*! \brief A list of Jids corresponding to self.*/ QList<QString> ownJids_; /*! \brief A list of callbacks used to determine whether an invitation should be accepted.*/ QList<bool (*)(const Jid &peer, const QList<QString> &features)> invitationCallbacks_; /*! \brief A counter used for including a unique id in each sent sxe element.*/ int sxeId_; /*! \brief A list of messages waiting to be sent out.*/ QList<Message> queuedMessages_; private slots: /*! \brief Receives incoming message and determines what to do with them.*/ void messageReceived(const Message &message); /*! \brief Send given whiteboard element to receiver in a message.*/ void sendSxe(QDomElement sxe, const Jid & receiver, bool groupChat); /*! \brief Removes and deletes the session.*/ void removeSession(SxeSession* session); /*! \brief Removes the "detected session" record of the given session.*/ void removeDetectedSession(SxeSession* session); /*! \brief Removes and deletes the possible sessions for the groupchat.*/ void groupChatLeft(const Jid &); /*! \brief Keeps a record of groupchats.*/ void groupChatJoined(const Jid &, const Jid &ownJid); /*! \brief Removes inactive and unfinished session negotiations.*/ void negotiationTimeout(); }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxeedit.cpp������������������������������������������������������������������������0000644�0001750�0001750�00000005235�11305557613�014105� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxeedit.cpp - The base class for SXE edits * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxeedit.h" #include "sxerecordedit.h" //---------------------------------------------------------------------------- // SxeEdit //---------------------------------------------------------------------------- SxeEdit::SxeEdit(const QString rid, bool remote) { rid_ = rid; remote_ = remote; }; SxeEdit::~SxeEdit() { }; bool SxeEdit::remote() const { return remote_; }; QString SxeEdit::rid() const { return rid_; }; bool SxeEdit::isNull() { return null_; } void SxeEdit::nullify() { null_ = true; } bool SxeEdit::overridenBy(const SxeEdit &e) const { if(e.rid() == rid()) { if(e.type() == SxeEdit::Remove) return true; else if(type() == SxeEdit::Record && e.type() == SxeEdit::Record) { const SxeRecordEdit* ep = dynamic_cast<const SxeRecordEdit*>(&e); const SxeRecordEdit* tp = dynamic_cast<const SxeRecordEdit*>(this); return (ep->version() <= tp->version()); } } return false; } bool SxeEdit::operator<(const SxeEdit &other) const { // Can't compare edits to different records if(rid() != other.rid()) { qDebug() << QString("Comparing SxeEdits to %1 an %2.").arg(rid()).arg(other.rid()).toAscii(); return false; } if(type() == other.type()) { // Only Record edits can be unequal with other edits of the same type if(type() == SxeEdit::Record) { const SxeRecordEdit* thisp = dynamic_cast<const SxeRecordEdit*>(this); const SxeRecordEdit* otherp = dynamic_cast<const SxeRecordEdit*>(&other); return (thisp->version() < otherp->version()); } return false; } else { // New < Record, Record < Remove if(type() == SxeEdit::New) return true; if(other.type() == SxeEdit::Remove) return true; return false; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxerecord.h������������������������������������������������������������������������0000644�0001750�0001750�00000013664�11305557613�014110� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxerecord.h - A class for storing the record of an individual node * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDEMETADATA_H #define SXDEMETADATA_H #include "sxerecordedit.h" #include "sxenewedit.h" #include "sxeremoveedit.h" /*! \brief A class for storing the record of an individual node.*/ class SxeRecord : public QObject { Q_OBJECT public: /*! \brief Constructor * Constructs a SxeRecordEdit for \a node. */ SxeRecord(QString rid); /*! \brief Desctructor */ ~SxeRecord(); /*! \brief Returns the node that the record underlies. */ QDomNode node() const; /*! \brief Applies \a edit to the node. Takes ownership of \a edit. */ void apply(QDomDocument &doc, SxeEdit* edit); /*! \brief Returns a list of edits to the node.*/ QList<const SxeEdit*> edits() const; /*! \brief Returns the rid of the node that the record belongs to. */ QString rid() const; /*! \brief Returns the rid of the parent.*/ QString parent() const; /*! \brief Returns the primary-weight of the node.*/ double primaryWeight() const; /*! \brief Returns the version of the record. */ int version() const; /*! \brief Returns the name of the node, if any.*/ QString name() const; /*! \brief Returns the name of the node, if any.*/ QString nameSpace() const; /*! \brief Returns the chdata of the node, if any.*/ QString chdata() const; /*! \brief Returns the processing instruction target, if any.*/ QString processingInstructionTarget() const; /*! \brief Returns the processing instruction data, if any.*/ QString processingInstructionData() const; bool hasSmallerSecondaryWeight(const SxeRecord &other) const; bool operator==(const SxeRecord &other) const; bool operator<(const SxeRecord &other) const; bool operator>(const SxeRecord &other) const; signals: /*! \brief Emitted when the node is first created. */ void nodeToBeAdded(const QDomNode &node, bool remote, const QString &id); /*! \brief Emitted after the node has been placed in the document tree. */ // void nodeAdded(const QDomNode &node, bool remote); /*! \brief Emitted just before the node is removed. */ void nodeToBeRemoved(const QDomNode &node, bool remote); /*! \brief Emitted when the node is removed. */ void nodeRemoved(const QDomNode &node, bool remote); /*! \brief Emitted when primary-weight or parent record is changed. */ void nodeToBeMoved(const QDomNode &node, bool remote); /*! \brief Emitted after the node has been repositioned. */ // void nodeMoved(const QDomNode &node, bool remote); /*! \brief Emitted when the name of the node is changed. */ // void nameChanged(const QDomNode &node, bool remote); /*! \brief Emitted when the chdata of the node is changed. */ void chdataChanged(const QDomNode &node, bool remote); /*! \brief Emitted just before the chdata of the node is changed. */ void chdataToBeChanged(const QDomNode &node, bool remote); /*! \brief Emitted when the target of the processing instruction is changed. */ void processingInstructionTargetChanged(const QDomNode &node, bool remote); /*! \brief Emitted just before the target of the processing instruction is changed. */ void processingInstructionTargetToBeChanged(const QDomNode &node, bool remote); /*! \brief Emitted when the data of the processing instruction is changed. */ void processingInstructionDataChanged(const QDomNode &node, bool remote); /*! \brief Emitted just before the data of the processing instruction is changed. */ void processingInstructionDataToBeChanged(const QDomNode &node, bool remote); /*! \brief Emitted if a conflicting edit of some kind is applied. */ void nodeRemovalRequired(const QDomNode &node); private: /*! \brief Applies SxeNewEdit \a edit to the record.*/ bool applySxeNewEdit(QDomDocument &doc, SxeNewEdit* edit); /*! \brief Applies SxeRemoveEdit \a edit to the record.*/ bool applySxeRemoveEdit(SxeRemoveEdit* edit); /*! \brief Applies SxeRecordEdit \a edit to the record.*/ bool applySxeRecordEdit(SxeRecordEdit* edit); /*! \brief Applies an individual SxeRecordEdit assuming it can be applied to the current version.*/ void processInOrderRecordEdit(const SxeRecordEdit* edit); /*! \brief Reorder the edits_ list and reapply edits as necessary. */ void reorderEdits(); /*! \brief Revert the record to version 0. */ void revertToZero(); /*! \brief Synchronize the state of the DOM node with the fields of the record. */ void updateNode(bool remote); QList<SxeEdit*> edits_; QDomNode node_; QString rid_; int version_; /* The last* variants hold the values that were last put to the DOM node.*/ QString parent_, lastParent_; double primaryWeight_, lastPrimaryWeight_; QString identifier_, lastIdentifier_; QString data_, lastData_; }; #endif ����������������������������������������������������������������������������psi-0.14/src/sxe/sxeremoveedit.cpp������������������������������������������������������������������0000644�0001750�0001750�00000002770�11305557613�015324� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxeremoveedit.cpp - An single SXE edit that removes a node * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxeremoveedit.h" #include "sxesession.h" //---------------------------------------------------------------------------- // SxeRemoveEdit //---------------------------------------------------------------------------- SxeRemoveEdit::SxeRemoveEdit(const QString rid, bool remote) : SxeEdit(rid, remote) { } SxeRemoveEdit::SxeRemoveEdit(const QDomElement &sxeElement, bool remote) : SxeEdit(sxeElement.attribute("rid"), remote) { } SxeEdit::EditType SxeRemoveEdit::type() const { return SxeEdit::Remove; } QDomElement SxeRemoveEdit::xml(QDomDocument &doc) const { QDomElement edit = doc.createElementNS(SXENS, "remove"); edit.setAttribute("rid", rid_); return edit; } ��������psi-0.14/src/sxe/sxesession.h�����������������������������������������������������������������������0000644�0001750�0001750�00000030157�11305557613�014311� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxesession.h - Sxe Session * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDESESSION_H #define SXDESESSION_H #define SXENS "http://jabber.org/protocol/sxe" /* ^^^^ make sure corresponds to NS used for parsing in iris/src/xmpp/xmpp-im/types.cpp ^^^^ */ #include <QObject> #include <QList> #include <QPointer> #include <QDomNode> #include "im.h" #include "psiaccount.h" #include "sxerecord.h" namespace XMPP { class Client; class Jid; class Message; } using namespace XMPP; /*! \brief Class for storing the record and the XML document for an established SXE session.*/ class SxeSession : public QObject { Q_OBJECT // Make SxeManager a friend class so it can emit peerJoined/Left session. friend class SxeManager; private: struct IncomingEdit { QString id; QDomElement xml; }; public: /*! \brief Constructor. * Creates a new session for the specified jid and session identifier. */ SxeSession(const Jid &target, const QString &session, const Jid &ownJid, bool groupChat, bool serverSupport, const QList<QString> &features); /*! \brief Destructor. * Emits sessionEnded() */ ~SxeSession(); /*! \brief Initializes the shared document. Only used if starting a new session; not when joining one. */ void initializeDocument(const QDomDocument &doc); /*! \brief Processes the incoming SXE element and remembers its identifying information.*/ void processIncomingSxeElement(const QDomElement &, const QString &id); /*! \brief Returns a const reference to the target document.*/ const QDomDocument& document() const; /*! \brief Returns true if the target is a groupchat.*/ bool groupChat() const; /*! \brief Returns true if the target is a groupchat.*/ bool serverSupport() const; /*! \brief Returns the target contact's JID.*/ const Jid target() const; /*! \brief Returns the session identifier.*/ const QString session() const; /*! \brief Returns the JID used by the user in the session.*/ const Jid ownJid() const; /*! \brief Returns the session identifier.*/ const QList<QString> features() const; /*! \brief Starts queueing new edits to the document. * Queueing should be started just before sending <document-begin/>. */ QList<const SxeEdit*> startQueueing(); /*! \brief Stop queueing new edits to the document and process the queued ones. * Queueing should be stopped after sending <document-end/>. */ void stopQueueing(); /*! \brief Initializes the document with the prolog of \a doc if provided. * Should be used when <document-begin/> is received when joining. */ void startImporting(const QDomDocument &doc = QDomDocument()); /*! \brief Enters the normal editing mode. * Should be used when <document-end/> is received when joining. */ void stopImporting(); /*! \brief Add the given ID to the list of used IDs for <sxe/> elements.*/ void addUsedSxeId(QString id); /*! \brief Return the list of used IDs for <sxe/> elements.*/ QList<QString> usedSxeIds(); void setUUIDPrefix(const QString uuidPrefix = QString()); /*! \brief Returns a random UUID without enclosing { }. */ static QString generateUUID(); /*! \brief Returns the prolog of the document as a string. */ static QString parseProlog(const QDomDocument &doc); public slots: /*! \brief Ends the session.*/ void endSession(); /*! \brief Inserts or moves the given node so that it is before the reference element. * If the reference element is the null element the element is inserted as the first child of the parent. * Returns \a node if the node was already in the document. Otherwise returns the created node. */ const QDomNode insertNodeBefore(const QDomNode &node, const QDomNode &parent, const QDomNode &referenceNode = QDomNode()); /*! \brief Inserts or moves the given node so that it is after the reference element. * If the reference element is the null element the element is inserted as the last child of the parent. * Returns \a node if the node was already in the document. Otherwise returns the created node. */ const QDomNode insertNodeAfter(const QDomNode &node, const QDomNode &parent, const QDomNode &referenceNode = QDomNode()); /*! \brief Removes the given element.*/ void removeNode(const QDomNode &node); /*! \brief Sets the value of \a attribute of \a node to \a value. */ void setAttribute(const QDomNode &node, const QString &attribute, const QString &value, int from = -1, int n = 0); /*! \brief Sets the value of \a node to \a value. */ void setNodeValue(const QDomNode &node, const QString &value, int from = -1, int n = 0); /*! \brief Sends all queued edits.*/ void flush(); signals: /*! \brief used to pass the new <sxe/> elements to sxemanager.*/ void newSxeElement(const QDomElement &element, const Jid &, bool groupChat); /*! \brief Emitted after each processed SXE element.*/ void documentUpdated(bool remote); /*! \brief Emitted just before \a node is inserted.*/ void nodeToBeAdded(const QDomNode &node, bool remote); /*! \brief Emitted after \a node is inserted.*/ void nodeAdded(const QDomNode &node, bool remote); /*! \brief Emitted just before \a node is moved in the document tree due to processing of an SXE element.*/ void nodeToBeMoved(const QDomNode &node, bool remote); /*! \brief Emitted after \a node has been moved in the document tree due to processing of an SXE element.*/ void nodeMoved(const QDomNode &node, bool remote); /*! \brief Emitted just before \a node is removed from the document tree due to processing of an SXE element.*/ void nodeToBeRemoved(const QDomNode &node, bool remote); /*! \brief Emitted after \a node has been removed from the document tree due to processing of an SXE element.*/ void nodeRemoved(const QDomNode &node, bool remote); /*! \brief Emitted when the name of \a node has been changed. */ // void nameChanged(const QDomNode &node, bool remote); /*! \brief Emitted just before the chdata of \a node is changed. */ void chdataToBeChanged(const QDomNode &node, bool remote); /*! \brief Emitted when the chdata of \a node has been changed. */ void chdataChanged(const QDomNode &node, bool remote); /*! \brief Signals that a peer joined the session.*/ void peerJoinedSession(const Jid &); /*! \brief Signals that a peer left the session.*/ void peerLeftSession(const Jid &); /*! \brief Signals that the session ended and the session is to be deleted.*/ void sessionEnded(SxeSession*); private slots: /*! \brief Adds \a node to the document tree and emits the appropriate public signals. */ void handleNodeToBeAdded(const QDomNode &node, bool remote); /*! \brief Moves \a node in the document tree and emits the appropriate public signals. */ void handleNodeToBeMoved(const QDomNode &node, bool remote); /*! \brief Remove the record entry from the lookup tables and emit the appropriate public signals. */ void handleNodeToBeRemoved(const QDomNode &node, bool remote); /*! \brief Add a node node to the lookup table. */ // void addToLookup(const QDomNode &node, bool, const QString &rid); private: /*! \brief Inserts or moves a node according to it's record (parent and primary-weight). */ void reposition(const QDomNode &node, bool remote); /*! \brief Remove the record associated with \a node from the lookup tables. */ void removeRecord(const QDomNode &node); /*! \brief Remove the item with smaller secondary weight. Returns true iff \a meta1 was removed. */ bool removeSmaller(SxeRecord* meta1, SxeRecord* meta2); /*! \brief Processes an incoming sxe element.*/ bool processSxe(const QDomElement &sxe, const QString &id); /*! \brief Queues an outgoing edit to be sent when flushed.*/ void queueOutgoingEdit(SxeEdit* edit); /*! \brief Creates the record of node with rid \a id. Returns a pointer to it. */ SxeRecord* createRecord(const QString &id); /*! \brief Returns a pointer to the record of node with rid \a id. */ SxeRecord* record(const QString &id); /*! \brief Returns a pointer to the record of \a node. */ SxeRecord* record(const QDomNode &node) const; /*! \brief Generates SxeNewEdits for \a node and its children. * Returns the created node. */ QDomNode generateNewNode(const QDomNode &node, const QString &parent, double primaryWeight); /*! \brief Generates SxeRemoveEdits for \a node and its children. */ void generateRemoves(const QDomNode &node); /*! \brief Recursive helper method for arranging edits for the snapshot. */ void arrangeEdits(QHash<QString, QString> &ridByParent, QList<const SxeEdit*> &output, const QString &iterator); /*! \brief Insert node with the given primaryWeight. * Returns node if the node was already in the document. Otherwise returns the created node. */ const QDomNode insertNode(const QDomNode &node, const QString &parentId, double primaryWeight); /*! \brief Returns a random UUID without enclosing { } and checks that it's not used as a rid. Necessary because you often generate the same UUID on two different processes on the same computer (non-windows). */ QString generateUUIDForSession(); /*! \brief The string identifying the session.*/ QString session_; /*! \brief The target JID.*/ Jid target_; /*! \brief The target JID.*/ Jid ownJid_; /*! \brief The target XML document.*/ QDomDocument document_; /*! \brief Hash used for rid -> SxeRecord* lookups.*/ QHash< QString, SxeRecord* > recordByNodeId_; /*! \brief List of queued incoming sxe elements.*/ QList<IncomingEdit> queuedIncomingEdits_; /*! \brief List of queued outgoing sxe elements.*/ QList<QDomNode> queuedOutgoingEdits_; /*! \brief QDomDocument representing the the contents when queueing_ was set true.*/ QList<SxeEdit*> snapshot_; /*! \brief True if the target is a groupchat.*/ bool groupChat_; /*! \brief True if the session was not established with a server supporting SXE.*/ bool serverSupport_; /*! \brief If true, new sxe elements are queued rather than processed.*/ bool queueing_; /*! \brief True while initial contents of the document are being imported.*/ bool importing_; /*! \brief A list of supported features for the session.*/ QList<QString> features_; /*! \brief Identifiers for the <sxe/> elements that have been processed already.*/ QList<QString> usedSxeIds_; /*! \brief A unique id is generated as "uuidPrefix.counter".*/ QString uuidPrefix_; int uuidMaxPostfix_; /*! \brief The main DOM document.*/ QDomDocument doc_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxerecord.cpp����������������������������������������������������������������������0000644�0001750�0001750�00000026634�11305557613�014444� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxerecord.cpp - A class for storing the record of an individual node * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxerecord.h" static bool referencedEditLessThan(const SxeEdit* e1, const SxeEdit* e2) { return *e1 < *e2; } //---------------------------------------------------------------------------- // SxeRecord //---------------------------------------------------------------------------- SxeRecord::SxeRecord(QString rid) { rid_ = rid; }; SxeRecord::~SxeRecord() { while(!edits_.isEmpty()) delete edits_.takeFirst(); }; QDomNode SxeRecord::node() const { return node_; } void SxeRecord::apply(QDomDocument &doc, SxeEdit* edit) { if(edit->rid() == rid()) { if(edit->type() == SxeEdit::New) applySxeNewEdit(doc, dynamic_cast<SxeNewEdit*>(edit)); else if (edit->type() == SxeEdit::Remove) applySxeRemoveEdit(dynamic_cast<SxeRemoveEdit*>(edit)); else if (edit->type() == SxeEdit::Record) applySxeRecordEdit(dynamic_cast<SxeRecordEdit*>(edit)); } else { qDebug() << QString("Tried to apply an edit meant for %1 to %2.").arg(edit->rid()).arg(rid()).toAscii(); } } QList<const SxeEdit*> SxeRecord::edits() const { QList<const SxeEdit*> edits; foreach(SxeEdit* e, edits_) { edits.append(e); } return edits; }; bool SxeRecord::applySxeNewEdit(QDomDocument &doc, SxeNewEdit* edit) { if(!(edits_.size() == 0 && node_.isNull())) { qDebug("Someone's not behaving! Tried to apply a SxeNewEdit to an existing node."); emit nodeRemovalRequired(node_); return false; } // create the new node if(edit->nodeType() == QDomNode::ElementNode) { if(edit->nameSpace().isEmpty()) node_ = doc.createElement(edit->name()); else node_ = doc.createElementNS(edit->nameSpace(), edit->name()); } else if(edit->nodeType() == QDomNode::AttributeNode) { if(edit->nameSpace().isEmpty()) node_ = doc.createAttribute(edit->name()); else node_ = doc.createAttributeNS(edit->nameSpace(), edit->name()); node_.toAttr().setValue(edit->chdata()); } else if(edit->nodeType() == QDomNode::TextNode) { node_ = doc.createTextNode(edit->chdata()); } else if(edit->nodeType() == QDomNode::CommentNode) { node_ = doc.createComment(edit->chdata()); } else if(edit->nodeType() == QDomNode::ProcessingInstructionNode) { node_ = doc.createProcessingInstruction(edit->processingInstructionTarget(), edit->processingInstructionData()); } else return false; edits_ += edit; revertToZero(); emit nodeToBeAdded(node_, edit->remote(), edit->rid()); lastParent_ = parent(); lastPrimaryWeight_ = primaryWeight(); return true; } void SxeRecord::revertToZero() { #ifndef NDEBUG if (edits_[0]->type() != SxeEdit::New) qDebug() << QString("First edit is of type %1!").arg(edits_[0]->type()); #endif const SxeNewEdit* edit = dynamic_cast<const SxeNewEdit*>(edits_[0]); parent_ = edit->parent(); primaryWeight_ = edit->primaryWeight(); identifier_ = edit->name(); data_ = edit->chdata(); } bool SxeRecord::applySxeRemoveEdit(SxeRemoveEdit* edit) { if(!node_.isNull()) { emit nodeToBeRemoved(node_, edit->remote()); if(node_.isAttr()) { QDomNode parent = node_.parentNode(); while(!parent.isElement() && !parent.isNull()) parent = parent.parentNode(); if(!parent.isNull()) { parent.toElement().removeAttributeNode(node_.toAttr()); emit nodeRemoved(node_, edit->remote()); } // else, the attr hadn't been added to the doc yet. } else { node_.parentNode().removeChild(node_); emit nodeRemoved(node_, edit->remote()); } edits_ += edit; // delete the record deleteLater(); } return true; } bool SxeRecord::applySxeRecordEdit(SxeRecordEdit* edit) { if(!node_.isNull() && edits_.size() > 0) { if(edit->version() == version() + 1 && !edits_.last()->overridenBy(*edit)) { // process the "in order" edit edits_ += edit; processInOrderRecordEdit(edit); } else { edits_ += edit; reorderEdits(); } updateNode(edit->remote()); return true; } return false; } void SxeRecord::processInOrderRecordEdit(const SxeRecordEdit* edit) { foreach(SxeRecordEdit::Key key, edit->keys()) { if(key == SxeRecordEdit::Parent && edit->value(key) != parent()) { parent_ = edit->value(key); } else if(key == SxeRecordEdit::PrimaryWeight && edit->value(key).toDouble() != primaryWeight()) { primaryWeight_ = edit->value(key).toDouble(); } else if(key == SxeRecordEdit::Name && edit->value(key) != name()) { identifier_ = edit->value(key); } else if(key == SxeRecordEdit::ProcessingInstructionTarget && edit->value(key) != processingInstructionTarget()) { identifier_ = edit->value(key); } else if(key == SxeRecordEdit::Chdata || key == SxeRecordEdit::ProcessingInstructionData) { // Check for partial replacements QList<SxeRecordEdit::Key> keys = edit->keys(); if(keys.contains(SxeRecordEdit::ReplaceFrom) && keys.contains(SxeRecordEdit::ReplaceN)) { // 'replacefrom' & 'replacen' exist, do they contain integers? bool ok1, ok2; int from = edit->value(SxeRecordEdit::ReplaceFrom).toInt(&ok1); int n = edit->value(SxeRecordEdit::ReplaceN).toInt(&ok2); if(ok1 && ok2 && from >= 0 && n >= 0 && from + n <= data_.length()) { // Do partial replace if the range makes sense data_.replace(from, n, edit->value(key)); } else { if(!ok1) qDebug() << QString("Could not convert 'replacefrom' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceFrom)); if(!ok2) qDebug() << QString("Could not convert 'replacen' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceN)); if(from < 0) qDebug() << QString("'replacefrom' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceFrom)); if(n < 0) qDebug() << QString("'replacen' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceN)); if(from + n > data_.length()) qDebug() << QString("from (%1) + n (%2) > data_.length() (%3).").arg(from).arg(n).arg(data_.length()); } } else { data_ = edit->value(key); } } } } void SxeRecord::reorderEdits() { qSort(edits_.begin(), edits_.end(), referencedEditLessThan); revertToZero(); // Apply all the valid record edits for(int i = 1; i < edits_.size(); i++) { if (edits_[i]->type() == SxeEdit::Record) { SxeRecordEdit* edit = dynamic_cast<SxeRecordEdit*>(edits_[i]); // Check that the version matches and that the next edit doesn't override it. if (i == edit->version() && (i+1 == edits_.size() || !edit->overridenBy(*edits_[i+1]))) processInOrderRecordEdit(edit); else if (edit->version() <= i) edit->nullify(); // There's no way the edit could be applied anymore } else { qDebug() << QString("Edit of type %1 at %2!").arg(edits_[i]->type()).arg(i).toAscii(); } } } void SxeRecord::updateNode(bool remote) { if(parent_ != lastParent_ || primaryWeight_ != lastPrimaryWeight_) emit nodeToBeMoved(node_, remote); if(identifier_ != lastIdentifier_) { if ((node_.isElement() || node_.isAttr()) && node_.nodeName() != name()) { // emit nameToBeChanged(node_, remote); // TODO: update the name somehow // emit nameChanged(node_, remote); } else if(node_.isProcessingInstruction()) { // emit processingInstructionTargetToBeChanged(node_, remote); // TODO: figure out a way to change the target // will probably need to recreate the pi // emit processingInstructionTargetChanged(node_, remote); } } if(data_ != lastData_) { // qDebug() << QString("Setting '%1' to \"%2\"").arg(node_.nodeName()).arg(data_).toAscii(); if((node_.isText() || node_.isAttr() || node_.isComment())) { emit chdataToBeChanged(node_, remote); node_.setNodeValue(data_); emit chdataChanged(node_, remote); } else if(node_.isProcessingInstruction()) { emit processingInstructionDataToBeChanged(node_, remote); node_.toProcessingInstruction().setData(data_); emit processingInstructionDataChanged(node_, remote); } } } QString SxeRecord::rid() const { return rid_; }; QString SxeRecord::parent() const { return parent_; } double SxeRecord::primaryWeight() const { return primaryWeight_; } int SxeRecord::version() const { return edits_.size() - 1; } QString SxeRecord::name() const { return identifier_; } QString SxeRecord::nameSpace() const { if(node_.isNull()) return QString(); else return node_.namespaceURI(); } QString SxeRecord::chdata() const { return data_; } QString SxeRecord::processingInstructionTarget() const { return identifier_; } QString SxeRecord::processingInstructionData() const { return data_; } bool SxeRecord::hasSmallerSecondaryWeight(const SxeRecord &other) const { // compare the "secondary weight" (the id's) QString selfid = rid(); QString otherid = other.rid(); for(int i = 0; i < selfid.length() && i < otherid.length(); i++) { if(selfid[i].unicode() < otherid[i].unicode()) return true; else if(selfid[i].unicode() > otherid[i].unicode()) return false; } // if no difference was found. one must be shorter return (selfid.length() < otherid.length()); } bool SxeRecord::operator==(const SxeRecord &other) const { return rid() == other.rid(); } bool SxeRecord::operator<(const SxeRecord &other) const { if(other == *this) return false; if(primaryWeight() < other.primaryWeight()) return true; else if(primaryWeight() == other.primaryWeight()) { return hasSmallerSecondaryWeight(other); } else return false; } bool SxeRecord::operator>(const SxeRecord &other) const { return !(*this == other || *this < other); } ����������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxerecordedit.cpp������������������������������������������������������������������0000644�0001750�0001750�00000006600�11305557613�015301� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxeremoveedit.cpp - An single SXE edit that changes a node * Copyright (C) 2006 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "sxerecordedit.h" #include "sxesession.h" //---------------------------------------------------------------------------- // SxeRecordEdit //---------------------------------------------------------------------------- SxeRecordEdit::SxeRecordEdit(const QString rid, int version, QHash<Key, QString> changes, bool remote) : SxeEdit(rid, remote) { version_ = version; changes_ = changes; } SxeRecordEdit::SxeRecordEdit(const QDomElement &sxeElement, bool remote) : SxeEdit(sxeElement.attribute("rid"), remote) { version_ = sxeElement.attribute("version").toInt(); if(sxeElement.hasAttribute("parent")) changes_[Parent] = sxeElement.attribute("parent"); if(sxeElement.hasAttribute("primary-weight")) changes_[PrimaryWeight] = sxeElement.attribute("primary-weight"); if(sxeElement.hasAttribute("name")) changes_[Name] = sxeElement.attribute("name"); if(sxeElement.hasAttribute("chdata")) changes_[Chdata] = sxeElement.attribute("chdata"); if(sxeElement.hasAttribute("replacefrom")) changes_[ReplaceFrom] = sxeElement.attribute("replacefrom"); if(sxeElement.hasAttribute("replacen")) changes_[ReplaceN] = sxeElement.attribute("replacen"); if(sxeElement.hasAttribute("pitarget")) changes_[ProcessingInstructionTarget] = sxeElement.attribute("pitarget"); if(sxeElement.hasAttribute("pidata")) changes_[ProcessingInstructionData] = sxeElement.attribute("pidata"); } SxeEdit::EditType SxeRecordEdit::type() const { return SxeEdit::Record; } QDomElement SxeRecordEdit::xml(QDomDocument &doc) const { QDomElement edit = doc.createElementNS(SXENS, "set"); edit.setAttribute("rid", rid_); edit.setAttribute("version", version_); foreach(Key key, changes_.keys()) edit.setAttribute(keyToString(key), changes_[key]); return edit; } int SxeRecordEdit::version() const { return version_; } QList<SxeRecordEdit::Key> SxeRecordEdit::keys() const { return changes_.keys(); } QString SxeRecordEdit::value(Key key) const { return changes_.value(key); } QString SxeRecordEdit::keyToString(Key key) { if(key == Parent) return "parent"; if(key == PrimaryWeight) return "primary-weight"; if(key == Name) return "name"; if(key == Chdata) return "chdata"; if(key == ReplaceFrom) return "replacefrom"; if(key == ReplaceN) return "replacen"; if(key == ProcessingInstructionTarget) return "pitarget"; if(key == ProcessingInstructionData) return "pidata"; return ""; } void SxeRecordEdit::nullify() { SxeEdit::nullify(); changes_.clear(); } ��������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxeremoveedit.h��������������������������������������������������������������������0000644�0001750�0001750�00000003077�11305557613�014772� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxeedit.h - A class for SXE edits that remove a node * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDEREMOVEEDIT_H #define SXDEREMOVEEDIT_H #include "sxeedit.h" /*! \brief A class used for storing SXE edits that remove nodes in the undo stacks and in the queue of outgoing edits.*/ class SxeRemoveEdit : public SxeEdit { public: /*! \brief Constructor * Constructs a SxeRemoveEdit for \a node. */ SxeRemoveEdit(const QString rid, bool remote = false); /*! \brief Constructor * Parses a SxeRemoveEdit from \a sxeElement. */ SxeRemoveEdit(const QDomElement &sxeElement, bool remote = true); /*! \brief The type of edit.*/ SxeEdit::EditType type() const; /*! \brief The XML (the SXE) representing the edit.*/ QDomElement xml(QDomDocument &doc) const; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/sxe/sxeedit.h��������������������������������������������������������������������������0000644�0001750�0001750�00000004532�11305557613�013551� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * sxeedit.h - The base class for SXE edits * Copyright (C) 2007 Joonas Govenius * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SXDEEDIT_H #define SXDEEDIT_H #include <QString> #include <QDomNode> /*! \brief A class used for storing SXE edits in the undo stacks and in the queue of outgoing edits.*/ class SxeEdit { public: /*! \brief Describes which kind of edit the object represents.*/ enum EditType {New, Record, Remove}; /*! \brief Constructor * Constructs an SxeEdit for a node with \a rid. */ SxeEdit(const QString rid, bool remote); virtual ~SxeEdit(); /*! \brief Indicates whether the edit is from a remote client.*/ bool remote() const; /*! \brief The rid of the edit.*/ QString rid() const; /*! \brief The type of edit.*/ virtual EditType type() const = 0; /*! \brief The XML (the SXE) representing the edit.*/ virtual QDomElement xml(QDomDocument &doc) const = 0; /*! \brief A null edit is a no-op.*/ bool isNull(); /*! \brief Turns the edit into a no-op.*/ virtual void nullify(); /*! \brief Returns true if \a e renders the SxeEdit ineffective * (e.g. a SxeRemoveEdit will make a SxeNewEdit ineffective). */ bool overridenBy(const SxeEdit &e) const; bool operator<(const SxeEdit &other) const; protected: /*! \brief The node id of the target.*/ QString rid_; /*! \brief Indicates whether the edit is from a remote client.*/ bool remote_; /*! \brief Indicates whether the edit has been nullified.*/ bool null_; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/vcardphotodlg.h������������������������������������������������������������������������0000644�0001750�0001750�00000001067�11305557613�014145� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef VCARDPHOTODLG_H #define VCARDPHOTODLG_H #include <QLabel> #include <QDialog> #include <QToolBar> class ShowPhotoDlg : public QDialog { Q_OBJECT public: ShowPhotoDlg(QWidget *parent, QPixmap &pixmap); private: QDialog *showPhotoDlg; QLabel *label; QPixmap photoPixmap; QToolBar *toolbar; QAction *saveAct; QAction *restoreAct; bool initSize; void createActions(); void updatePhoto(const QSize size); protected: void resizeEvent(QResizeEvent *event); void wheelEvent(QWheelEvent * event); private slots: void save(); void restore(); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psichatdlg.h���������������������������������������������������������������������������0000644�0001750�0001750�00000003753�11305557613�013433� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef PSICHATDLG_H #define PSICHATDLG_H #include "minicmd.h" #include "mcmdsimplesite.h" #include "mcmdmanager.h" #include "chatdlg.h" #include "mcmdcompletion.h" #include "ui_chatdlg.h" class IconAction; class PsiChatDlg : public ChatDlg { Q_OBJECT public: PsiChatDlg(const Jid& jid, PsiAccount* account, TabManager* tabManager); protected: // reimplemented void contextMenuEvent(QContextMenuEvent *); void doSend(); bool eventFilter(QObject *obj, QEvent *event); private: void setContactToolTip(QString text); private slots: void toggleSmallChat(); void doClearButton(); void doMiniCmd(); void buildMenu(); void updateCounter(); void updateIdentityVisibility(); void updateCountVisibility(); // reimplemented void chatEditCreated(); private: void initToolBar(); void initToolButtons(); // reimplemented void initUi(); void capsChanged(); bool isEncryptionEnabled() const; void contactUpdated(UserListItem* u, int status, const QString& statusString); void updateAvatar(); void optionsUpdate(); void updatePGP(); void setPGPEnabled(bool enabled); void activated(); void setLooks(); void setShortcuts(); QString colorString(bool local, SpooledType spooled) const; void appendSysMsg(const QString &); void appendEmoteMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt); void appendNormalMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt); void appendMessageFields(const Message& m); void updateLastMsgTime(QDateTime t); ChatView* chatView() const; ChatEdit* chatEdit() const; private: Ui::ChatDlg ui_; QMenu* pm_settings_; IconAction* act_clear_; IconAction* act_history_; IconAction* act_info_; IconAction* act_pgp_; IconAction* act_icon_; IconAction* act_file_; IconAction* act_compact_; IconAction* act_voice_; QAction *act_mini_cmd_; MCmdManager mCmdManager_; MCmdSimpleSite mCmdSite_; MCmdTabCompletion tabCompletion; bool smallChat_; QDateTime lastMsgTime_; class ChatDlgMCmdProvider; }; #endif ���������������������psi-0.14/src/psicon.h�������������������������������������������������������������������������������0000644�0001750�0001750�00000011030�11305557613�012567� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psicon.h - core of Psi * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSICON_H #define PSICON_H #include <QList> #include "profiles.h" #include "psiactions.h" #include "tabbablewidget.h" using namespace XMPP; class PsiCon; class PsiAccount; class PsiEvent; class ContactView; class AutoUpdater; class EventDlg; class UserListItem; class EDB; class EDBItem; class ProxyManager; class QMenuBar; class FileTransDlg; class IconSelectPopup; class QThread; class PsiActionList; class PsiToolBar; class TabDlg; class AccountsComboBox; class ChatDlg; class TuneController; class PsiContactList; class Q3DockWindow; namespace OpenPGP { class Engine; } namespace XMPP { class Jid; } class PsiCon : public QObject { Q_OBJECT public: enum { QuitProgram, QuitProfile }; PsiCon(); ~PsiCon(); bool init(); void deinit(); PsiContactList* contactList() const; ContactView *contactView() const; EDB *edb() const; TuneController* tuneController() const; ProxyManager *proxy() const; FileTransDlg *ftdlg() const; QWidget *dialogFind(const char *className); void dialogRegister(QWidget *w); void dialogUnregister(QWidget *w); QMenuBar* defaultMenuBar() const; void createAccount(const QString &name, const Jid &j="", const QString &pass="", bool opt_host=false, const QString &host="", int port=5222, bool legacy_ssl_probe = true, UserAccount::SSLFlag ssl=UserAccount::SSL_Auto, QString proxy="", const QString &tlsOverrideDomain="", const QByteArray &tlsOverrideCert=QByteArray()); PsiAccount *createAccount(const UserAccount &); //void createAccount(const QString &, const QString &host="", int port=5222, bool ssl=false, const QString &user="", const QString &pass=""); void removeAccount(PsiAccount *); void playSound(const QString &); AccountsComboBox *accountsComboBox(QWidget *parent=0, bool online_only = false); QStringList recentGCList() const; void recentGCAdd(const QString &); QStringList recentBrowseList() const; void recentBrowseAdd(const QString &); const QStringList & recentNodeList() const; void recentNodeAdd(const QString &); EventDlg *createEventDlg(const QString &, PsiAccount *); void updateContactGlobal(PsiAccount *, const Jid &); PsiActionList *actionList() const; IconSelectPopup *iconSelectPopup() const; void processEvent(PsiEvent*, ActivationType activationType); bool haveAutoUpdater() const; signals: void quit(int); void accountAdded(PsiAccount *); void accountUpdated(PsiAccount *); void accountRemoved(PsiAccount *); void accountCountChanged(); void accountActivityChanged(); void emitOptionsUpdate(); public slots: void setGlobalStatus(const Status &, bool withPriority = false); void doToolbars(); void checkAccountsEmpty(); public slots: void doSleep(); void doWakeup(); void closeProgram(); void changeProfile(); void doManageAccounts(); void doGroupChat(); void doNewBlankMessage(); void doOptions(); void doFileTransDlg(); void statusMenuChanged(int); void pa_updatedActivity(); void pa_updatedAccount(); void slotApplyOptions(); void queueChanged(); void recvNextEvent(); void setStatusFromDialog(const XMPP::Status &, bool withPriority); void setStatusFromCommandline(const QString &status, const QString &message); void proxy_settingsChanged(); void updateMainwinStatus(); void openUri(const QString &uri); void openUri(const QUrl &uri); void raiseMainwin(); private slots: void saveAccounts(); void saveCapabilities(); void optionChanged(const QString& option); void forceSavePreferences(); void startBounce(); private: class Private; Private *d; void deleteAllDialogs(); void s5b_init(); void updateS5BServerAddresses(); void setShortcuts(); friend class PsiAccount; // FIXME void promptUserToCreateAccount(); QString optionsFile() const; void registerCaps(const QString& ext, const QStringList& features); friend class EventQueue; int getId(); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/conf_iris.pri��������������������������������������������������������������������������0000644�0001750�0001750�00000001263�11305557613�013621� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../conf.pri) windows:include(../conf_windows.pri) # don't build iris apps CONFIG += no_tests # use qca from psi if necessary qca-static { DEFINES += QCA_STATIC INCLUDEPATH += $$PWD/../third-party/qca/qca/include/QtCrypto } else { CONFIG += crypto } # use zlib from psi if necessary psi-zip { INCLUDEPATH += $$PWD/libpsi/tools/zip/minizip/win32 } mac { # Universal binaries qc_universal:contains(QT_CONFIG,x86):contains(QT_CONFIG,ppc) { CONFIG += x86 ppc QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk # comment this out, iris already specifies 10.3, and i don't # think this has anything to do with universal, does it? #QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/urlbookmark.cpp������������������������������������������������������������������������0000644�0001750�0001750�00000003233�11305557613�014165� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * urlbookmark.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QDomDocument> #include <QDomElement> #include "urlbookmark.h" URLBookmark::URLBookmark(const QString& name, const QString& url) : name_(name), url_(url) { } URLBookmark::URLBookmark(const QDomElement& el) { fromXml(el); } const QString& URLBookmark::name() const { return name_; } const QString& URLBookmark::url() const { return url_; } bool URLBookmark::isNull() const { return name_.isEmpty() && url_.isEmpty(); } void URLBookmark::fromXml(const QDomElement& e) { name_ = e.attribute("name"); url_ = e.attribute("url"); } QDomElement URLBookmark::toXml(QDomDocument& doc) const { QDomElement e = doc.createElement("url"); if (!name_.isEmpty()) e.setAttribute("name",name_); if (!url_.isEmpty()) e.setAttribute("url",url_); return e; } bool URLBookmark::operator==(const URLBookmark & other) const { return name_ == other.name_ && url_ == other.url_; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pubsubsubscription.cpp�����������������������������������������������������������������0000644�0001750�0001750�00000004621�11305557613�015604� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * pubsubsubscription.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QDomDocument> #include <QDomElement> #include <QString> #include "pubsubsubscription.h" PubSubSubscription::PubSubSubscription() { } PubSubSubscription::PubSubSubscription(const QDomElement& e) { fromXml(e); } const QString& PubSubSubscription::jid() const { return jid_; } const QString& PubSubSubscription::node() const { return node_; } PubSubSubscription::State PubSubSubscription::state() const { return state_; } bool PubSubSubscription::isNull() const { return jid_.isEmpty() && node_.isEmpty(); } void PubSubSubscription::fromXml(const QDomElement& e) { if (e.tagName() != "subscription") return; node_ = e.attribute("node"); jid_ = e.attribute("jid"); QString sub = e.attribute("subscription"); if (sub == "none") state_ = None; else if (sub == "pending") state_ = Pending; else if (sub == "unconfigured") state_ = Unconfigured; else if (sub == "subscribed") state_ = Subscribed; } QDomElement PubSubSubscription::toXml(QDomDocument& doc) const { QDomElement s = doc.createElement("subscription"); s.setAttribute("node",node_); if (state_ == None) s.setAttribute("subscription","none"); else if (state_ == Pending) s.setAttribute("subscription","pending"); else if (state_ == Unconfigured) s.setAttribute("subscription","unconfigured"); else if (state_ == Subscribed) s.setAttribute("subscription","subscribed"); return s; } bool PubSubSubscription::operator==(const PubSubSubscription& s) const { return jid() == s.jid() && node() == s.node() && state() == s.state(); } bool PubSubSubscription::operator!=(const PubSubSubscription& s) const { return !((*this) == s); } ���������������������������������������������������������������������������������������������������������������psi-0.14/src/mucjoindlg.cpp�������������������������������������������������������������������������0000644�0001750�0001750�00000013341�11305557613�013771� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * mucjoindlg.cpp * Copyright (C) 2001-2008 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QString> #include <QStringList> #include <QMessageBox> #include "jidutil.h" #include "psicon.h" #include "accountscombobox.h" #include "psiaccount.h" #include "mucjoindlg.h" #include "psicontactlist.h" #include "groupchatdlg.h" MUCJoinDlg::MUCJoinDlg(PsiCon* psi, PsiAccount* pa) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); ui_.setupUi(this); controller_ = psi; account_ = 0; controller_->dialogRegister(this); ui_.ck_history->setChecked(true); ui_.ck_history->hide(); joinButton_ = ui_.buttonBox->addButton(tr("&Join"), QDialogButtonBox::AcceptRole); joinButton_->setDefault(true); updateIdentity(pa); ui_.cb_ident->setController(controller_); ui_.cb_ident->setOnlineOnly(true); connect(ui_.cb_ident, SIGNAL(activated(PsiAccount *)), SLOT(updateIdentity(PsiAccount *))); ui_.cb_ident->setAccount(pa); connect(controller_, SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility())); updateIdentityVisibility(); foreach(QString j, controller_->recentGCList()) { Jid jid(j); QString s = tr("%1 on %2").arg(jid.resource()).arg(JIDUtil::toString(jid, false)); ui_.cb_recent->addItem(s); ui_.cb_recent->setItemData(ui_.cb_recent->count()-1, QVariant(j)); } setWindowTitle(CAP(windowTitle())); connect(ui_.cb_recent, SIGNAL(activated(int)), SLOT(recent_activated(int))); if (!ui_.cb_recent->count()) { ui_.cb_recent->setEnabled(false); ui_.le_host->setFocus(); } else { recent_activated(0); } setWidgetsEnabled(true); adjustSize(); } MUCJoinDlg::~MUCJoinDlg() { if (controller_) controller_->dialogUnregister(this); if (account_) account_->dialogUnregister(this); } void MUCJoinDlg::done(int r) { if (ui_.busy->isActive()) { //int n = QMessageBox::information(0, tr("Warning"), tr("Are you sure you want to cancel joining groupchat?"), tr("&Yes"), tr("&No")); //if(n != 0) // return; account_->groupChatLeave(jid_.domain(), jid_.node()); } QDialog::done(r); } void MUCJoinDlg::updateIdentity(PsiAccount *pa) { if (account_) disconnect(account_, SIGNAL(disconnected()), this, SLOT(pa_disconnected())); account_ = pa; joinButton_->setEnabled(account_); if (!account_) { ui_.busy->stop(); return; } connect(account_, SIGNAL(disconnected()), this, SLOT(pa_disconnected())); } void MUCJoinDlg::updateIdentityVisibility() { bool visible = controller_->contactList()->enabledAccounts().count() > 1; ui_.cb_ident->setVisible(visible); ui_.lb_identity->setVisible(visible); } void MUCJoinDlg::pa_disconnected() { if (ui_.busy->isActive()) { ui_.busy->stop(); } } void MUCJoinDlg::recent_activated(int x) { Jid jid(ui_.cb_recent->itemData(x).toString()); if (jid.full().isEmpty()) return; ui_.le_host->setText(jid.domain()); ui_.le_room->setText(jid.node()); ui_.le_nick->setText(jid.resource()); } void MUCJoinDlg::doJoin() { if (!account_ || !account_->checkConnected(this)) return; QString host = ui_.le_host->text(); QString room = ui_.le_room->text(); QString nick = ui_.le_nick->text(); QString pass = ui_.le_pass->text(); if (host.isEmpty() || room.isEmpty() || nick.isEmpty()) { QMessageBox::information(this, tr("Error"), tr("You must fill out the fields in order to join.")); return; } Jid j = room + '@' + host + '/' + nick; if (!j.isValid()) { QMessageBox::information(this, tr("Error"), tr("You entered an invalid room name.")); return; } GCMainDlg *gc = account_->findDialog<GCMainDlg*>(j.bare()); if (gc) { gc->bringToFront(); if (gc->isInactive()) { gc->reactivate(); } joined(); return; } if (!account_->groupChatJoin(host, room, nick, pass, !ui_.ck_history->isChecked())) { QMessageBox::information(this, tr("Error"), tr("You are in or joining this room already!")); return; } controller_->dialogUnregister(this); jid_ = room + '@' + host + '/' + nick; account_->dialogRegister(this, jid_); setWidgetsEnabled(false); ui_.busy->start(); } void MUCJoinDlg::setWidgetsEnabled(bool enabled) { ui_.cb_ident->setEnabled(enabled); ui_.cb_recent->setEnabled(enabled && ui_.cb_recent->count() > 0); ui_.gb_info->setEnabled(enabled); joinButton_->setEnabled(enabled); } void MUCJoinDlg::joined() { controller_->recentGCAdd(jid_.full()); ui_.busy->stop(); closeDialogs(this); deleteLater(); } void MUCJoinDlg::error(int, const QString &str) { ui_.busy->stop(); setWidgetsEnabled(true); account_->dialogUnregister(this); controller_->dialogRegister(this); QMessageBox* msg = new QMessageBox(QMessageBox::Information, tr("Error"), tr("Unable to join groupchat.\nReason: %1").arg(str), QMessageBox::Ok, this); msg->setAttribute(Qt::WA_DeleteOnClose, true); msg->setModal(false); msg->show(); } void MUCJoinDlg::setJid(const Jid& mucJid) { ui_.le_host->setText(mucJid.domain()); ui_.le_room->setText(mucJid.node()); } void MUCJoinDlg::setNick(const QString nick) { ui_.le_nick->setText(nick); } void MUCJoinDlg::setPassword(const QString& password) { ui_.le_pass->setText(password); } void MUCJoinDlg::accept() { doJoin(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/discodlg.h�����������������������������������������������������������������������������0000644�0001750�0001750�00000002551�11305557613�013074� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * discodlg.h - main dialog for the Service Discovery protocol * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef DISCODLG_H #define DISCODLG_H #include <QDialog> #include "ui_disco.h" #include "xmpp_jid.h" class PsiAccount; class QString; using namespace XMPP; class DiscoDlg : public QDialog, public Ui::Disco { Q_OBJECT public: DiscoDlg(PsiAccount *, const Jid &, const QString &node = QString::null); ~DiscoDlg(); void doDisco(QString host = QString::null, QString node = QString::null); signals: void featureActivated(QString feature, Jid jid, QString node); public: class Private; friend class Private; private: Private *d; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/mucaffiliationsview.cpp����������������������������������������������������������������0000644�0001750�0001750�00000004655�11305557613�015716� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * mucaffiliationsview.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QHeaderView> #include "xmpp_jid.h" #include "mucaffiliationsview.h" MUCAffiliationsView::MUCAffiliationsView(QWidget* parent) : QTreeView(parent) { setRootIsDecorated(false); header()->hide(); setItemsExpandable(false); setDragEnabled(true); setAcceptDrops(true); setDropIndicatorShown(true); } bool MUCAffiliationsView::addToCurrent(const QString& j) { QModelIndex index = currentIndex(); if (!index.isValid()) return false; if (index.parent().isValid()) index = index.parent(); if (!index.parent().isValid()) { XMPP::Jid jid(j); if (!jid.isValid()) return false; // TODO: Check if the user is already in the list int row = model()->rowCount(index); model()->insertRows(row,1,index); model()->setData(model()->index(row,0,index),QVariant(jid.bare())); return true; } return false; } void MUCAffiliationsView::removeCurrent() { QModelIndex index = currentIndex(); if (index.isValid() && index.parent().isValid()) { model()->removeRows(index.row(),1,index.parent()); } } void MUCAffiliationsView::currentChanged(const QModelIndex& current, const QModelIndex& previous) { Q_UNUSED(previous); // Commenting these optimizations, since they cause too much trouble //bool add_before = previous.isValid() && (model()->flags(previous) & Qt::ItemIsEnabled); //bool remove_before = previous.isValid() && previous.parent().isValid(); bool add_after = current.isValid() && (model()->flags(current) & Qt::ItemIsEnabled); bool remove_after = current.isValid() && current.parent().isValid(); //if (add_before != add_after) emit addEnabled(add_after); //if (remove_before != remove_after) emit removeEnabled(remove_after); } �����������������������������������������������������������������������������������psi-0.14/src/serverlistquerier.cpp������������������������������������������������������������������0000644�0001750�0001750�00000005755�11305557613�015447� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * serverlistquerier.cpp * Copyright (C) 2007 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QHttp> #include <QUrl> #include <QDomDocument> #include <QDomElement> #include <QDomNodeList> #include "serverlistquerier.h" #define SERVERLIST_SERVER "xmpp.org" #define SERVERLIST_PORT 80 #define SERVERLIST_PATH "/services/services.xml" #define SERVERLIST_MAX_REDIRECT 5 ServerListQuerier::ServerListQuerier(QObject* parent) : QObject(parent) { http_ = new QHttp(SERVERLIST_SERVER, SERVERLIST_PORT, this); connect(http_,SIGNAL(requestFinished(int,bool)),SLOT(get_finished(int,bool))); } void ServerListQuerier::getList() { redirectCount_ = 0; http_->get(SERVERLIST_PATH); } void ServerListQuerier::get_finished(int, bool err) { const QHttpResponseHeader response = http_->lastResponse(); if (err) { emit error(http_->errorString()); } else { if(response.statusCode() == 200) { // Parse the XML file QDomDocument doc; if (!doc.setContent(http_->readAll())) { emit error(tr("Unable to parse server list")); return; } // Fill the list QStringList servers; QDomNodeList items = doc.elementsByTagName("item"); for (int i = 0; i < items.count(); i++) { QString jid = items.item(i).toElement().attribute("jid"); if (!jid.isEmpty()) { servers.push_back(jid); } } emit listReceived(servers); } else if(response.statusCode() == 301 || response.statusCode() == 302) { // handle redirections: // 301 = moved permanently // 302 = found if (redirectCount_ >= SERVERLIST_MAX_REDIRECT) { emit error(tr("Maximum redirect count reached")); return; } QString newUrl = response.value("Location"); QUrl url = newUrl; if (!url.scheme().isEmpty()) { if (url.scheme() != "http") { emit error(tr("Redirect to protocol '%1' not supported").arg(url.scheme())); return; } if (url.host().isEmpty()) { emit error(tr("Cannot redirect to empty host")); return; } http_->disconnect(this); http_->deleteLater(); http_ = new QHttp(url.host(), url.port(80), this); connect(http_,SIGNAL(requestFinished(int,bool)),SLOT(get_finished(int,bool))); } ++redirectCount_; http_->get(newUrl); } else { emit error(tr("Unexpected HTTP status code: %1").arg(response.statusCode())); } } } �������������������psi-0.14/src/groupchatdlg.ui������������������������������������������������������������������������0000644�0001750�0001750�00000021071�11305557613�014153� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <class>GroupChatDlg</class> <widget class="QWidget" name="GroupChatDlg" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>633</width> <height>428</height> </rect> </property> <property name="windowTitle" > <string/> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>4</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="ChatSplitter" name="vsplitter" > <property name="orientation" > <enum>Qt::Vertical</enum> </property> <widget class="QFrame" name="topFrame" > <property name="sizePolicy" > <sizepolicy> <hsizetype>5</hsizetype> <vsizetype>3</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="frameShape" > <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow" > <enum>QFrame::Plain</enum> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>4</number> </property> <item> <widget class="QWidget" native="1" name="widget" > <property name="sizePolicy" > <sizepolicy> <hsizetype>5</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>4</number> </property> <item> <widget class="QPushButton" name="pb_topic" > <property name="text" > <string>Topic:</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="le_topic" > <property name="readOnly" > <bool>true</bool> </property> </widget> </item> <item> <widget class="AccountLabel" name="lb_ident" > <property name="sizePolicy" > <sizepolicy> <hsizetype>1</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text" > <string>AccountLabel</string> </property> </widget> </item> <item> <widget class="QToolButton" name="tb_find" > <property name="toolTip" > <string>Select icon</string> </property> <property name="text" > <string/> </property> <property name="iconSize" > <size> <width>16</width> <height>16</height> </size> </property> <property name="popupMode" > <enum>QToolButton::InstantPopup</enum> </property> </widget> </item> <item> <widget class="QToolButton" name="tb_emoticons" > <property name="toolTip" > <string>Select icon</string> </property> <property name="text" > <string/> </property> <property name="iconSize" > <size> <width>16</width> <height>16</height> </size> </property> <property name="popupMode" > <enum>QToolButton::InstantPopup</enum> </property> </widget> </item> <item> <widget class="QToolButton" name="tb_actions" > <property name="toolTip" > <string>Actions</string> </property> <property name="text" > <string/> </property> <property name="iconSize" > <size> <width>16</width> <height>16</height> </size> </property> <property name="popupMode" > <enum>QToolButton::InstantPopup</enum> </property> <property name="arrowType" > <enum>Qt::DownArrow</enum> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QSplitter" name="hsplitter" > <property name="sizePolicy" > <sizepolicy> <hsizetype>7</hsizetype> <vsizetype>5</vsizetype> <horstretch>0</horstretch> <verstretch>1</verstretch> </sizepolicy> </property> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <widget class="ChatView" name="log" > <property name="sizePolicy" > <sizepolicy> <hsizetype>7</hsizetype> <vsizetype>3</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="focusPolicy" > <enum>Qt::NoFocus</enum> </property> <property name="readOnly" > <bool>true</bool> </property> </widget> <widget class="GCUserView" name="lv_users" > <property name="minimumSize" > <size> <width>20</width> <height>0</height> </size> </property> </widget> </widget> </item> </layout> </widget> <widget class="QFrame" name="bottomFrame" > <property name="sizePolicy" > <sizepolicy> <hsizetype>5</hsizetype> <vsizetype>4</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="frameShape" > <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow" > <enum>QFrame::Plain</enum> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QToolBar" name="toolbar" > <property name="sizePolicy" > <sizepolicy> <hsizetype>5</hsizetype> <vsizetype>4</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="mini_prompt"> <property name="font" > <font> <weight>75</weight> <bold>true</bold> </font> </property> </widget> </item> <item> <widget class="ChatEditProxy" name="mle" > <property name="sizePolicy" > <sizepolicy> <hsizetype>7</hsizetype> <vsizetype>5</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> </item> </layout> </item> </layout> </widget> </widget> </item> </layout> </widget> <customwidgets> <customwidget> <class>AccountLabel</class> <extends>QLabel</extends> <header>accountlabel.h</header> </customwidget> <customwidget> <class>Q3ListView</class> <extends>Q3Frame</extends> <header>q3listview.h</header> </customwidget> <customwidget> <class>GCUserView</class> <extends>Q3ListView</extends> <header>gcuserview.h</header> </customwidget> <customwidget> <class>ChatSplitter</class> <extends>QSplitter</extends> <header>chatsplitter.h</header> </customwidget> <customwidget> <class>ChatView</class> <extends>QTextEdit</extends> <header>msgmle.h</header> </customwidget> <customwidget> <class>ChatEditProxy</class> <extends>QTextEdit</extends> <header>chateditproxy.h</header> </customwidget> </customwidgets> <resources/> <connections/> </ui> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/rosteritemexchangetask.cpp�������������������������������������������������������������0000644�0001750�0001750�00000004677�11305557613�016435� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * rosteritemexchangetask.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_xmlcommon.h" #include "xmpp_client.h" #include "xmpp_liveroster.h" #include "rosteritemexchangetask.h" RosterItemExchangeTask::RosterItemExchangeTask(Task* parent) : Task(parent), ignoreNonRoster_(false) { } bool RosterItemExchangeTask::take(const QDomElement& e) { for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/rosterx") { Jid from(e.attribute("from")); if (client()->roster().find(from,false) == client()->roster().end() && ignoreNonRoster_) { // Send a not-authorized error QDomElement iq = createIQ(doc(), "error", e.attribute("from"), e.attribute("id")); QDomElement error = doc()->createElement("error"); error.setAttribute("type","cancel"); QDomElement notauthorized = doc()->createElement("not-authorized"); notauthorized.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-stanzas"); error.appendChild(notauthorized); iq.appendChild(error); send(iq); setError(e); return true; } // Parse all items RosterExchangeItems items; for(QDomNode m = i.firstChild(); !m.isNull(); m = m.nextSibling()) { QDomElement j = m.toElement(); if(j.isNull()) continue; RosterExchangeItem it(j); if (!it.isNull()) items += it; } // Return success QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); send(iq); emit rosterItemExchange(from,items); setSuccess(true); return true; } } return false; } void RosterItemExchangeTask::setIgnoreNonRoster(bool b) { ignoreNonRoster_ = b; } �����������������������������������������������������������������psi-0.14/src/psiiconset.h���������������������������������������������������������������������������0000644�0001750�0001750�00000004576�11305557613�013475� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psiiconset.h - the Psi iconset class * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIICONSET_H #define PSIICONSET_H #include <QMap> #include "iconset.h" class PsiEvent; class UserListItem; namespace XMPP { class Status; class Jid; } class PsiIconset : public QObject { Q_OBJECT public: static PsiIconset* instance(); bool loadSystem(); void reloadRoster(); bool loadAll(); QHash<QString, Iconset*> roster; QList<Iconset*> emoticons; const Iconset &system() const; void stripFirstAnimFrame(Iconset *); static void removeAnimation(Iconset *); PsiIcon *event2icon(PsiEvent *); // these two can possibly fail (and return 0) PsiIcon *statusPtr(int); PsiIcon *statusPtr(const XMPP::Status &); // these two return empty PsiIcon on failure and are safe PsiIcon status(int); PsiIcon status(const XMPP::Status &); // JID-enabled status functions PsiIcon *statusPtr(const XMPP::Jid &, int); PsiIcon *statusPtr(const XMPP::Jid &, const XMPP::Status &); PsiIcon status(const XMPP::Jid &, int); PsiIcon status(const XMPP::Jid &, const XMPP::Status &); // functions to get status icon by transport name PsiIcon *transportStatusPtr(QString name, int); PsiIcon *transportStatusPtr(QString name, const XMPP::Status &); PsiIcon transportStatus(QString name, int); PsiIcon transportStatus(QString name, const XMPP::Status &); PsiIcon *statusPtr(UserListItem *); PsiIcon status(UserListItem *); signals: void emoticonsChanged(); private slots: void optionChanged(const QString& option); private: PsiIconset(); ~PsiIconset(); class Private; Private *d; static PsiIconset* instance_; bool loadRoster(); void loadEmoticons(); }; #endif ����������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/eventdb.h������������������������������������������������������������������������������0000644�0001750�0001750�00000010626�11305557613�012735� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * eventdb.h - asynchronous I/O event database * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef EVENTDB_H #define EVENTDB_H #include <qobject.h> #include <qtimer.h> #include <qfile.h> #include "xmpp_jid.h" class PsiEvent; class EDBItem { public: EDBItem(PsiEvent *, const QString &id, const QString &nextId, const QString &prevId); ~EDBItem(); PsiEvent *event() const; const QString & id() const; const QString & nextId() const; const QString & prevId() const; private: QString v_id, v_prevId, v_nextId; PsiEvent *e; }; class EDBResult : public QList<EDBItem*> { public: EDBResult() : autoDelete_(false) {} ~EDBResult() { if (autoDelete_) { qDeleteAll(*this); } } void setAutoDelete(bool autoDelete) { autoDelete_ = autoDelete; } private: bool autoDelete_; }; class EDB; class EDBHandle : public QObject { Q_OBJECT public: enum { Read, Write, Erase }; EDBHandle(EDB *); ~EDBHandle(); // operations void getLatest(const XMPP::Jid &, int len); void getOldest(const XMPP::Jid &, int len); void get(const XMPP::Jid &jid, const QString &id, int direction, int len); void find(const QString &, const XMPP::Jid &, const QString &id, int direction); void append(const XMPP::Jid &, PsiEvent *); void erase(const XMPP::Jid &); bool busy() const; const EDBResult *result() const; bool writeSuccess() const; int lastRequestType() const; signals: void finished(); private: class Private; Private *d; friend class EDB; void edb_resultReady(EDBResult *); void edb_writeFinished(bool); int listeningFor() const; }; class EDB : public QObject { Q_OBJECT public: enum { Forward, Backward }; EDB(); virtual ~EDB()=0; protected: int genUniqueId() const; virtual int getLatest(const XMPP::Jid &, int len)=0; virtual int getOldest(const XMPP::Jid &, int len)=0; virtual int get(const XMPP::Jid &jid, const QString &id, int direction, int len)=0; virtual int append(const XMPP::Jid &, PsiEvent *)=0; virtual int find(const QString &, const XMPP::Jid &, const QString &id, int direction)=0; virtual int erase(const XMPP::Jid &)=0; void resultReady(int, EDBResult *); void writeFinished(int, bool); private: class Private; Private *d; friend class EDBHandle; void reg(EDBHandle *); void unreg(EDBHandle *); int op_getLatest(const XMPP::Jid &, int len); int op_getOldest(const XMPP::Jid &, int len); int op_get(const XMPP::Jid &, const QString &id, int direction, int len); int op_find(const QString &, const XMPP::Jid &, const QString &id, int direction); int op_append(const XMPP::Jid &, PsiEvent *); int op_erase(const XMPP::Jid &); }; class EDBFlatFile : public EDB { Q_OBJECT public: EDBFlatFile(); ~EDBFlatFile(); int getLatest(const XMPP::Jid &, int len); int getOldest(const XMPP::Jid &, int len); int get(const XMPP::Jid &jid, const QString &id, int direction, int len); int find(const QString &, const XMPP::Jid &, const QString &id, int direction); int append(const XMPP::Jid &, PsiEvent *); int erase(const XMPP::Jid &); class File; private slots: void performRequests(); void file_timeout(); private: class Private; Private *d; File *findFile(const XMPP::Jid &) const; File *ensureFile(const XMPP::Jid &); bool deleteFile(const XMPP::Jid &); }; class EDBFlatFile::File : public QObject { Q_OBJECT public: File(const XMPP::Jid &_j); ~File(); int total() const; void touch(); PsiEvent *get(int); bool append(PsiEvent *); static QString jidToFileName(const XMPP::Jid &); signals: void timeout(); private slots: void timer_timeout(); public: XMPP::Jid j; QString fname; QFile f; bool valid; QTimer *t; class Private; Private *d; private: PsiEvent *lineToEvent(const QString &); QString eventToLine(PsiEvent *); void ensureIndex(); }; #endif ����������������������������������������������������������������������������������������������������������psi-0.14/src/accountreg.ui��������������������������������������������������������������������������0000644�0001750�0001750�00000020715�11305557613�013626� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <class>AccountReg</class> <widget class="QDialog" name="AccountReg" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>384</width> <height>339</height> </rect> </property> <property name="windowTitle" > <string>Register Account</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QStackedWidget" name="sw_register" > <property name="currentIndex" > <number>0</number> </property> <widget class="QWidget" name="page_server" > <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QGroupBox" name="gb_server" > <property name="title" > <string>Server</string> </property> <layout class="QGridLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item row="0" column="0" colspan="2"> <widget class="QLabel" name="lb_jid" > <property name="text" > <string>Please enter the name of the server you wish to register with:</string> </property> <property name="wordWrap" > <bool>true</bool> </property> </widget> </item> <item row="1" column="0" colspan="2"> <widget class="UpdatingComboBox" name="le_server" > <property name="minimumSize" > <size> <width>200</width> <height>0</height> </size> </property> <property name="editable"> <bool>true</bool> </property> </widget> </item> <item row="2" column="0" colspan="2"> <widget class="QLabel" name="lb_example" > <property name="enabled" > <bool>false</bool> </property> <property name="text" > <string>Example: capulet.com</string> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="gb_connection" > <property name="title" > <string>Connection settings</string> </property> <layout class="QVBoxLayout" > <property name="margin" > <number>9</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QCheckBox" name="ck_host" > <property name="text" > <string>Manually Specify Server Host/Port:</string> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="lb_host" > <property name="text" > <string>Host:</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="le_host" /> </item> <item> <widget class="QLabel" name="lb_port" > <property name="text" > <string>Port:</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="le_port" > <property name="minimumSize" > <size> <width>56</width> <height>0</height> </size> </property> <property name="maximumSize" > <size> <width>56</width> <height>32767</height> </size> </property> </widget> </item> </layout> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="lb_ssl" > <property name="text" > <string>Encrypt connection:</string> </property> </widget> </item> <item> <widget class="QComboBox" name="cb_ssl" /> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>151</width> <height>20</height> </size> </property> </spacer> </item> </layout> </item> <item> <widget class="QCheckBox" name="ck_legacy_ssl_probe" > <property name="text" > <string>Probe legacy SSL port</string> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="QLabel" name="lb_proxy" > <property name="text" > <string>Proxy:</string> </property> </widget> </item> <item> <widget class="QLabel" name="lb_proxychooser" > <property name="text" > <string>proxychooser</string> </property> </widget> </item> </layout> </item> </layout> </widget> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeType" > <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" > <size> <width>20</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> <widget class="QWidget" name="page_fields" /> </widget> </item> <item> <widget class="Line" name="line2" > <property name="frameShape" > <enum>QFrame::HLine</enum> </property> <property name="frameShadow" > <enum>QFrame::Sunken</enum> </property> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout" > <property name="margin" > <number>0</number> </property> <property name="spacing" > <number>6</number> </property> <item> <widget class="BusyWidget" name="busy" /> </item> <item> <spacer> <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" > <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="pb_cancel" > <property name="text" > <string>&Cancel</string> </property> </widget> </item> <item> <widget class="QPushButton" name="pb_next" > <property name="text" > <string>&Next</string> </property> <property name="default" > <bool>true</bool> </property> </widget> </item> </layout> </item> </layout> </widget> <layoutdefault spacing="6" margin="11" /> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <tabstops> <tabstop>le_server</tabstop> <tabstop>ck_host</tabstop> <tabstop>le_host</tabstop> <tabstop>le_port</tabstop> </tabstops> <resources/> <connections/> </ui> ���������������������������������������������������psi-0.14/src/accountmodifydlg.h���������������������������������������������������������������������0000644�0001750�0001750�00000004223�11305557613�014635� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * accountmodifydlg.h * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACCOUNTMODIFYDLG_H #define ACCOUNTMODIFYDLG_H #include <QDialog> #include <QtCrypto> #include "privacylistmodel.h" #include "privacylistblockedmodel.h" #include "ui_accountmodify.h" #include "profiles.h" class PsiAccount; class QWidget; class PsiCon; class ProxyChooser; class AccountModifyDlg : public QDialog, public Ui::AccountModify { Q_OBJECT public: AccountModifyDlg(PsiCon *,QWidget *parent=0); AccountModifyDlg(PsiAccount *, QWidget *parent=0); ~AccountModifyDlg(); void setPassword(const QString &); const UserAccount& account() const { return acc; } protected: void init(); private slots: void hostToggled(bool); void sslActivated(int); void detailsVCard(); void detailsChangePW(); void save(); //void pgpToggled(bool); void chooseKey(); void clearKey(); void tabChanged(int); // Privacy void privacyClicked(); void updatePrivacyTab(); void setPrivacyTabEnabled(bool b); void addBlockClicked(); void removeBlockClicked(); void updateBlockedContacts(const PrivacyList&); void getDefaultList_error(); void changeList_error(); private: PsiCon *psi; PsiAccount *pa; ProxyChooser *pc; QCA::PGPKey key; UserAccount acc; // Privacy PrivacyListModel privacyModel; PrivacyListBlockedModel privacyBlockedModel; bool privacyInitialized; void updateUserID(); void setKeyID(bool b, const QString &s=""); bool checkSSL(); }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/ahcommanddlg.h�������������������������������������������������������������������������0000644�0001750�0001750�00000003105�11305557613�013716� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ahcommanddlg.h - Ad-Hoc Command Dialog * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHCOMMANDDLG_H #define AHCOMMANDDLG_H #include <QDialog> #include <QList> #include "xmpp_jid.h" namespace XMPP { class Client; } class PsiAccount; class QObject; class QComboBox; class QPushButton; class BusyWidget; typedef struct { QString jid, node, name; } AHCommandItem; #include "ui_ahcommanddlg.h" class AHCommandDlg : public QDialog { Q_OBJECT public: AHCommandDlg(PsiAccount*, const XMPP::Jid& receiver); static void executeCommand(XMPP::Client*, const XMPP::Jid& j, const QString &node); protected slots: void refreshCommands(); void listReceived(); void executeCommand(); void commandExecuted(); private: Ui::AHCommandDlg ui_; PsiAccount* pa_; XMPP::Jid receiver_; QList<AHCommandItem> commands_; QPushButton* pb_close; QPushButton* pb_execute; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psievent.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000050121�11305557613�013470� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psievent.h - events * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psievent.h" #include <qdom.h> #include <QTextStream> #include <QList> #include "psicon.h" #include "psiaccount.h" #include "xmpp_xmlcommon.h" #include "filetransfer.h" #include "applicationinfo.h" #include "psicontactlist.h" #include "atomicxmlfile.h" #include "psioptions.h" #include "avcall/avcall.h" // FIXME renames those const int eventPriorityHeadline = 0; const int eventPriorityChat = 1; const int eventPriorityMessage = 1; const int eventPriorityAuth = 2; //const int eventPriorityFile = 3; const int eventPriorityFile = 2; const int eventPriorityRosterExchange = 0; // LEGOPTFIXME: was uninitialised using namespace XMPP; using namespace XMLHelper; //---------------------------------------------------------------------------- // DummyStream //---------------------------------------------------------------------------- class DummyStream : public Stream { public: QDomDocument & doc() const { return v_doc; } QString baseNS() const { return "jabber:client"; } bool old() const { return false; } void close() { } bool stanzaAvailable() const { return false; } Stanza read() { return Stanza(); } void write(const Stanza &) { } int errorCondition() const { return 0; } QString errorText() const { return QString::null; } QDomElement errorAppSpec() const { return v_doc.documentElement(); } private: static QDomDocument v_doc; }; QDomDocument DummyStream::v_doc; //---------------------------------------------------------------------------- // PsiEvent //---------------------------------------------------------------------------- PsiEvent::PsiEvent(PsiAccount *acc) { v_originLocal = false; v_late = false; v_account = acc; } PsiEvent::PsiEvent(const PsiEvent &from) : QObject() { v_originLocal = from.v_originLocal; v_late = from.v_late; v_ts = from.v_ts; v_jid = from.v_jid; v_account = from.v_account; } PsiEvent::~PsiEvent() { } XMPP::Jid PsiEvent::jid() const { return v_jid; } void PsiEvent::setJid(const XMPP::Jid &j) { v_jid = j; } PsiAccount *PsiEvent::account() const { return v_account; } bool PsiEvent::originLocal() const { return v_originLocal; } bool PsiEvent::late() const { return v_late; } QDateTime PsiEvent::timeStamp() const { return v_ts; } void PsiEvent::setOriginLocal(bool b) { v_originLocal = b; } void PsiEvent::setLate(bool b) { v_late = b; } void PsiEvent::setTimeStamp(const QDateTime &t) { v_ts = t; } QDomElement PsiEvent::toXml(QDomDocument *doc) const { QDomElement e = doc->createElement("event"); e.setAttribute("type", metaObject()->className()); e.appendChild( textTag(*doc, "originLocal", v_originLocal) ); e.appendChild( textTag(*doc, "late", v_late) ); e.appendChild( textTag(*doc, "ts", v_ts.toString( Qt::ISODate )) ); if ( !v_jid.full().isEmpty() ) e.appendChild( textTag(*doc, "jid", v_jid.full()) ); if ( v_account ) e.appendChild( textTag(*doc, "account", v_account->name()) ); return e; } bool PsiEvent::fromXml(PsiCon *psi, PsiAccount *account, const QDomElement *e) { if ( e->tagName() != "event" ) return false; if ( e->attribute("type") != metaObject()->className() ) return false; readBoolEntry(*e, "originLocal", &v_originLocal); readBoolEntry(*e, "late", &v_late); v_ts = QDateTime::fromString(subTagText(*e, "ts"), Qt::ISODate); v_jid = Jid( subTagText(*e, "jid") ); if ( account ) { v_account = account; } else if ( hasSubTag(*e, "account") ) { QString accName = subTagText(*e, "account"); foreach(PsiAccount* account, psi->contactList()->accounts()) { if ( account->name() == accName ) { v_account = account; break; } } } return true; } int PsiEvent::priority() const { return EventPriorityDontCare; } QString PsiEvent::description() const { return QString(); } PsiEvent *PsiEvent::copy() const { return 0; } //---------------------------------------------------------------------------- // MessageEvent //---------------------------------------------------------------------------- MessageEvent::MessageEvent(PsiAccount *acc) : PsiEvent(acc) { v_sentToChatWindow = false; } MessageEvent::MessageEvent(const XMPP::Message &m, PsiAccount *acc) : PsiEvent(acc) { v_sentToChatWindow = false; setMessage(m); } MessageEvent::MessageEvent(const MessageEvent &from) : PsiEvent(from), v_m(from.v_m), v_sentToChatWindow(from.v_sentToChatWindow) { } MessageEvent::~MessageEvent() { } int MessageEvent::type() const { return Message; } Jid MessageEvent::from() const { return v_m.from(); } void MessageEvent::setFrom(const Jid &j) { v_m.setFrom(j); } const QString& MessageEvent::nick() const { return v_m.nick(); } void MessageEvent::setNick(const QString &nick) { v_m.setNick(nick); } bool MessageEvent::sentToChatWindow() const { return v_sentToChatWindow; } const XMPP::Message & MessageEvent::message() const { return v_m; } void MessageEvent::setSentToChatWindow(bool b) { v_sentToChatWindow = b; } void MessageEvent::setMessage(const XMPP::Message &m) { v_m = m; setTimeStamp ( v_m.timeStamp() ); setLate ( v_m.spooled() ); } QDomElement MessageEvent::toXml(QDomDocument *doc) const { QDomElement e = PsiEvent::toXml(doc); DummyStream stream; Stanza s = v_m.toStanza(&stream); e.appendChild( s.element() ); return e; } bool MessageEvent::fromXml(PsiCon *psi, PsiAccount *account, const QDomElement *e) { if ( !PsiEvent::fromXml(psi, account, e) ) return false; bool found = false; QDomElement msg = findSubTag(*e, "message", &found); if ( found ) { DummyStream stream; Stanza s = stream.createStanza(addCorrectNS(msg)); v_m.fromStanza(s); // if message was not spooled, it will be initialized with the // current datetime. we want to reset it back to the original // receive time if (!v_m.timeStamp().secsTo(QDateTime::currentDateTime())) v_m.setTimeStamp(timeStamp()); return true; } return false; } int MessageEvent::priority() const { if ( v_m.type() == "headline" ) return eventPriorityHeadline; else if ( v_m.type() == "chat" ) return eventPriorityChat; return eventPriorityMessage; } QString MessageEvent::description() const { QStringList result; if (!v_m.subject().isEmpty()) result << v_m.subject(); if (!v_m.body().isEmpty()) result << v_m.body(); foreach(Url url, v_m.urlList()) { QString text = url.url(); if (!url.desc().isEmpty()) text += QString("(%1)").arg(url.desc()); result << text; } return result.join("\n"); } PsiEvent *MessageEvent::copy() const { return new MessageEvent( *this ); } //---------------------------------------------------------------------------- // AuthEvent //---------------------------------------------------------------------------- AuthEvent::AuthEvent(const Jid &j, const QString &authType, PsiAccount *acc) : PsiEvent(acc) { v_from = j; v_at = authType; } AuthEvent::AuthEvent(const AuthEvent &from) : PsiEvent(from), v_from(from.v_from), v_at(from.v_at) { } AuthEvent::~AuthEvent() { } int AuthEvent::type() const { return Auth; } Jid AuthEvent::from() const { return v_from; } void AuthEvent::setFrom(const Jid &j) { v_from = j; } const QString& AuthEvent::nick() const { return v_nick; } void AuthEvent::setNick(const QString &nick) { v_nick = nick; } QString AuthEvent::authType() const { return v_at; } QDomElement AuthEvent::toXml(QDomDocument *doc) const { QDomElement e = PsiEvent::toXml(doc); e.appendChild( textTag(*doc, "from", v_from.full()) ); e.appendChild( textTag(*doc, "authType", v_at) ); e.appendChild( textTag(*doc, "nick", v_nick) ); return e; } bool AuthEvent::fromXml(PsiCon *psi, PsiAccount *account, const QDomElement *e) { if ( !PsiEvent::fromXml(psi, account, e) ) return false; v_from = Jid( subTagText(*e, "from") ); v_at = subTagText(*e, "authType"); v_nick = subTagText(*e, "nick"); return false; } int AuthEvent::priority() const { return eventPriorityAuth; } QString AuthEvent::description() const { QString result; if (authType() == "subscribe") result = tr("This user wants to subscribe to your presence."); else if (authType() == "subscribed") result = tr("You are now authorized."); else if (authType() == "unsubscribed") result = tr("Your authorization has been removed!"); else Q_ASSERT(false); return result; } PsiEvent *AuthEvent::copy() const { return new AuthEvent( *this ); } //---------------------------------------------------------------------------- // FileEvent //---------------------------------------------------------------------------- FileEvent::FileEvent(const Jid &j, FileTransfer *_ft, PsiAccount *acc) :PsiEvent(acc) { v_from = j; ft = _ft; } FileEvent::~FileEvent() { delete ft; } FileEvent::FileEvent(const FileEvent &from) : PsiEvent(from.account()) { v_from = from.v_from; ft = from.ft->copy(); } int FileEvent::priority() const { return eventPriorityFile; } Jid FileEvent::from() const { return v_from; } void FileEvent::setFrom(const Jid &j) { v_from = j; } FileTransfer *FileEvent::takeFileTransfer() { FileTransfer *_ft = ft; ft = 0; return _ft; } QString FileEvent::description() const { return tr("This user wants to send you a file."); } PsiEvent *FileEvent::copy() const { return new FileEvent( *this ); } //---------------------------------------------------------------------------- // HttpAuthEvent //---------------------------------------------------------------------------- HttpAuthEvent::HttpAuthEvent(const PsiHttpAuthRequest &req, PsiAccount *acc) :MessageEvent(acc), v_req(req) { const XMPP::Stanza &s = req.stanza(); XMPP::Message m; if ( s.kind() == XMPP::Stanza::Message ) { m.fromStanza(s); } else { m.setFrom(s.from()); m.setTimeStamp(QDateTime::currentDateTime()); m.setHttpAuthRequest(HttpAuthRequest(s.element().elementsByTagNameNS("http://jabber.org/protocol/http-auth", "confirm").item(0).toElement())); } setMessage(m); } HttpAuthEvent::~HttpAuthEvent() { } QString HttpAuthEvent::description() const { return tr("HTTP Authentication Request"); } //---------------------------------------------------------------------------- // RosterExchangeEvent //---------------------------------------------------------------------------- RosterExchangeEvent::RosterExchangeEvent(const Jid &j, const RosterExchangeItems& i, const QString& text, PsiAccount *acc) :PsiEvent(acc) { v_from = j; v_items = i; v_text = text; } int RosterExchangeEvent::priority() const { return eventPriorityRosterExchange; } Jid RosterExchangeEvent::from() const { return v_from; } void RosterExchangeEvent::setFrom(const Jid &j) { v_from = j; } const RosterExchangeItems& RosterExchangeEvent::rosterExchangeItems() const { return v_items; } void RosterExchangeEvent::setRosterExchangeItems(const RosterExchangeItems& i) { v_items = i; } const QString& RosterExchangeEvent::text() const { return v_text; } void RosterExchangeEvent::setText(const QString& text) { v_text = text; } QString RosterExchangeEvent::description() const { return tr("This user wants to modify your roster."); } //---------------------------------------------------------------------------- // Status //---------------------------------------------------------------------------- /*StatusEvent::StatusEvent(const Jid &j, const XMPP::Status& s, PsiAccount *acc) :PsiEvent(acc) { v_from = j; v_status = s; } int StatusEvent::priority() const { return eventPriorityChat; } Jid StatusEvent::from() const { return v_from; } void StatusEvent::setFrom(const Jid &j) { v_from = j; } const XMPP::Status& StatusEvent::status() const { return v_status; } void StatusEvent::setStatus(const XMPP::Status& s) { v_status = s; }*/ //---------------------------------------------------------------------------- // AvCallEvent //---------------------------------------------------------------------------- AvCallEvent::AvCallEvent(const XMPP::Jid &j, AvCall *_sess, PsiAccount *acc) :PsiEvent(acc) { v_from = j; sess = _sess; } AvCallEvent::AvCallEvent(const AvCallEvent &from) :PsiEvent(from.account()) { v_from = from.v_from; sess = new AvCall(*from.sess); } AvCallEvent::~AvCallEvent() { delete sess; } XMPP::Jid AvCallEvent::from() const { return v_from; } void AvCallEvent::setFrom(const XMPP::Jid &j) { v_from = j; } AvCall *AvCallEvent::takeAvCall() { AvCall *_sess = sess; sess = 0; return _sess; } int AvCallEvent::priority() const { return eventPriorityFile; // FIXME } QString AvCallEvent::description() const { return tr("The user is calling you."); } PsiEvent *AvCallEvent::copy() const { return new AvCallEvent(*this); } //---------------------------------------------------------------------------- // EventItem //---------------------------------------------------------------------------- EventItem::EventItem(PsiEvent *_e, int i) { e = _e; v_id = i; } EventItem::EventItem(const EventItem &from) { e = from.e->copy(); v_id = from.v_id; } EventItem::~EventItem() { } int EventItem::id() const { return v_id; } PsiEvent* EventItem::event() const { return e; } //---------------------------------------------------------------------------- // EventQueue //---------------------------------------------------------------------------- class EventQueue::Private { public: Private() { } QList<EventItem*> list; PsiCon *psi; PsiAccount *account; }; EventQueue::EventQueue(PsiAccount *account) { d = new Private(); d->account = account; d->psi = account->psi(); } EventQueue::EventQueue(const EventQueue &from) : QObject() { d = new Private(); *this = from; } EventQueue::~EventQueue() { delete d; } int EventQueue::nextId() const { if (d->list.isEmpty()) return -1; EventItem *i = d->list.first(); if(!i) return -1; return i->id(); } int EventQueue::count() const { return d->list.count(); } int EventQueue::count(const Jid &j, bool compareRes) const { int total = 0; foreach(EventItem *i, d->list) { Jid j2(i->event()->jid()); if(j.compare(j2, compareRes)) ++total; } return total; } void EventQueue::enqueue(PsiEvent *e) { EventItem *i = new EventItem(e, d->psi->getId()); int prior = e->priority(); bool found = false; // skip all with higher or equal priority foreach(EventItem *ei, d->list) { if (ei && ei->event()->priority() < prior ) { d->list.insert(d->list.indexOf(ei), i); found = true; break; } } // everything else if ( !found ) d->list.append(i); emit queueChanged(); } void EventQueue::dequeue(PsiEvent *e) { if ( !e ) return; foreach(EventItem *i, d->list) { if ( e == i->event() ) { d->list.removeAll(i); emit queueChanged(); delete i; return; } } } PsiEvent *EventQueue::dequeue(const Jid &j, bool compareRes) { foreach(EventItem *i, d->list) { PsiEvent *e = i->event(); Jid j2(e->jid()); if(j.compare(j2, compareRes)) { d->list.removeAll(i); emit queueChanged(); delete i; return e; } } return 0; } PsiEvent *EventQueue::peek(const Jid &j, bool compareRes) const { foreach(EventItem *i, d->list) { PsiEvent *e = i->event(); Jid j2(e->jid()); if(j.compare(j2, compareRes)) { return e; } } return 0; } PsiEvent *EventQueue::dequeueNext() { if (d->list.isEmpty()) return 0; EventItem *i = d->list.first(); if(!i) return 0; PsiEvent *e = i->event(); d->list.removeAll(i); emit queueChanged(); delete i; return e; } PsiEvent *EventQueue::peekNext() const { if (d->list.isEmpty()) return 0; EventItem *i = d->list.first(); if(!i) return 0; return i->event(); } PsiEvent *EventQueue::peekFirstChat(const Jid &j, bool compareRes) const { foreach(EventItem *i, d->list) { PsiEvent *e = i->event(); if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; if(j.compare(me->from(), compareRes) && me->message().type() == "chat") return e; } } return 0; } bool EventQueue::hasChats(const Jid &j, bool compareRes) const { return (peekFirstChat(j, compareRes) ? true: false); } // this function extracts all chats from the queue, and returns a list of queue positions void EventQueue::extractChats(QList<PsiEvent*> *el, const Jid &j, bool compareRes) { bool changed = false; for(QList<EventItem*>::Iterator it = d->list.begin(); it != d->list.end();) { PsiEvent *e = (*it)->event(); if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; if(j.compare(me->from(), compareRes) && me->message().type() == "chat") { el->append(me); EventItem* ei = *it; it = d->list.erase(it); delete ei; changed = true; continue; } } ++it; } if ( changed ) emit queueChanged(); } // this function extracts all messages from the queue, and returns a list of them void EventQueue::extractMessages(QList<PsiEvent*> *el) { bool changed = false; for(QList<EventItem*>::Iterator it = d->list.begin(); it != d->list.end();) { PsiEvent *e = (*it)->event(); if(e->type() == PsiEvent::Message) { el->append(e); EventItem* ei = *it; it = d->list.erase(it); delete ei; changed = true; continue; } ++it; } if ( changed ) emit queueChanged(); } void EventQueue::printContent() const { foreach(EventItem *i, d->list) { PsiEvent *e = i->event(); printf(" %d: (%d) from=[%s] jid=[%s]\n", i->id(), e->type(), qPrintable(e->from().full()), qPrintable(e->jid().full())); } } void EventQueue::clear() { while(!d->list.isEmpty()) delete d->list.takeFirst(); emit queueChanged(); } // this function removes all events associated with the input jid void EventQueue::clear(const Jid &j, bool compareRes) { bool changed = false; for(QList<EventItem*>::Iterator it = d->list.begin(); it != d->list.end();) { PsiEvent *e = (*it)->event(); Jid j2(e->jid()); if(j.compare(j2, compareRes)) { EventItem* ei = *it; it = d->list.erase(it); delete ei; changed = true; } else ++it; } if ( changed ) emit queueChanged(); } EventQueue &EventQueue::operator= (const EventQueue &from) { while(!d->list.isEmpty()) delete d->list.takeFirst(); d->psi = from.d->psi; foreach(EventItem *i, from.d->list) { PsiEvent *e = i->event(); enqueue( e->copy() ); } return *this; } QDomElement EventQueue::toXml(QDomDocument *doc) const { QDomElement e = doc->createElement("eventQueue"); e.setAttribute("version", "1.0"); e.appendChild(textTag(doc, "progver", ApplicationInfo::version())); foreach(EventItem *i, d->list) { QDomElement event = i->event()->toXml(doc); e.appendChild( event ); } return e; } bool EventQueue::fromXml(const QDomElement *q) { if ( !q ) return false; if ( q->tagName() != "eventQueue" ) return false; if ( q->attribute("version") != "1.0" ) return false; QString progver = subTagText(*q, "progver"); for(QDomNode n = q->firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if( e.isNull() ) continue; if ( e.tagName() != "event" ) continue; PsiEvent *event = 0; QString eventType = e.attribute("type"); if ( eventType == "MessageEvent" ) { event = new MessageEvent(0); if ( !event->fromXml(d->psi, d->account, &e) ) { delete event; event = 0; } } else if ( eventType == "AuthEvent" ) { event = new AuthEvent("", "", 0); if ( !event->fromXml(d->psi, d->account, &e) ) { delete event; event = 0; } } if ( event ) emit eventFromXml( event ); } return true; } bool EventQueue::toFile(const QString &fname) { QDomDocument doc; QDomElement element = toXml(&doc); doc.appendChild(element); AtomicXmlFile f(fname); return f.saveDocument(doc); } bool EventQueue::fromFile(const QString &fname) { AtomicXmlFile f(fname); QDomDocument doc; if (!f.loadDocument(&doc)) return false; QDomElement base = doc.documentElement(); return fromXml(&base); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/serverinfomanager.h��������������������������������������������������������������������0000644�0001750�0001750�00000002465�11305557613�015025� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * serverinfomanager.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SERVERINFOMANAGER_H #define SERVERINFOMANAGER_H #include <QObject> #include <QString> namespace XMPP { class Client; } class ServerInfoManager : public QObject { Q_OBJECT public: ServerInfoManager(XMPP::Client* client); const QString& multicastService() const; bool hasPEP() const; signals: void featuresChanged(); private slots: void disco_finished(); void initialize(); void deinitialize(); void reset(); private: XMPP::Client* client_; QString multicastService_; bool featuresRequested_; bool hasPEP_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/systeminfo.cpp�������������������������������������������������������������������������0000644�0001750�0001750�00000013550�11305557613�014040� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007-2008 Psi Development Team * Licensed under the GNU General Public License. * See the COPYING file for more information. */ #include <QString> #include <QStringList> #include <QFile> #include <QFileInfo> #include <QDir> #include <QCoreApplication> #include <QSysInfo> #include <QProcess> #include <QTextStream> #if defined(Q_WS_X11) || defined(Q_WS_MAC) #include <time.h> #include <stdlib.h> #include <string.h> #include <sys/utsname.h> #endif #ifdef Q_WS_WIN #include <windows.h> #endif #include "systeminfo.h" #if defined(Q_WS_X11) static QString lsbRelease(const QStringList& args) { QStringList path = QString(qgetenv("PATH")).split(':'); QString found; foreach(QString dirname, path) { QDir dir(dirname); QFileInfo cand(dir.filePath("lsb_release")); if (cand.isExecutable()) { found = cand.absoluteFilePath(); break; } } if (found.isEmpty()) { return QString(); } QProcess process; process.start(found, args, QIODevice::ReadOnly); if(!process.waitForStarted()) return QString(); // process failed to start QTextStream stream(&process); QString ret; while(process.waitForReadyRead()) ret += stream.readAll(); process.close(); return ret.trimmed(); } static QString unixHeuristicDetect() { QString ret; struct utsname u; uname(&u); ret.sprintf("%s", u.sysname); // get description about os enum LinuxName { LinuxNone = 0, LinuxMandrake, LinuxDebian, LinuxRedHat, LinuxGentoo, LinuxSlackware, LinuxSuSE, LinuxConectiva, LinuxCaldera, LinuxLFS, LinuxASP, // Russian Linux distros LinuxALT, LinuxPLD, // Polish Linux distros LinuxAurox, LinuxArch }; enum OsFlags { OsUseName = 0, OsUseFile, OsAppendFile }; struct OsInfo { LinuxName id; OsFlags flags; QString file; QString name; } osInfo[] = { { LinuxMandrake, OsUseFile, "/etc/mandrake-release", "Mandrake Linux" }, { LinuxDebian, OsAppendFile, "/etc/debian_version", "Debian GNU/Linux" }, { LinuxGentoo, OsUseFile, "/etc/gentoo-release", "Gentoo Linux" }, { LinuxSlackware, OsAppendFile, "/etc/slackware-version", "Slackware Linux" }, { LinuxPLD, OsUseFile, "/etc/pld-release", "PLD Linux" }, { LinuxAurox, OsUseName, "/etc/aurox-release", "Aurox Linux" }, { LinuxArch, OsUseFile, "/etc/arch-release", "Arch Linux" }, { LinuxLFS, OsAppendFile, "/etc/lfs-release", "LFS Linux" }, // untested { LinuxSuSE, OsUseFile, "/etc/SuSE-release", "SuSE Linux" }, { LinuxConectiva, OsUseFile, "/etc/conectiva-release", "Conectiva Linux" }, { LinuxCaldera, OsUseFile, "/etc/.installed", "Caldera Linux" }, // many distros use the /etc/redhat-release for compatibility, so RedHat will be the last :) { LinuxRedHat, OsUseFile, "/etc/redhat-release", "RedHat Linux" }, { LinuxNone, OsUseName, "", "" } }; for (int i = 0; osInfo[i].id != LinuxNone; i++) { QFileInfo fi( osInfo[i].file ); if ( fi.exists() ) { char buffer[128]; QFile f( osInfo[i].file ); f.open( QIODevice::ReadOnly ); f.readLine( buffer, 128 ); QString desc(buffer); desc = desc.trimmed(); switch ( osInfo[i].flags ) { case OsUseFile: ret = desc; break; case OsUseName: ret = osInfo[i].name; break; case OsAppendFile: ret = osInfo[i].name + " (" + desc + ")"; break; } break; } } return ret; } #endif SystemInfo::SystemInfo() : QObject(QCoreApplication::instance()) { // Initialize timezone_offset_ = 0; timezone_str_ = "N/A"; os_str_ = "Unknown"; // Detect #if defined(Q_WS_X11) || defined(Q_WS_MAC) time_t x; time(&x); char str[256]; char fmt[32]; strcpy(fmt, "%z"); strftime(str, 256, fmt, localtime(&x)); if(strcmp(fmt, str)) { QString s = str; if(s.at(0) == '+') s.remove(0,1); s.truncate(s.length()-2); timezone_offset_ = s.toInt(); } strcpy(fmt, "%Z"); strftime(str, 256, fmt, localtime(&x)); if(strcmp(fmt, str)) timezone_str_ = str; #endif #if defined(Q_WS_X11) // attempt to get LSB version before trying the distro-specific approach os_str_ = lsbRelease(QStringList() << "--description" << "--short"); if(os_str_.isEmpty()) { os_str_ = unixHeuristicDetect(); } #elif defined(Q_WS_MAC) QSysInfo::MacVersion v = QSysInfo::MacintoshVersion; if(v == QSysInfo::MV_10_3) os_str_ = "Mac OS X 10.3"; else if(v == QSysInfo::MV_10_4) os_str_ = "Mac OS X 10.4"; else if(v == QSysInfo::MV_10_5) os_str_ = "Mac OS X 10.5"; #if QT_VERSION >= 0x040500 else if(v == QSysInfo::MV_10_6) os_str_ = "Mac OS X 10.6"; #endif else os_str_ = "Mac OS X"; #endif #if defined(Q_WS_WIN) TIME_ZONE_INFORMATION i; //GetTimeZoneInformation(&i); //timezone_offset_ = (-i.Bias) / 60; memset(&i, 0, sizeof(i)); bool inDST = (GetTimeZoneInformation(&i) == TIME_ZONE_ID_DAYLIGHT); int bias = i.Bias; if(inDST) bias += i.DaylightBias; timezone_offset_ = (-bias) / 60; timezone_str_ = ""; for(int n = 0; n < 32; ++n) { int w = inDST ? i.DaylightName[n] : i.StandardName[n]; if(w == 0) break; timezone_str_ += QChar(w); } QSysInfo::WinVersion v = QSysInfo::WindowsVersion; if(v == QSysInfo::WV_95) os_str_ = "Windows 95"; else if(v == QSysInfo::WV_98) os_str_ = "Windows 98"; else if(v == QSysInfo::WV_Me) os_str_ = "Windows Me"; else if(v == QSysInfo::WV_DOS_based) os_str_ = "Windows 9x/Me"; else if(v == QSysInfo::WV_NT) os_str_ = "Windows NT 4.x"; else if(v == QSysInfo::WV_2000) os_str_ = "Windows 2000"; else if(v == QSysInfo::WV_XP) os_str_ = "Windows XP"; else if(v == QSysInfo::WV_2003) os_str_ = "Windows Server 2003"; else if(v == QSysInfo::WV_VISTA) os_str_ = "Windows Vista"; #if QT_VERSION >= 0x040500 else if(v == QSysInfo::WV_WINDOWS7) os_str_ = "Windows 7"; #endif else if(v == QSysInfo::WV_NT_based) os_str_ = "Windows NT"; #endif } SystemInfo* SystemInfo::instance() { if (!instance_) instance_ = new SystemInfo(); return instance_; } SystemInfo* SystemInfo::instance_ = NULL; ��������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/aboutdlg.h�����������������������������������������������������������������������������0000644�0001750�0001750�00000002216�11305557613�013103� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * aboutdlg.h * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ABOUTDLG_H #define ABOUTDLG_H #include <QDialog> #include "ui_about.h" class AboutDlg : public QDialog { Q_OBJECT public: AboutDlg(QWidget* parent = NULL); protected: QString loadText( const QString & fileName ); QString details( QString name, QString email, QString jabber, QString www, QString desc ); private: Ui::AboutDlg ui_; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/userlist.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000042744�11305557613�013521� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * userlist.cpp - high-level roster * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QApplication> #include <QPixmap> #include <QList> #include <QtCrypto> #include <QTextDocument> // for Qt::escape() #include "userlist.h" #include "avatars.h" #include "textutil.h" #include "common.h" #include "mucmanager.h" #include "psioptions.h" #include "jidutil.h" using namespace XMPP; static QString dot_truncate(const QString &in, int clip) { if((int)in.length() <= clip) return in; QString s = in; s.truncate(clip); s += "..."; return s; } //---------------------------------------------------------------------------- // UserResource //---------------------------------------------------------------------------- UserResource::UserResource() :Resource() { } UserResource::UserResource(const Resource &r) { setResource(r); } UserResource::~UserResource() { } void UserResource::setResource(const Resource &r) { setName(r.name()); setStatus(r.status()); } const QString & UserResource::versionString() const { return v_ver; } const QString & UserResource::clientName() const { return v_clientName; } const QString & UserResource::clientVersion() const { return v_clientVersion; } const QString & UserResource::clientOS() const { return v_clientOS; } void UserResource::setClient(const QString &name, const QString& version, const QString& os) { v_clientName = name; v_clientVersion = version; v_clientOS = os; if (!v_clientName.isEmpty()) { v_ver = v_clientName + " " + v_clientVersion; if ( !v_clientOS.isEmpty() ) v_ver += " / " + v_clientOS; } else { v_ver = ""; } } const QString & UserResource::publicKeyID() const { return v_keyID; } int UserResource::pgpVerifyStatus() const { return v_pgpVerifyStatus; } QDateTime UserResource::sigTimestamp() const { return sigts; } void UserResource::setPublicKeyID(const QString &s) { v_keyID = s; } void UserResource::setPGPVerifyStatus(int x) { v_pgpVerifyStatus = x; } void UserResource::setSigTimestamp(const QDateTime &ts) { sigts = ts; } void UserResource::setTune(const QString& t) { v_tune = t; } const QString& UserResource::tune() const { return v_tune; } void UserResource::setGeoLocation(const GeoLocation& geoLocation) { v_geoLocation = geoLocation; } const GeoLocation& UserResource::geoLocation() const { return v_geoLocation; } void UserResource::setPhysicalLocation(const PhysicalLocation& physicalLocation) { v_physicalLocation = physicalLocation; } const PhysicalLocation& UserResource::physicalLocation() const { return v_physicalLocation; } bool operator<(const UserResource &r1, const UserResource &r2) { return r1.priority() > r2.priority(); } bool operator<=(const UserResource &r1, const UserResource &r2) { return r1.priority() >= r2.priority(); } bool operator==(const UserResource &r1, const UserResource &r2) { return r1.priority() == r2.priority(); } bool operator>(const UserResource &r1, const UserResource &r2) { return r1.priority() < r2.priority(); } bool operator>=(const UserResource &r1, const UserResource &r2) { return r1.priority() <= r2.priority(); } //---------------------------------------------------------------------------- // UserResourceList //---------------------------------------------------------------------------- UserResourceList::UserResourceList() :QList<UserResource>() { } UserResourceList::~UserResourceList() { } UserResourceList::Iterator UserResourceList::find(const QString & _find) { for(UserResourceList::Iterator it = begin(); it != end(); ++it) { if((*it).name() == _find) return it; } return end(); } UserResourceList::Iterator UserResourceList::priority() { UserResourceList::Iterator highest = end(); for(UserResourceList::Iterator it = begin(); it != end(); ++it) { if(highest == end() || (*it).priority() > (*highest).priority()) highest = it; } return highest; } UserResourceList::ConstIterator UserResourceList::find(const QString & _find) const { for(UserResourceList::ConstIterator it = begin(); it != end(); ++it) { if((*it).name() == _find) return it; } return end(); } UserResourceList::ConstIterator UserResourceList::priority() const { UserResourceList::ConstIterator highest = end(); for(UserResourceList::ConstIterator it = begin(); it != end(); ++it) { if(highest == end() || (*it).priority() > (*highest).priority()) highest = it; } return highest; } void UserResourceList::sort() { qSort(*this); } //---------------------------------------------------------------------------- // UserListItem //---------------------------------------------------------------------------- UserListItem::UserListItem(bool self) { v_inList = false; v_self = self; v_private = false; v_avatarFactory = NULL; lastmsgtype = -1; } UserListItem::~UserListItem() { } bool UserListItem::inList() const { return v_inList; } void UserListItem::setMood(const Mood& mood) { v_mood = mood; } const Mood& UserListItem::mood() const { return v_mood; } void UserListItem::setTune(const QString& t) { v_tune = t; } const QString& UserListItem::tune() const { return v_tune; } void UserListItem::setGeoLocation(const GeoLocation& geoLocation) { v_geoLocation = geoLocation; } const GeoLocation& UserListItem::geoLocation() const { return v_geoLocation; } void UserListItem::setPhysicalLocation(const PhysicalLocation& physicalLocation) { v_physicalLocation = physicalLocation; } const PhysicalLocation& UserListItem::physicalLocation() const { return v_physicalLocation; } void UserListItem::setAvatarFactory(AvatarFactory* av) { v_avatarFactory = av; } void UserListItem::setJid(const Jid &j) { LiveRosterItem::setJid(j); int n = jid().full().indexOf('@'); if(n == -1) v_isTransport = true; else v_isTransport = false; } bool UserListItem::isTransport() const { return v_isTransport; } bool UserListItem::isAvailable() const { return !v_url.isEmpty(); } bool UserListItem::isHidden() const { return groups().contains(qApp->translate("ContactView", "Hidden")); } bool UserListItem::isAway() const { int status; if(!isAvailable()) status = STATUS_OFFLINE; else status = makeSTATUS((*userResourceList().priority()).status()); if(status == STATUS_AWAY || status == STATUS_XA || status == STATUS_DND) return true; else return false; } QDateTime UserListItem::lastAvailable() const { return v_t; } int UserListItem::lastMessageType() const { return lastmsgtype; } void UserListItem::setLastMessageType(const int mtype) { // printf("setting message type to %i\n", mtype); lastmsgtype = mtype; } const QString & UserListItem::presenceError() const { return v_perr; } bool UserListItem::isSelf() const { return v_self; } void UserListItem::setInList(bool b) { v_inList = b; } void UserListItem::setLastAvailable(const QDateTime &t) { v_t = t; } void UserListItem::setPresenceError(const QString &e) { v_perr = e; } UserResourceList & UserListItem::userResourceList() { return v_url; } UserResourceList::Iterator UserListItem::priority() { return v_url.priority(); } const UserResourceList & UserListItem::userResourceList() const { return v_url; } UserResourceList::ConstIterator UserListItem::priority() const { return v_url.priority(); } QString UserListItem::makeTip(bool trim, bool doLinkify) const { return "<qt>" + makeBareTip(trim,doLinkify) + "</qt>"; } QString UserListItem::makeBareTip(bool trim, bool doLinkify) const { // NOTE: If you add something to the tooltip, // you most probably want to wrap it with Qt::escape() QString str; bool useAvatar = false; if (v_avatarFactory && !v_avatarFactory->getAvatar(jid().bare()).isNull() && PsiOptions::instance()->getOption("options.ui.contactlist.tooltip.avatar").toBool()) useAvatar = true; if (useAvatar) { str += "<table cellspacing=\"0\"><tr>"; str += "<td>"; str += QString("<icon name=\"avatars/%1\">").arg(jid().bare()); str += "</td><td width=\"10\"></td>"; str += "<td>"; } QString nick = JIDUtil::nickOrJid(name(), jid().full()); if(jid().full() != nick) str += QString("<div style='white-space:pre'>%1 <%2></div>").arg(Qt::escape(nick)).arg(Qt::escape(JIDUtil::toString(jid(),true))); else str += QString("<div style='white-space:pre'>%1</div>").arg(Qt::escape(nick)); // subscription if(!v_self && subscription().type() != Subscription::Both) str += QString("<div style='white-space:pre'>") + QObject::tr("Subscription") + ": " + subscription().toString() + "</div>"; if(!v_keyID.isEmpty()) str += QString("<div style='white-space:pre'>") + QObject::tr("OpenPGP") + ": " + v_keyID.right(8) + "</div>"; // User Mood if (!mood().isNull()) { str += QString("<div style='white-space:pre'>") + QObject::tr("Mood") + ": " + mood().typeText(); if (!mood().text().isEmpty()) str += QString(" (") + Qt::escape(mood().text()) + QString(")"); str += "</div>"; } // User Tune if (!tune().isEmpty()) str += QString("<div style='white-space:pre'>") + QObject::tr("Listening to") + ": " + Qt::escape(tune()) + "</div>"; // User Physical Location if (!physicalLocation().isNull()) str += QString("<div style='white-space:pre'>") + QObject::tr("Location") + ": " + Qt::escape(physicalLocation().toString()) + "</div>"; // User Geolocation if (!geoLocation().isNull()) str += QString("<div style='white-space:pre'>") + QObject::tr("Geolocation") + ": " + QString::number(geoLocation().lat().value()) + "/" + QString::number(geoLocation().lon().value()) + "</div>"; // resources if(!userResourceList().isEmpty()) { UserResourceList srl = userResourceList(); srl.sort(); for(UserResourceList::ConstIterator rit = srl.begin(); rit != srl.end(); ++rit) { const UserResource &r = *rit; QString name; if(!r.name().isEmpty()) name = r.name(); else name = QObject::tr("[blank]"); int status = makeSTATUS(r.status()); QString istr = "status/offline"; if(status == STATUS_ONLINE) istr = "status/online"; else if(status == STATUS_AWAY) istr = "status/away"; else if(status == STATUS_XA) istr = "status/xa"; else if(status == STATUS_DND) istr = "status/dnd"; else if(status == STATUS_CHAT) istr = "status/chat"; else if(status == STATUS_INVISIBLE) istr = "status/invisible"; //this shouldn't happen QString imgTag = "icon name"; // or 'img src' if appropriate QMimeSourceFactory is installed. but mblsha noticed that QMimeSourceFactory unloads sometimes QString secstr; if(isSecure(r.name()) && PsiOptions::instance()->getOption("options.ui.contactlist.tooltip.pgp").toBool()) secstr += QString(" <%1=\"psi/cryptoYes\">").arg(imgTag); str += QString("<div style='white-space:pre'>") + QString("<%1=\"%2\"> ").arg(imgTag).arg(istr) + QString("<b>%1</b> ").arg(Qt::escape(name)) + QString("(%1)").arg(r.priority()) + secstr + "</div>"; if(!r.publicKeyID().isEmpty() && PsiOptions::instance()->getOption("options.ui.contactlist.tooltip.pgp").toBool()) { int v = r.pgpVerifyStatus(); if(v == QCA::SecureMessageSignature::Valid || v == QCA::SecureMessageSignature::InvalidSignature || v == QCA::SecureMessageSignature::InvalidKey || v == QCA::SecureMessageSignature::NoKey) { if(v == QCA::SecureMessageSignature::Valid) { QString d = r.sigTimestamp().toString(Qt::TextDate); str += QString("<div style='white-space:pre'>") + QObject::tr("Signed") + " @ " + "<font color=\"#2A993B\">" + d + "</font>"; } else if(v == QCA::SecureMessageSignature::NoKey) { QString d = r.sigTimestamp().toString(Qt::TextDate); str += QString("<div style='white-space:pre'>") + QObject::tr("Signed") + " @ " + d; } else if(v == QCA::SecureMessageSignature::InvalidSignature || v == QCA::SecureMessageSignature::InvalidKey) { str += QString("<div style='white-space:pre'>") + "<font color=\"#810000\">" + QObject::tr("Bad signature") + "</font>"; } if(v_keyID != r.publicKeyID()) str += QString(" [%1]").arg(r.publicKeyID().right(8)); str += "</div>"; } } // last status if(r.status().timeStamp().isValid() && PsiOptions::instance()->getOption("options.ui.contactlist.tooltip.last-status").toBool()) { QString d = r.status().timeStamp().toString(Qt::TextDate); str += QString("<div style='white-space:pre'>") + QObject::tr("Last Status") + " @ " + d + "</div>"; } // MUC if(r.status().hasMUCItem()) { if(!r.status().mucItem().jid().isEmpty()) str += QString("<div style='white-space:pre'>") + QObject::tr("JID: %1").arg(JIDUtil::toString(r.status().mucItem().jid(),true)) + QString("</div>"); if(r.status().mucItem().role() != MUCItem::NoRole) str += QString("<div style='white-space:pre'>") + QObject::tr("Role: %1").arg(MUCManager::roleToString(r.status().mucItem().role())) + QString("</div>"); str += QString("<div style='white-space:pre'>") + QObject::tr("Affiliation: %1").arg(MUCManager::affiliationToString(r.status().mucItem().affiliation())) + QString("</div>"); } // gabber music if(!r.status().songTitle().isEmpty()) { QString s = r.status().songTitle(); if(trim) s = dot_truncate(s, 80); s = Qt::escape(s); str += QString("<div style='white-space:pre'>") + QObject::tr("Listening to") + QString(": %1").arg(s) + "</div>"; } // User Tune if (!r.tune().isEmpty()) str += QString("<div style='white-space:pre'>") + QObject::tr("Listening to") + ": " + Qt::escape(r.tune()) + "</div>"; // User Physical Location if (!r.physicalLocation().isNull()) str += QString("<div style='white-space:pre'>") + QObject::tr("Location") + ": " + Qt::escape(r.physicalLocation().toString()) + "</div>"; // User Geolocation if (!r.geoLocation().isNull()) str += QString("<div style='white-space:pre'>") + QObject::tr("Geolocation") + ": " + QString::number(r.geoLocation().lat().value()) + "/" + QString::number(r.geoLocation().lon().value()) + "</div>"; // client if(!r.versionString().isEmpty() && PsiOptions::instance()->getOption("options.ui.contactlist.tooltip.client-version").toBool()) { QString ver = r.versionString(); if(trim) ver = dot_truncate(ver, 80); ver = Qt::escape(ver); str += QString("<div style='white-space:pre'>") + QObject::tr("Using") + QString(": %1").arg(ver) + "</div>"; } // status message QString s = r.status().status(); if(!s.isEmpty()) { QString head = QObject::tr("Status Message"); if(trim) s = TextUtil::plain2rich(clipStatus(s, 200, 12)); else s = TextUtil::plain2rich(s); if ( doLinkify ) s = TextUtil::linkify(s); if( PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool() && !doLinkify ) s = TextUtil::emoticonify(s); if( !doLinkify && PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool() ) s = TextUtil::legacyFormat(s); str += QString("<div style='white-space:pre'><u>%1</u></div><div>%2</div>").arg(head).arg(s); } } } else { // last available if(!lastAvailable().isNull()) { QString d = lastAvailable().toString(Qt::TextDate); str += QString("<div style='white-space:pre'>") + QObject::tr("Last Available") + " @ " + d + "</div>"; } // presence error if(!v_perr.isEmpty()) { QStringList err = v_perr.split('\n'); str += QString("<div style='white-space:pre'>") + QObject::tr("Presence Error") + QString(": %1").arg(Qt::escape(err[0])) + "</div>"; err.pop_front(); foreach (QString line, err) str += "<div>" + line + "</div>"; } // status message QString s = lastUnavailableStatus().status(); if(!s.isEmpty()) { QString head = QObject::tr("Last Status Message"); if(trim) s = TextUtil::plain2rich(clipStatus(s, 200, 12)); else { s = TextUtil::plain2rich(clipStatus(s, 200, 12)); if ( doLinkify ) s = TextUtil::linkify(s); } str += QString("<div style='white-space:pre'><u>%1</u></div><div>%2</div>").arg(head).arg(s); } } if (useAvatar) { str += "</td>"; str += "</tr></table>"; } return str; } QString UserListItem::makeDesc() const { return makeTip(false); } bool UserListItem::isPrivate() const { return v_private; } void UserListItem::setPrivate(bool b) { v_private = b; } bool UserListItem::isSecure(const QString &rname) const { for(QStringList::ConstIterator it = secList.begin(); it != secList.end(); ++it) { if(*it == rname) return true; } return false; } void UserListItem::setSecure(const QString &rname, bool b) { foreach(const QString s, secList) { if(s == rname) { if(!b) secList.removeAll(s); return; } } if(b) secList.append(rname); } const QString & UserListItem::publicKeyID() const { return v_keyID; } void UserListItem::setPublicKeyID(const QString &k) { v_keyID = k; } //---------------------------------------------------------------------------- // UserList //---------------------------------------------------------------------------- UserList::UserList() { } UserList::~UserList() { } UserListItem *UserList::find(const XMPP::Jid &j) { foreach(UserListItem* i, *this) { if(i->jid().compare(j)) return i; } return 0; } ����������������������������psi-0.14/src/historydlg.h���������������������������������������������������������������������������0000644�0001750�0001750�00000005073�11305557613�013476� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * historydlg.h - a dialog to show event history * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef HISTORYDLG_H #define HISTORYDLG_H #include <q3listview.h> class PsiEvent; class PsiAccount; class EDBItem; class EDBResult; class Q3SimpleRichText; namespace XMPP { class Jid; } class HistoryViewItem : public Q3ListViewItem { public: HistoryViewItem(PsiEvent *, const QString &, int id, Q3ListView *); ~HistoryViewItem(); Q3SimpleRichText *rt; QString text; int id; PsiEvent *e; QString eventId; // reimplemented int rtti() const; void paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int alignment); void setup(); int compare(Q3ListViewItem *, int column, bool ascending) const; }; class HistoryView : public Q3ListView { Q_OBJECT public: HistoryView(QWidget *parent=0, const char *name=0); void doResize(); void addEvent(PsiEvent *, const QString &); // reimplemented void keyPressEvent(QKeyEvent *e); void resizeEvent(QResizeEvent *e); signals: void aOpenEvent(PsiEvent *); private slots: void doOpenEvent(); void qlv_doubleclick(Q3ListViewItem *); void qlv_contextPopup(Q3ListViewItem *, const QPoint &, int); private: int at_id; }; class HistoryDlg : public QWidget { Q_OBJECT public: HistoryDlg(const XMPP::Jid &, PsiAccount *); ~HistoryDlg(); // reimplemented void keyPressEvent(QKeyEvent *e); void closeEvent(QCloseEvent *e); signals: void openEvent(PsiEvent *); public slots: // reimplemented void show(); private slots: void doLatest(); void doPrev(); void doNext(); void doSave(); void doErase(); void setButtons(); void actionOpenEvent(PsiEvent *); void doFind(); void edb_finished(); void le_textChanged(const QString &); private: class Private; Private *d; void loadPage(int); void displayResult(const EDBResult *, int, int max=-1); void exportHistory(const QString &fname); }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/mcmdmanager.cpp������������������������������������������������������������������������0000644�0001750�0001750�00000012400�11305557613�014104� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see <http://www.gnu.org/licenses/>. * */ // manager mini command system #include <QDebug> #include "mcmdmanager.h" MCmdSimpleState::MCmdSimpleState(QString name, QString prompt) { name_ = name; prompt_ = prompt; } MCmdSimpleState::MCmdSimpleState(QString name, QString prompt, int flags) { name_ = name; prompt_ = prompt; flags_ = flags; } MCmdSimpleState::~MCmdSimpleState() { } MCmdManager::MCmdManager(MCmdUiSiteIface* site_) : state_(0), uiSite_(site_) { }; MCmdManager::~MCmdManager() { foreach(MCmdProviderIface *prov, providers_) { prov->mCmdSiteDestroyed(); } } QStringList MCmdManager::parseCommand(const QString command, int pos, int &part, QString &partial, int &start, int &end, char "edAtPos) { QStringList list; QString item; bool escape=false; int quote=0; // "=1, '=2 bool space=true; int partStart = 0; quotedAtPos = 0; for (int i=0; i < command.length(); i++) { if (i == pos) { part = list.size(); partial = item; end = i; start = partStart; if (quote) quotedAtPos = (quote == 1) ? '"' : '\''; } QChar ch = command[i]; if (escape) { escape = false; item += ch; } else if (ch == '\\') { escape = true; } else if (quote != 0) { if ((quote == 1 && ch == '"') || (quote == 2 && ch == '\'')) { quote = 0; } else { item += ch; } } else if (ch == ' ') { partStart = i+1; if (space) { continue; } list << item; item = ""; space = true; continue; } else if (ch == '\'') { quote = 2; } else if (ch == '"') { quote = 1; } else { item += ch; } space = false; } if (command.length() == pos) { part = list.size(); partial = item; end = command.length(); start = partStart; if (quote) quotedAtPos = (quote == 1) ? '"' : '\''; } if (!space) list << item; return list; } QString MCmdManager::serializeCommand(const QStringList &list) { QString retval; bool needspace = false; QRegExp specials("([\"\'\\\\ ])"); foreach(QString item, list) { item.replace(specials, "\\\\1"); if (item == "") item = "\"\""; if (needspace) retval += " "; retval += item; needspace = true; } return retval; } bool MCmdManager::processCommand(QString command) { MCmdStateIface *tmpstate=0; QStringList preset; QStringList items; if (state_->getFlags() & MCMDSTATE_UNPARSED) { items << command; } else { int tmp_1; QString tmp_2; char tmp_3; items = parseCommand(command, -1, tmp_1, tmp_2, tmp_1, tmp_1, tmp_3); } foreach(MCmdProviderIface *prov, providers_) { if (prov->mCmdTryStateTransit(state_, items, tmpstate, preset)) { state_ = tmpstate; if (state_ != 0) { QString prompt = state_->getPrompt(); QString def; if (state_->getFlags() & MCMDSTATE_UNPARSED) { if (preset.size() == 1) { def = preset.at(0); } } else { def = serializeCommand(preset); } uiSite_->mCmdReady(prompt, def); } else { uiSite_->mCmdClose(); } return true; } } tmpstate = state_; bool ret = state_->unhandled(items); state_ = 0; if (state_ == 0) { tmpstate->dispose(); uiSite_->mCmdClose(); } return ret; } bool MCmdManager::open(MCmdStateIface *state, QStringList preset) { if (0 != state_) state_->dispose(); state_ = state; QString prompt = state->getPrompt(); QString def; if (state_->getFlags() & MCMDSTATE_UNPARSED) { if (preset.size() == 1) def = preset.at(0); } else { def = serializeCommand(preset); } uiSite_->mCmdReady(prompt, def); return true; } QStringList MCmdManager::completeCommand(QString &command, int pos, int &start, int &end) { int part; QString query; char quotedAtPos; QStringList all; if (state_->getFlags() & MCMDSTATE_UNPARSED) { all << command; query = command.left(pos); part = -1; } else { all = parseCommand(command, pos, part, query, start, end, quotedAtPos); } QStringList res; foreach(MCmdProviderIface *prov, providers_) { res += prov->mCmdTryCompleteCommand(state_, query, all, part); } res.sort(); QStringList quoted; if ((state_->getFlags() & MCMDSTATE_UNPARSED) == 0) { foreach(QString str, res) { QString trail; if (str.size() > 1 && str.at(str.size()-1) == QChar(0)) { str.chop(1); trail = " "; } str = str.replace("\\", "\\\\"); if (quotedAtPos == 0) { quoted << str.replace(" ", "\\ ").replace("\"", "\\\"").replace("'", "\\'") + trail; } else { quoted << quotedAtPos + str.replace(quotedAtPos, QString("\\") + quotedAtPos) + trail; } } } else { quoted = res; } return quoted; } bool MCmdManager::isActive() { return state_ != 0; } void MCmdManager::registerProvider(MCmdProviderIface *prov) { if (! providers_.contains(prov)) { providers_ += prov; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/pgputil.h������������������������������������������������������������������������������0000644�0001750�0001750�00000003144�11305557613�012767� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef PGPUTIL_H #define PGPUTIL_H // FIXME: instead of a singleton, make it a member of PsiCon. #include <QSet> #include <QList> #include <QMap> #include <QtCrypto> class QString; class PassphraseDlg; namespace QCA { class KeyStore; class PGPKey; } class PGPUtil : public QObject { Q_OBJECT public: static PGPUtil& instance(); bool pgpAvailable(); void clearPGPAvailableCache(); static void showDiagnosticText(const QString& event, const QString& diagnostic); static void showDiagnosticText(QCA::SecureMessage::Error error, const QString& diagnostic); QCA::KeyStoreEntry getSecretKeyStoreEntry(const QString& key); QCA::KeyStoreEntry getPublicKeyStoreEntry(const QString& key); QString stripHeaderFooter(const QString &); QString addHeaderFooter(const QString &, int); QString messageErrorString(enum QCA::SecureMessage::Error); bool equals(QCA::PGPKey, QCA::PGPKey); void removePassphrase(const QString& id); signals: void pgpKeysUpdated(); protected: PGPUtil(); ~PGPUtil(); void promptPassphrase(int id, const QCA::Event& event); protected slots: void handleEvent(int id, const QCA::Event& event); void passphraseDone(int); void keyStoreAvailable(const QString&); private: static PGPUtil* instance_; struct EventItem { int id; QCA::Event event; }; QList<EventItem> pendingEvents_; QSet<QCA::KeyStore*> keystores_; QMap<QString,QString> passphrases_; QCA::EventHandler* qcaEventHandler_; QCA::KeyStoreManager qcaKeyStoreManager_; PassphraseDlg* passphraseDlg_; int currentEventId_; QString currentEntryId_; bool cache_no_pgp_; // FIXME friend class PGPKeyDlg; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psicontactlist.h�����������������������������������������������������������������������0000644�0001750�0001750�00000006143�11305557613�014350� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psicontactlist.h - general abstraction of the psi-specific contact list * Copyright (C) 2006 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSICONTACTLIST_H #define PSICONTACTLIST_H #include <QList> #include "profiles.h" using namespace XMPP; class PsiCon; class PsiAccount; namespace XMPP { class Jid; } class PsiContactList : public QObject { Q_OBJECT public: PsiContactList(PsiCon* psi); ~PsiContactList(); PsiCon* psi() const; const QList<PsiAccount*>& accounts() const; const QList<PsiAccount*>& enabledAccounts() const; bool haveActiveAccounts() const; bool haveEnabledAccounts() const; PsiAccount *defaultAccount() const; UserAccountList getUserAccountList() const; void createAccount(const QString& name, const Jid& j = "", const QString& pass = "", bool opt_host = false, const QString& host = "", int port = 5222, bool legacy_ssl_probe = true, UserAccount::SSLFlag ssl = UserAccount::SSL_Auto, QString proxyID = "", const QString &tlsOverrideDomain="", const QByteArray &tlsOverrideCert=QByteArray(), bool modify = true); void createAccount(const UserAccount&); void removeAccount(PsiAccount*); void setAccountEnabled(PsiAccount*, bool enabled = TRUE); int queueCount() const; PsiAccount *queueLowestEventId(); void loadAccounts(const UserAccountList &); void link(PsiAccount*); void unlink(PsiAccount*); void beginBulkOperation(); void endBulkOperation(); signals: /** * This signal is emitted when account is loaded from disk or created * anew. */ void accountAdded(PsiAccount*); /** * This signal is emitted when account is completely removed from the * program, i.e. deleted. */ void accountRemoved(PsiAccount*); /** * This signal is emitted when number of accounts managed by * PsiContactList changes. */ void accountCountChanged(); /** * This signal is emitted when one of the accounts emits * activityChanged() signal. */ void accountActivityChanged(); /** * This signal is emitted when the features of one of the accounts change. */ void accountFeaturesChanged(); /** * This signal is emitted when either new account was added, or * existing one was removed altogether. */ void saveAccounts(); private slots: void accountEnabledChanged(); private: PsiAccount *loadAccount(const UserAccount &); PsiAccount *tryQueueLowestEventId(bool includeDND); PsiCon *psi_; PsiContactList *contactList_; QList<PsiAccount *> accounts_, enabledAccounts_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/accountlabel.cpp�����������������������������������������������������������������������0000644�0001750�0001750�00000003253�11305557613�014273� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * accountlabel.cpp - simple label to display account name currently in use * Copyright (C) 2006-2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "accountlabel.h" #include "psiaccount.h" AccountLabel::AccountLabel(QWidget* parent) : QLabel(parent) , showJid_(true) { setFrameStyle(QFrame::Panel | QFrame::Sunken); } AccountLabel::~AccountLabel() { } PsiAccount* AccountLabel::account() const { return account_; } bool AccountLabel::showJid() const { return showJid_; } void AccountLabel::setAccount(PsiAccount* account) { account_ = account; if (account) { connect(account, SIGNAL(updatedAccount()), SLOT(updateName())); connect(account, SIGNAL(destroyed()), SLOT(deleteLater())); } updateName(); } void AccountLabel::setShowJid(bool showJid) { showJid_ = showJid; updateName(); } void AccountLabel::updateName() { QString text = "..."; if (!account_.isNull()) { if (showJid_) text = account_->nameWithJid(); else text = account_->name(); } setText(text); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/statuscombobox.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000005510�11305557613�014711� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * statuscombobox.cpp - helper class that displays available statuses using QComboBox * Copyright (C) 2008 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "statuscombobox.h" #include "psioptions.h" #include "common.h" /** * \brief Constructs new StatusComboBox * \param parent, widget's parent * \param type, selected status type just after creation */ StatusComboBox::StatusComboBox(QWidget* parent, XMPP::Status::Type type) : QComboBox(parent) { if (PsiOptions::instance()->getOption("options.ui.menu.status.chat").toBool()) { addStatus(XMPP::Status::FFC); } addStatus(XMPP::Status::Online); addStatus(XMPP::Status::Away); if (PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()) { addStatus(XMPP::Status::XA); } addStatus(XMPP::Status::DND); if (PsiOptions::instance()->getOption("options.ui.menu.status.invisible").toBool()) { addStatus(XMPP::Status::Invisible); } addStatus(XMPP::Status::Offline); connect(this, SIGNAL(currentIndexChanged(int)), SLOT(onCurrentIndexChanged(int))); setStatus(type); } /** * \brief Set currently selected status */ void StatusComboBox::setStatus(XMPP::Status::Type type) { if (type == XMPP::Status::FFC && !PsiOptions::instance()->getOption("options.ui.menu.status.chat").toBool()) type = XMPP::Status::Online; else if (type == XMPP::Status::XA && !PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()) type = XMPP::Status::Away; else if (type == XMPP::Status::Invisible && !PsiOptions::instance()->getOption("options.ui.menu.status.invisible").toBool()) type = XMPP::Status::Offline; for (int i = 0; i < count(); ++i) { if (static_cast<XMPP::Status::Type>(itemData(i).toInt()) == type) { setCurrentIndex(i); break; } } } /** * \brief Read currently selected status */ XMPP::Status::Type StatusComboBox::status() const { return static_cast<XMPP::Status::Type>(itemData(currentIndex()).toInt()); } // private void StatusComboBox::addStatus(XMPP::Status::Type status){ addItem(status2txt(status), status); } void StatusComboBox::onCurrentIndexChanged(int index) { emit statusChanged(static_cast<XMPP::Status::Type>(itemData(index).toInt())); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/chatdlg.cpp����������������������������������������������������������������������������0000644�0001750�0001750�00000062731�11305557613�013253� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * chatdlg.cpp - dialog for handling chats * Copyright (C) 2001-2007 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "chatdlg.h" #include <QLabel> #include <QCursor> #include <QLineEdit> #include <QToolButton> #include <QLayout> #include <QSplitter> #include <QToolBar> #include <QTimer> #include <QDateTime> #include <QPixmap> #include <QColor> #include <Qt> #include <QCloseEvent> #include <QList> #include <QKeyEvent> #include <QHBoxLayout> #include <QDropEvent> #include <QList> #include <QMessageBox> #include <QShowEvent> #include <QVBoxLayout> #include <QContextMenuEvent> #include <QResizeEvent> #include <QMenu> #include <QDragEnterEvent> #include <QTextDocument> // for Qt::escape() #include <QScrollBar> #include "psiaccount.h" #include "userlist.h" #include "stretchwidget.h" #include "psiiconset.h" #include "iconwidget.h" #include "textutil.h" #include "xmpp_message.h" #include "xmpp_htmlelement.h" #include "fancylabel.h" #include "msgmle.h" #include "iconselect.h" #include "pgputil.h" #include "psicon.h" #include "iconlabel.h" #include "capsmanager.h" #include "iconaction.h" #include "avatars.h" #include "jidutil.h" #include "tabdlg.h" #include "psioptions.h" #include "psitooltip.h" #include "shortcutmanager.h" #include "psicontactlist.h" #include "accountlabel.h" #include "psirichtext.h" #ifdef Q_WS_WIN #include <windows.h> #endif #include "psichatdlg.h" ChatDlg* ChatDlg::create(const Jid& jid, PsiAccount* account, TabManager* tabManager) { ChatDlg* chat = new PsiChatDlg(jid, account, tabManager); chat->init(); return chat; } ChatDlg::ChatDlg(const Jid& jid, PsiAccount* pa, TabManager* tabManager) : TabbableWidget(jid, pa, tabManager) , highlightersInstalled_(false) { if (PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool()) { setAttribute(Qt::WA_MacMetalStyle); } pending_ = 0; keepOpen_ = false; warnSend_ = false; selfDestruct_ = 0; transid_ = -1; key_ = ""; lastWasEncrypted_ = false; status_ = -1; // Message events contactChatState_ = XMPP::StateNone; lastChatState_ = XMPP::StateNone; sendComposingEvents_ = false; isComposing_ = false; composingTimer_ = 0; } void ChatDlg::init() { initUi(); initActions(); setShortcuts(); // TODO: this have to be moved to chatEditCreated() chatView()->setDialog(this); chatEdit()->setDialog(this); chatEdit()->installEventFilter(this); connect(chatView(), SIGNAL(selectionChanged()), SLOT(logSelectionChanged())); // SyntaxHighlighters modify the QTextEdit in a QTimer::singleShot(0, ...) call // so we need to install our hooks after it fired for the first time QTimer::singleShot(10, this, SLOT(initComposing())); connect(this, SIGNAL(composing(bool)), SLOT(updateIsComposing(bool))); setAcceptDrops(true); updateContact(jid(), true); X11WM_CLASS("chat"); setLooks(); updatePGP(); connect(account(), SIGNAL(pgpKeyChanged()), SLOT(updatePGP())); connect(account(), SIGNAL(encryptedMessageSent(int, bool, int, const QString &)), SLOT(encryptedMessageSent(int, bool, int, const QString &))); account()->dialogRegister(this, jid()); chatView()->setFocusPolicy(Qt::NoFocus); chatEdit()->setFocus(); // TODO: port to restoreSavedSize() (and adapt it from restoreSavedGeometry()) QSize size = PsiOptions::instance()->getOption("options.ui.chat.size").toSize(); if (!size.isEmpty()) { resize(size); } else { resize(defaultSize()); } } ChatDlg::~ChatDlg() { account()->dialogUnregister(this); } void ChatDlg::initComposing() { highlightersInstalled_ = true; chatEditCreated(); } void ChatDlg::initActions() { act_send_ = new QAction(this); addAction(act_send_); connect(act_send_, SIGNAL(triggered()), SLOT(doSend())); act_close_ = new QAction(this); addAction(act_close_); connect(act_close_, SIGNAL(triggered()), SLOT(close())); act_scrollup_ = new QAction(this); addAction(act_scrollup_); connect(act_scrollup_, SIGNAL(triggered()), SLOT(scrollUp())); act_scrolldown_ = new QAction(this); addAction(act_scrolldown_); connect(act_scrolldown_, SIGNAL(triggered()), SLOT(scrollDown())); } void ChatDlg::ensureTabbedCorrectly() { TabbableWidget::ensureTabbedCorrectly(); setShortcuts(); } void ChatDlg::setShortcuts() { act_send_->setShortcuts(ShortcutManager::instance()->shortcuts("chat.send")); act_scrollup_->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-up")); act_scrolldown_->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-down")); if(!isTabbed()) { act_close_->setShortcuts(ShortcutManager::instance()->shortcuts("common.close")); } else { act_close_->QAction::setShortcuts (QList<QKeySequence>()); } } void ChatDlg::scrollUp() { chatView()->verticalScrollBar()->setValue(chatView()->verticalScrollBar()->value() - chatView()->verticalScrollBar()->pageStep() / 2); } void ChatDlg::scrollDown() { chatView()->verticalScrollBar()->setValue(chatView()->verticalScrollBar()->value() + chatView()->verticalScrollBar()->pageStep() / 2); } void ChatDlg::resizeEvent(QResizeEvent *e) { if (PsiOptions::instance()->getOption("options.ui.remember-window-sizes").toBool()) { PsiOptions::instance()->setOption("options.ui.chat.size", e->size()); } } void ChatDlg::closeEvent(QCloseEvent *e) { if (readyToHide()) { e->accept(); } else { e->ignore(); } } /** * Runs all the gumph necessary before hiding a chat. * (checking new messages, setting the autodelete, cancelling composing etc) * \return ChatDlg is ready to be hidden. */ bool ChatDlg::readyToHide() { // really lame way of checking if we are encrypting if (!chatEdit()->isEnabled()) { return false; } if (keepOpen_) { QMessageBox mb(QMessageBox::Information, tr("Warning"), tr("A new chat message was just received.\nDo you still want to close the window?"), QMessageBox::Cancel, this); mb.addButton(tr("Close"), QMessageBox::AcceptRole); if (mb.exec() == QMessageBox::Cancel) { return false; } } keepOpen_ = false; // tabdlg calls readyToHide twice on tabdlg close, only display message once. // destroy the dialog if delChats is dcClose if (PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "instant") { setAttribute(Qt::WA_DeleteOnClose); } else { if (PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "hour") { setSelfDestruct(60); } else if (PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "day") { setSelfDestruct(60 * 24); } } // Reset 'contact is composing' & cancel own composing event resetComposing(); setChatState(StateGone); if (contactChatState_ == XMPP::StateComposing || contactChatState_ == XMPP::StateInactive) { setContactChatState(StatePaused); } if (pending_ > 0) { pending_ = 0; messagesRead(jid()); invalidateTab(); } doFlash(false); chatEdit()->setFocus(); return true; } void ChatDlg::capsChanged(const Jid& j) { if (jid().compare(j, false)) { capsChanged(); } } void ChatDlg::capsChanged() { } void ChatDlg::hideEvent(QHideEvent* e) { if (isMinimized()) { resetComposing(); setChatState(StateInactive); } TabbableWidget::hideEvent(e); } void ChatDlg::showEvent(QShowEvent *) { setSelfDestruct(0); } void ChatDlg::logSelectionChanged() { #ifdef Q_WS_MAC // A hack to only give the message log focus when text is selected if (chatView()->textCursor().hasSelection()) { chatView()->setFocus(); } else { chatEdit()->setFocus(); } #endif } void ChatDlg::deactivated() { TabbableWidget::deactivated(); } void ChatDlg::activated() { TabbableWidget::activated(); if (pending_ > 0) { pending_ = 0; messagesRead(jid()); invalidateTab(); } doFlash(false); chatEdit()->setFocus(); } void ChatDlg::dropEvent(QDropEvent* event) { QStringList files; if (account()->loggedIn() && event->mimeData()->hasUrls()) { foreach(QUrl url, event->mimeData()->urls()) { if (!url.toLocalFile().isEmpty()) { files << url.toLocalFile(); } } } if (!files.isEmpty()) { account()->actionSendFiles(jid(), files); } } void ChatDlg::dragEnterEvent(QDragEnterEvent* event) { Q_ASSERT(event); bool accept = false; if (account()->loggedIn() && event->mimeData()->hasUrls()) { foreach(QUrl url, event->mimeData()->urls()) { if (!url.toLocalFile().isEmpty()) { event->accept(); break; } } } } void ChatDlg::setJid(const Jid &j) { if (!j.compare(jid())) { account()->dialogUnregister(this); TabbableWidget::setJid(j); account()->dialogRegister(this, jid()); updateContact(jid(), false); } } const QString& ChatDlg::getDisplayName() { return dispNick_; } QSize ChatDlg::defaultSize() { return QSize(320, 280); } struct UserStatus { UserStatus() : userListItem(0) , statusType(XMPP::Status::Offline) {} UserListItem* userListItem; XMPP::Status::Type statusType; QString status; QString publicKeyID; }; UserStatus userStatusFor(const Jid& jid, QList<UserListItem*> ul, bool forceEmptyResource) { if (ul.isEmpty()) return UserStatus(); UserStatus u; u.userListItem = ul.first(); if (jid.resource().isEmpty() || forceEmptyResource) { // use priority if (u.userListItem->isAvailable()) { const UserResource &r = *u.userListItem->userResourceList().priority(); u.statusType = r.status().type(); u.status = r.status().status(); u.publicKeyID = r.publicKeyID(); } } else { // use specific UserResourceList::ConstIterator rit = u.userListItem->userResourceList().find(jid.resource()); if (rit != u.userListItem->userResourceList().end()) { u.statusType = (*rit).status().type(); u.status = (*rit).status().status(); u.publicKeyID = (*rit).publicKeyID(); } } if (u.statusType == XMPP::Status::Offline) u.status = u.userListItem->lastUnavailableStatus().status(); return u; } void ChatDlg::updateContact(const Jid &j, bool fromPresence) { // if groupchat, only update if the resource matches if (account()->findGCContact(j) && !jid().compare(j)) { return; } if (jid().compare(j, false)) { QList<UserListItem*> ul = account()->findRelevant(j); UserStatus userStatus = userStatusFor(jid(), ul, false); if (userStatus.statusType == XMPP::Status::Offline) contactChatState_ = XMPP::StateNone; bool statusChanged = false; if (status_ != userStatus.statusType || statusString_ != userStatus.status) { statusChanged = true; status_ = userStatus.statusType; statusString_ = userStatus.status; } contactUpdated(userStatus.userListItem, userStatus.statusType, userStatus.status); if (userStatus.userListItem) { dispNick_ = JIDUtil::nickOrJid(userStatus.userListItem->name(), userStatus.userListItem->jid().full()); nicksChanged(); invalidateTab(); key_ = userStatus.publicKeyID; updatePGP(); if (fromPresence && statusChanged) { QString msg = tr("%1 is %2").arg(Qt::escape(dispNick_)).arg(status2txt(status_)); if (!statusString_.isEmpty()) { QString ss = TextUtil::linkify(TextUtil::plain2rich(statusString_)); if (PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool()) { ss = TextUtil::emoticonify(ss); } if (PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool()) { ss = TextUtil::legacyFormat(ss); } msg += QString(" [%1]").arg(ss); } appendSysMsg(msg); } } // Update capabilities capsChanged(jid()); // Reset 'is composing' event if the status changed if (statusChanged && contactChatState_ != XMPP::StateNone) { if (contactChatState_ == XMPP::StateComposing || contactChatState_ == XMPP::StateInactive) { setContactChatState(XMPP::StatePaused); } } } } void ChatDlg::contactUpdated(UserListItem* u, int status, const QString& statusString) { Q_UNUSED(u); Q_UNUSED(status); Q_UNUSED(statusString); } void ChatDlg::doVoice() { aVoice(jid()); } void ChatDlg::updateAvatar(const Jid& j) { if (j.compare(jid(), false)) updateAvatar(); } void ChatDlg::setLooks() { // update the font QFont f; f.fromString(PsiOptions::instance()->getOption("options.ui.look.font.chat").toString()); chatView()->setFont(f); chatEdit()->setFont(f); // update contact info status_ = -2; // sick way of making it redraw the status updateContact(jid(), false); // update the widget icon #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/start-chat").icon()); #endif /*QBrush brush; brush.setPixmap( QPixmap( LEGOPTS.chatBgImage ) ); chatView()->setPaper(brush); chatView()->setStaticBackground(true);*/ setWindowOpacity(double(qMax(MINIMUM_OPACITY, PsiOptions::instance()->getOption("options.ui.chat.opacity").toInt())) / 100); } void ChatDlg::optionsUpdate() { setLooks(); setShortcuts(); if (isHidden()) { if (PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "instant") { deleteLater(); return; } else { if (PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "hour") { setSelfDestruct(60); } else if (PsiOptions::instance()->getOption("options.ui.chat.delete-contents-after").toString() == "day") { setSelfDestruct(60 * 24); } else { setSelfDestruct(0); } } } } void ChatDlg::updatePGP() { } void ChatDlg::doInfo() { aInfo(jid()); } void ChatDlg::doHistory() { aHistory(jid()); } void ChatDlg::doFile() { aFile(jid()); } void ChatDlg::doClear() { chatView()->clear(); } void ChatDlg::setKeepOpenFalse() { keepOpen_ = false; } void ChatDlg::setWarnSendFalse() { warnSend_ = false; } void ChatDlg::setSelfDestruct(int minutes) { if (minutes <= 0) { if (selfDestruct_) { delete selfDestruct_; selfDestruct_ = 0; } return; } if (!selfDestruct_) { selfDestruct_ = new QTimer(this); connect(selfDestruct_, SIGNAL(timeout()), SLOT(deleteLater())); } selfDestruct_->start(minutes * 60000); } QString ChatDlg::desiredCaption() const { QString cap = ""; if (pending_ > 0) { cap += "* "; if (pending_ > 1) { cap += QString("[%1] ").arg(pending_); } } cap += dispNick_; if (contactChatState_ == XMPP::StateComposing) { cap = tr("%1 (Composing ...)").arg(cap); } else if (contactChatState_ == XMPP::StateInactive) { cap = tr("%1 (Inactive)").arg(cap); } return cap; } void ChatDlg::invalidateTab() { TabbableWidget::invalidateTab(); } bool ChatDlg::isEncryptionEnabled() const { return false; } void ChatDlg::doSend() { if (!chatEdit()->isEnabled()) { return; } if (chatEdit()->toPlainText().isEmpty()) { return; } if (chatEdit()->toPlainText() == "/clear") { chatEdit()->clear(); doClear(); QString line1,line2; MiniCommand_Depreciation_Message("/clear", "clear", line1, line2); appendSysMsg(line1); appendSysMsg(line2); return; } if (!account()->loggedIn()) { return; } if (warnSend_) { warnSend_ = false; int n = QMessageBox::information(this, tr("Warning"), tr( "<p>Encryption was recently disabled by the remote contact. " "Are you sure you want to send this message without encryption?</p>" ), tr("&Yes"), tr("&No")); if (n != 0) { return; } } Message m(jid()); m.setType("chat"); m.setBody(chatEdit()->toPlainText()); m.setTimeStamp(QDateTime::currentDateTime()); if (isEncryptionEnabled()) { m.setWasEncrypted(true); } m_ = m; // Request events if (PsiOptions::instance()->getOption("options.messages.send-composing-events").toBool()) { // Only request more events when really necessary if (sendComposingEvents_) { m.addEvent(ComposingEvent); } m.setChatState(XMPP::StateActive); } // Update current state setChatState(XMPP::StateActive); if (isEncryptionEnabled()) { chatEdit()->setEnabled(false); transid_ = account()->sendMessageEncrypted(m); if (transid_ == -1) { chatEdit()->setEnabled(true); chatEdit()->setFocus(); return; } } else { aSend(m); doneSend(); } chatEdit()->setFocus(); } void ChatDlg::doneSend() { appendMessage(m_, true); disconnect(chatEdit(), SIGNAL(textChanged()), this, SLOT(setComposing())); chatEdit()->clear(); // Reset composing timer connect(chatEdit(), SIGNAL(textChanged()), this, SLOT(setComposing())); // Reset composing timer resetComposing(); } void ChatDlg::encryptedMessageSent(int x, bool b, int e, const QString &dtext) { if (transid_ == -1 || transid_ != x) { return; } transid_ = -1; if (b) { doneSend(); } else { PGPUtil::showDiagnosticText(static_cast<QCA::SecureMessage::Error>(e), dtext); } chatEdit()->setEnabled(true); chatEdit()->setFocus(); } void ChatDlg::incomingMessage(const Message &m) { if (m.body().isEmpty()) { // Event message if (m.containsEvent(CancelEvent)) { setContactChatState(XMPP::StatePaused); } else if (m.containsEvent(ComposingEvent)) { setContactChatState(XMPP::StateComposing); } if (m.chatState() != XMPP::StateNone) { setContactChatState(m.chatState()); } } else { // Normal message // Check if user requests event messages sendComposingEvents_ = m.containsEvent(ComposingEvent); if (!m.eventId().isEmpty()) { eventId_ = m.eventId(); } if (m.containsEvents() || m.chatState() != XMPP::StateNone) { setContactChatState(XMPP::StateActive); } else { setContactChatState(XMPP::StateNone); } appendMessage(m); } } void ChatDlg::setPGPEnabled(bool enabled) { Q_UNUSED(enabled); } QString ChatDlg::whoNick(bool local) const { QString result; if (local) { result = account()->nick(); } else { result = dispNick_; } return Qt::escape(result); } void ChatDlg::appendMessage(const Message &m, bool local) { // figure out the encryption state bool encChanged = false; bool encEnabled = false; if (lastWasEncrypted_ != m.wasEncrypted()) { encChanged = true; } lastWasEncrypted_ = m.wasEncrypted(); encEnabled = lastWasEncrypted_; if (encChanged) { if (encEnabled) { appendSysMsg(QString("<icon name=\"psi/cryptoYes\"> ") + tr("Encryption Enabled")); if (!local) { setPGPEnabled(true); } } else { appendSysMsg(QString("<icon name=\"psi/cryptoNo\"> ") + tr("Encryption Disabled")); if (!local) { setPGPEnabled(false); // enable warning warnSend_ = true; QTimer::singleShot(3000, this, SLOT(setWarnSendFalse())); } } } QString txt = messageText(m); ChatDlg::SpooledType spooledType = m.spooled() ? ChatDlg::Spooled_OfflineStorage : ChatDlg::Spooled_None; if (isEmoteMessage(m)) appendEmoteMessage(spooledType, m.timeStamp(), local, txt); else appendNormalMessage(spooledType, m.timeStamp(), local, txt); appendMessageFields(m); if (local) { deferredScroll(); } // if we're not active, notify the user by changing the title if (!isActiveTab()) { ++pending_; invalidateTab(); if (PsiOptions::instance()->getOption("options.ui.flash-windows").toBool()) { doFlash(true); } if (PsiOptions::instance()->getOption("options.ui.chat.raise-chat-windows-on-new-messages").toBool()) { if (isTabbed()) { TabDlg* tabSet = getManagingTabDlg(); tabSet->selectTab(this); ::bringToFront(tabSet, false); } else { ::bringToFront(this, false); } } } //else { // messagesRead(jid()); //} if (!local) { keepOpen_ = true; QTimer::singleShot(1000, this, SLOT(setKeepOpenFalse())); } } void ChatDlg::deferredScroll() { QTimer::singleShot(250, this, SLOT(slotScroll())); } void ChatDlg::slotScroll() { chatView()->scrollToBottom(); } void ChatDlg::updateIsComposing(bool b) { setChatState(b ? XMPP::StateComposing : XMPP::StatePaused); } void ChatDlg::setChatState(ChatState state) { if (PsiOptions::instance()->getOption("options.messages.send-composing-events").toBool() && (sendComposingEvents_ || (contactChatState_ != XMPP::StateNone))) { // Don't send to offline resource QList<UserListItem*> ul = account()->findRelevant(jid()); if (ul.isEmpty()) { sendComposingEvents_ = false; lastChatState_ = XMPP::StateNone; return; } UserListItem *u = ul.first(); if (!u->isAvailable()) { sendComposingEvents_ = false; lastChatState_ = XMPP::StateNone; return; } // Transform to more privacy-enabled chat states if necessary if (!PsiOptions::instance()->getOption("options.messages.send-inactivity-events").toBool() && (state == XMPP::StateGone || state == XMPP::StateInactive)) { state = XMPP::StatePaused; } if (lastChatState_ == XMPP::StateNone && (state != XMPP::StateActive && state != XMPP::StateComposing && state != XMPP::StateGone)) { //this isn't a valid transition, so don't send it, and don't update laststate return; } // Check if we should send a message if (state == lastChatState_ || state == XMPP::StateActive || (lastChatState_ == XMPP::StateActive && state == XMPP::StatePaused)) { lastChatState_ = state; return; } // Build event message Message m(jid()); if (sendComposingEvents_) { m.setEventId(eventId_); if (state == XMPP::StateComposing) { m.addEvent(ComposingEvent); } else if (lastChatState_ == XMPP::StateComposing) { m.addEvent(CancelEvent); } } if (contactChatState_ != XMPP::StateNone) { if (lastChatState_ != XMPP::StateGone) { if ((state == XMPP::StateInactive && lastChatState_ == XMPP::StateComposing) || (state == XMPP::StateComposing && lastChatState_ == XMPP::StateInactive)) { // First go to the paused state Message tm(jid()); m.setType("chat"); m.setChatState(XMPP::StatePaused); if (account()->isAvailable()) { account()->dj_sendMessage(m, false); } } m.setChatState(state); } } // Send event message if (m.containsEvents() || m.chatState() != XMPP::StateNone) { m.setType("chat"); if (account()->isAvailable()) { account()->dj_sendMessage(m, false); } } // Save last state if (lastChatState_ != XMPP::StateGone || state == XMPP::StateActive) lastChatState_ = state; } } void ChatDlg::setContactChatState(ChatState state) { contactChatState_ = state; if (state == XMPP::StateGone) { appendSysMsg(tr("%1 ended the conversation").arg(Qt::escape(dispNick_))); } else { // Activate ourselves if (lastChatState_ == XMPP::StateGone) { setChatState(XMPP::StateActive); } } invalidateTab(); } bool ChatDlg::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { keyPressEvent(static_cast<QKeyEvent*>(event)); if (event->isAccepted()) return true; } if (chatView()->handleCopyEvent(obj, event, chatEdit())) return true; return QWidget::eventFilter(obj, event); } void ChatDlg::addEmoticon(QString text) { if (!isActiveTab()) return; PsiRichText::addEmoticon(chatEdit(), text); } /** * Records that the user is composing */ void ChatDlg::setComposing() { if (!composingTimer_) { /* User (re)starts composing */ composingTimer_ = new QTimer(this); connect(composingTimer_, SIGNAL(timeout()), SLOT(checkComposing())); composingTimer_->start(2000); // FIXME: magic number emit composing(true); } isComposing_ = true; } /** * Checks if the user is still composing */ void ChatDlg::checkComposing() { if (!isComposing_) { // User stopped composing composingTimer_->deleteLater(); composingTimer_ = 0; emit composing(false); } isComposing_ = false; // Reset composing } void ChatDlg::resetComposing() { if (composingTimer_) { delete composingTimer_; composingTimer_ = 0; isComposing_ = false; } } PsiAccount* ChatDlg::account() const { return TabbableWidget::account(); } void ChatDlg::nicksChanged() { // this function is intended to be reimplemented in subclasses } static const QString me_cmd = "/me "; bool ChatDlg::isEmoteMessage(const XMPP::Message& m) { if (m.body().startsWith(me_cmd) || m.html().text().trimmed().startsWith(me_cmd)) return true; return false; } QString ChatDlg::messageText(const XMPP::Message& m) { bool emote = isEmoteMessage(m); QString txt; if (m.containsHTML() && PsiOptions::instance()->getOption("options.html.chat.render").toBool() && !m.html().text().isEmpty()) { txt = m.html().toString("span"); if (emote) { int cmd = txt.indexOf(me_cmd); txt = txt.remove(cmd, me_cmd.length()); } // qWarning("html body:\n%s\n",qPrintable(txt)); } else { txt = m.body(); if (emote) txt = txt.mid(me_cmd.length()); txt = TextUtil::plain2rich(txt); txt = TextUtil::linkify(txt); // qWarning("regular body:\n%s\n",qPrintable(txt)); } if (PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool()) txt = TextUtil::emoticonify(txt); if (PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool()) txt = TextUtil::legacyFormat(txt); return txt; } void ChatDlg::chatEditCreated() { chatView()->setDialog(this); chatEdit()->setDialog(this); if (highlightersInstalled_) { connect(chatEdit(), SIGNAL(textChanged()), this, SLOT(setComposing())); } } TabbableWidget::State ChatDlg::state() const { return contactChatState_ == XMPP::StateComposing ? TabbableWidget::StateComposing : TabbableWidget::StateNone; } int ChatDlg::unreadMessageCount() const { return pending_; } ���������������������������������������psi-0.14/src/mainwin_p.h����������������������������������������������������������������������������0000644�0001750�0001750�00000006750�11305557613�013272� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * mainwin_p.h - classes used privately by the main window. * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MAINWIN_P_H #include <QPushButton> #include <QToolButton> #include <QMenu> #include <QLayout> #include <QLabel> #include <QAction> #include <QMouseEvent> #include "psicon.h" #include "iconaction.h" class QMenu; class SeparatorAction : public IconAction { Q_OBJECT public: SeparatorAction(QObject *parent, const char *name = 0); ~SeparatorAction(); virtual bool addTo(QWidget *w); virtual IconAction *copy() const; private: class Private; Private *d; }; class SpacerAction : public IconAction { Q_OBJECT public: SpacerAction(QObject *parent, const char *name = 0); ~SpacerAction(); virtual bool addTo (QWidget *w); virtual IconAction *copy() const; }; class EventNotifierAction : public IconAction { Q_OBJECT public: EventNotifierAction(QObject *parent, const char *name = 0); ~EventNotifierAction(); void setMessage(const QString &); bool addTo (QWidget *w); void hide(); void show(); void updateVisibility(); virtual IconAction *copy() const; virtual EventNotifierAction &operator=( const EventNotifierAction & ); signals: void clicked(int); private slots: void objectDestroyed (); private: class Private; Private *d; }; class PopupAction : public IconAction { Q_OBJECT private: class Private; Private *d; private slots: void objectDestroyed (); public slots: void setEnabled (bool); public: PopupAction (const QString &label, QMenu *_menu, QObject *parent, const char *name); void setSizePolicy (const QSizePolicy &p); void setAlert (const PsiIcon *); void setIcon (const PsiIcon *, bool showText = true, bool alert = false); void setText (const QString &text); bool addTo (QWidget *w); virtual IconAction *copy() const; virtual PopupAction &operator=( const PopupAction & ); }; class MLabel : public QLabel { Q_OBJECT public: MLabel(QWidget *parent=0, const char *name=0); protected: // reimplemented void mouseReleaseEvent(QMouseEvent *); void mouseDoubleClickEvent(QMouseEvent *); signals: void clicked(int); void doubleClicked(); }; class MAction : public IconActionGroup { Q_OBJECT public: MAction(PsiIcon, const QString &, int id, PsiCon *, QObject *parent); MAction(const QString &, int id, PsiCon *, QObject *parent); // reimplemented virtual bool addTo(QWidget *); virtual IconAction *copy() const; virtual MAction &operator=( const MAction & ); signals: void activated(PsiAccount *, int); private slots: void numAccountsChanged(); void actionActivated(); void slotActivated(); protected: // reimplemented virtual void doSetMenu(QMenu* menu); private: int id_; PsiCon* controller_; void init(const QString& name, PsiIcon, int id, PsiCon* psi); QList<PsiAccount*> accounts() const; }; #endif ������������������������psi-0.14/src/psimedia/������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�012723� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psimedia/psimedia.pri������������������������������������������������������������������0000644�0001750�0001750�00000000135�11305557613�015231� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������HEADERS += \ $$PWD/psimedia.h \ $$PWD/psimediaprovider.h SOURCES += \ $$PWD/psimedia.cpp �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psimedia/psimediaprovider.h������������������������������������������������������������0000644�0001750�0001750�00000015373�11305557613�016453� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008-2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef PSIMEDIAPROVIDER_H #define PSIMEDIAPROVIDER_H #include <QString> #include <QList> #include <QByteArray> #include <QSize> #include <QObject> class QImage; class QIODevice; #ifdef QT_GUI_LIB class QWidget; class QPainter; #endif // since we cannot put signals/slots in Qt "interfaces", we use the following // defines to hint about signals/slots that derived classes should provide #define HINT_SIGNALS protected #define HINT_PUBLIC_SLOTS public #define HINT_METHOD(x) namespace PsiMedia { class Provider; class FeaturesContext; class RtpSessionContext; class Plugin { public: virtual ~Plugin() {} virtual Provider *createProvider() = 0; }; class QObjectInterface { public: virtual ~QObjectInterface() {} virtual QObject *qobject() = 0; }; class PDevice { public: enum Type { AudioOut, AudioIn, VideoIn }; Type type; QString name; QString id; }; class PAudioParams { public: QString codec; int sampleRate; int sampleSize; int channels; inline PAudioParams() : sampleRate(0), sampleSize(0), channels(0) { } }; class PVideoParams { public: QString codec; QSize size; int fps; inline PVideoParams() : fps(0) { } }; class PFeatures { public: QList<PDevice> audioOutputDevices; QList<PDevice> audioInputDevices; QList<PDevice> videoInputDevices; QList<PAudioParams> supportedAudioModes; QList<PVideoParams> supportedVideoModes; }; class PPayloadInfo { public: class Parameter { public: QString name; QString value; }; int id; QString name; int clockrate; int channels; int ptime; int maxptime; QList<Parameter> parameters; inline PPayloadInfo() : id(-1), clockrate(-1), channels(-1), ptime(-1), maxptime(-1) { } }; class PRtpPacket { public: QByteArray rawValue; int portOffset; inline PRtpPacket() : portOffset(0) { } }; class Provider : public QObjectInterface { public: virtual bool init(const QString &resourcePath) = 0; virtual QString creditName() = 0; virtual QString creditText() = 0; virtual FeaturesContext *createFeatures() = 0; virtual RtpSessionContext *createRtpSession() = 0; }; class FeaturesContext : public QObjectInterface { public: enum Type { AudioOut = 0x01, AudioIn = 0x02, VideoIn = 0x04, AudioModes = 0x08, VideoModes = 0x10 }; virtual void lookup(int types) = 0; virtual bool waitForFinished(int msecs) = 0; // -1 = no timeout virtual PFeatures results() const = 0; HINT_SIGNALS: HINT_METHOD(finished()) }; class RtpChannelContext : public QObjectInterface { public: virtual void setEnabled(bool b) = 0; virtual int packetsAvailable() const = 0; virtual PRtpPacket read() = 0; virtual void write(const PRtpPacket &rtp) = 0; HINT_SIGNALS: HINT_METHOD(readyRead()) HINT_METHOD(packetsWritten(int count)) }; #ifdef QT_GUI_LIB class VideoWidgetContext : public QObjectInterface { public: virtual QWidget *qwidget() = 0; // this function causes VideoWidget::videoSizeChanged() to be emitted virtual void setVideoSize(const QSize &size) = 0; HINT_SIGNALS: HINT_METHOD(resized(const QSize &newSize)) // listener must use a direct connection and paint during the signal HINT_METHOD(paintEvent(QPainter *p)) }; #endif class RtpSessionContext : public QObjectInterface { public: enum Error { ErrorGeneric, ErrorSystem, ErrorCodec }; virtual void setAudioOutputDevice(const QString &deviceId) = 0; virtual void setAudioInputDevice(const QString &deviceId) = 0; virtual void setVideoInputDevice(const QString &deviceId) = 0; virtual void setFileInput(const QString &fileName) = 0; virtual void setFileDataInput(const QByteArray &fileData) = 0; virtual void setFileLoopEnabled(bool enabled) = 0; #ifdef QT_GUI_LIB virtual void setVideoOutputWidget(VideoWidgetContext *widget) = 0; virtual void setVideoPreviewWidget(VideoWidgetContext *widget) = 0; #endif virtual void setRecorder(QIODevice *recordDevice) = 0; virtual void stopRecording() = 0; virtual void setLocalAudioPreferences(const QList<PAudioParams> ¶ms) = 0; virtual void setLocalVideoPreferences(const QList<PVideoParams> ¶ms) = 0; virtual void setMaximumSendingBitrate(int kbps) = 0; virtual void setRemoteAudioPreferences(const QList<PPayloadInfo> &info) = 0; virtual void setRemoteVideoPreferences(const QList<PPayloadInfo> &info) = 0; virtual void start() = 0; virtual void updatePreferences() = 0; virtual void transmitAudio() = 0; virtual void transmitVideo() = 0; virtual void pauseAudio() = 0; virtual void pauseVideo() = 0; virtual void stop() = 0; virtual QList<PPayloadInfo> localAudioPayloadInfo() const = 0; virtual QList<PPayloadInfo> localVideoPayloadInfo() const = 0; virtual QList<PPayloadInfo> remoteAudioPayloadInfo() const = 0; virtual QList<PPayloadInfo> remoteVideoPayloadInfo() const = 0; virtual QList<PAudioParams> audioParams() const = 0; virtual QList<PVideoParams> videoParams() const = 0; virtual bool canTransmitAudio() const = 0; virtual bool canTransmitVideo() const = 0; virtual int outputVolume() const = 0; // 0 (mute) to 100 virtual void setOutputVolume(int level) = 0; virtual int inputVolume() const = 0; // 0 (mute) to 100 virtual void setInputVolume(int level) = 0; virtual Error errorCode() const = 0; virtual RtpChannelContext *audioRtpChannel() = 0; virtual RtpChannelContext *videoRtpChannel() = 0; HINT_SIGNALS: HINT_METHOD(started()) HINT_METHOD(preferencesUpdated()) HINT_METHOD(audioOutputIntensityChanged(int intensity)) HINT_METHOD(audioInputIntensityChanged(int intensity)) HINT_METHOD(stoppedRecording()) HINT_METHOD(stopped()) HINT_METHOD(finished()) // for file playback only HINT_METHOD(error()) }; } Q_DECLARE_INTERFACE(PsiMedia::Plugin, "org.psi-im.psimedia.Plugin/1.0") Q_DECLARE_INTERFACE(PsiMedia::Provider, "org.psi-im.psimedia.Provider/1.0") Q_DECLARE_INTERFACE(PsiMedia::FeaturesContext, "org.psi-im.psimedia.FeaturesContext/1.0") Q_DECLARE_INTERFACE(PsiMedia::RtpChannelContext, "org.psi-im.psimedia.RtpChannelContext/1.0") Q_DECLARE_INTERFACE(PsiMedia::RtpSessionContext, "org.psi-im.psimedia.RtpSessionContext/1.0") #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psimedia/psimedia.h��������������������������������������������������������������������0000644�0001750�0001750�00000032232�11305557613�014671� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008-2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef PSIMEDIA_H #define PSIMEDIA_H #include <QSize> #include <QStringList> #include <QSharedDataPointer> #ifdef QT_GUI_LIB #include <QWidget> #endif namespace PsiMedia { class RtpSession; class RtpSessionPrivate; class VideoWidgetPrivate; class RtpChannelPrivate; enum PluginResult { PluginSuccess, ErrorLoad, ErrorVersion, ErrorInit }; bool isSupported(); PluginResult loadPlugin(const QString &fname, const QString &resourcePath); void unloadPlugin(); QString creditName(); QString creditText(); class Device { public: enum Type { AudioOut, // speaker AudioIn, // microphone VideoIn // camera }; Device(); Device(const Device &other); ~Device(); Device & operator=(const Device &other); bool isNull() const; Type type() const; QString name() const; QString id() const; private: class Private; friend class Global; Private *d; }; #ifdef QT_GUI_LIB class VideoWidget : public QWidget { Q_OBJECT public: VideoWidget(QWidget *parent = 0); ~VideoWidget(); virtual QSize sizeHint() const; protected: virtual void paintEvent(QPaintEvent *event); virtual void resizeEvent(QResizeEvent *event); signals: // check the size hint after receiving this signal void videoSizeChanged(); private: Q_DISABLE_COPY(VideoWidget); friend class VideoWidgetPrivate; friend class RtpSession; VideoWidgetPrivate *d; }; #endif class AudioParams { public: AudioParams(); AudioParams(const AudioParams &other); ~AudioParams(); AudioParams & operator=(const AudioParams &other); QString codec() const; int sampleRate() const; int sampleSize() const; int channels() const; void setCodec(const QString &s); void setSampleRate(int n); void setSampleSize(int n); void setChannels(int n); bool operator==(const AudioParams &other) const; inline bool operator!=(const AudioParams &other) const { return !(*this == other); } private: class Private; Private *d; }; class VideoParams { public: VideoParams(); VideoParams(const VideoParams &other); ~VideoParams(); VideoParams & operator=(const VideoParams &other); QString codec() const; QSize size() const; int fps() const; void setCodec(const QString &s); void setSize(const QSize &s); void setFps(int n); bool operator==(const VideoParams &other) const; inline bool operator!=(const VideoParams &other) const { return !(*this == other); } private: class Private; Private *d; }; class Features : public QObject { Q_OBJECT public: enum Type { AudioOut = 0x01, AudioIn = 0x02, VideoIn = 0x04, AudioModes = 0x08, VideoModes = 0x10, All = 0xff }; Features(QObject *parent = 0); ~Features(); void lookup(int types = All); bool waitForFinished(int msecs = -1); QList<Device> audioOutputDevices(); QList<Device> audioInputDevices(); QList<Device> videoInputDevices(); QList<AudioParams> supportedAudioModes(); QList<VideoParams> supportedVideoModes(); signals: void finished(); private: class Private; friend class Private; Private *d; }; class RtpPacket { public: RtpPacket(); RtpPacket(const QByteArray &rawValue, int portOffset); RtpPacket(const RtpPacket &other); ~RtpPacket(); RtpPacket & operator=(const RtpPacket &other); bool isNull() const; QByteArray rawValue() const; int portOffset() const; private: class Private; QSharedDataPointer<Private> d; }; // may drop packets if not read fast enough. // may queue no packets at all, if nobody is listening to readyRead. class RtpChannel : public QObject { Q_OBJECT public: int packetsAvailable() const; RtpPacket read(); void write(const RtpPacket &rtp); signals: void readyRead(); void packetsWritten(int count); protected: virtual void connectNotify(const char *signal); virtual void disconnectNotify(const char *signal); private: RtpChannel(); ~RtpChannel(); Q_DISABLE_COPY(RtpChannel); friend class RtpSession; friend class RtpSessionPrivate; friend class RtpChannelPrivate; RtpChannelPrivate *d; }; // this class essentially follows jingle's notion of payload information, // though it's not really jingle-specific and should be usable for any RTP // purpose class PayloadInfo { public: class Parameter { public: QString name; QString value; bool operator==(const Parameter &other) const; inline bool operator!=(const Parameter &other) const { return !(*this == other); } }; PayloadInfo(); PayloadInfo(const PayloadInfo &other); ~PayloadInfo(); PayloadInfo & operator=(const PayloadInfo &other); bool isNull() const; int id() const; QString name() const; int clockrate() const; int channels() const; int ptime() const; int maxptime() const; QList<Parameter> parameters() const; void setId(int i); void setName(const QString &str); void setClockrate(int i); void setChannels(int num); void setPtime(int i); void setMaxptime(int i); void setParameters(const QList<Parameter> ¶ms); bool operator==(const PayloadInfo &other) const; inline bool operator!=(const PayloadInfo &other) const { return !(*this == other); } private: class Private; Private *d; }; class RtpSession : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, ErrorSystem, ErrorCodec }; RtpSession(QObject *parent = 0); ~RtpSession(); void reset(); void setAudioOutputDevice(const QString &deviceId); #ifdef QT_GUI_LIB void setVideoOutputWidget(VideoWidget *widget); #endif void setAudioInputDevice(const QString &deviceId); void setVideoInputDevice(const QString &deviceId); void setFileInput(const QString &fileName); void setFileDataInput(const QByteArray &fileData); void setFileLoopEnabled(bool enabled); #ifdef QT_GUI_LIB void setVideoPreviewWidget(VideoWidget *widget); #endif // pass a QIODevice to record to. if a device is set before starting // the session, then recording will wait until it starts. // records in ogg theora+vorbis format void setRecordingQIODevice(QIODevice *dev); // stop recording operation. wait for stoppedRecording signal before // QIODevice is released. void stopRecording(); // set local preferences, using fuzzy *params structures. void setLocalAudioPreferences(const QList<AudioParams> ¶ms); void setLocalVideoPreferences(const QList<VideoParams> ¶ms); void setMaximumSendingBitrate(int kbps); // set remote preferences, using payloadinfo. void setRemoteAudioPreferences(const QList<PayloadInfo> &info); void setRemoteVideoPreferences(const QList<PayloadInfo> &info); // usage strategy: // - initiator sets local prefs / bitrate // - initiator starts(), waits for started() // - initiator obtains the corresponding payloadinfos and sends to // target. // - target receives payloadinfos // - target sets local prefs / bitrate, and remote prefs // - target starts(), waits for started() // - target obtains the corresponding payloadinfos, which is mostly // an intersection of initiator/target preferences, and sends to // initiator // - target is ready for use // - initiator receives payloadinfos, sets remote prefs, calls // updatePreferences() and waits for preferencesUpdated() // - initiator ready for use // // after starting, params getter functions will return a number // of objects matching that of the local payloadinfo getters. note // that these objects may not match the original local prefs // params (if any). // // you must set at least one local pref for each media type you want // to support. any fields in params may be left unset, even all of // them. if multiple params structs are specified for a media type, // then this means configurations "in between" what is specified are // allowed. // // note: targets should leave room in the prefs for flexibility in // choosing among the initiator payloadinfos. if a target // specifies exactly one params struct, and leaves no fields empty, // then this will result in very strict choosing. for a given media // type, targets should leave some fields blank or set at least two // params. // // adding audio/video to existing session lacking it: // - set new local prefs as params // - call updatePreferences(), wait for preferencesUpdated() // - obtain corresponding payloadinfos, send to peer // - peer receives payloadinfos, sets local prefs as params, and // remote prefs // - peer calls updatePreferences(), waits for preferencesUpdated() // - peer obtains corresponding payloadinfos (intersection), and // sends back // - receive payloadinfos, set remote prefs, call // updatePreferences() and wait for preferencesUpdated() // // modifying params of existing media types: // - set new local prefs as params // - save original payloadinfos // - call updatePreferences(), wait for preferencesUpdated() // - obtain corresponding payloadinfos, and compare to original to // determine what was added or removed // - send adds/removes to peer // - peer receives payloadinfos, sets remote prefs based on // adds/removes to the original // - peer calls updatePreferences(), waits for preferencesUpdated() // - if there were any adds, peer obtains corresponding payloadinfos // (intersection), and compares to original to determine what was // agreed to be added. // - peer acks back with accepted adds, or rejects // - if reject is received, set original remote prefs // - if accept is received, add the 'adds' to the original remote // prefs and set them // - call updatePreferences(), wait for preferencesUpdated() // // during modification, if a payloadinfo is being removed, then it // is removed from both local/remote payloadinfo. if the peer // transmits with the removed payload type, then it will be // ignored. the local app won't transmit with a removed type. // // during modification, if a payloadinfo is being added, then it // is added only to the local payloadinfo. the app must explicitly // set remote prefs to update the remote payloadinfo (it would // do this after receiving a peer ack). the app won't transmit // using the added payloadinfo until the remote list is updated // as appropriate (more generally, the app won't transmit using a // payloadinfo that is not in the remote list). void start(); // if prefs are changed after starting, this function needs to be // called for them to take effect void updatePreferences(); void transmitAudio(); void transmitVideo(); void pauseAudio(); void pauseVideo(); void stop(); // in a correctly negotiated session, there will be an equal amount of // local/remote values for each media type (during negotiation there // may be a mismatch). however, the payloadinfo for each won't // necessarily match exactly. for example, both sides could be // using theora, but they'll almost certainly have different // parameters. QList<PayloadInfo> localAudioPayloadInfo() const; QList<PayloadInfo> localVideoPayloadInfo() const; QList<PayloadInfo> remoteAudioPayloadInfo() const; QList<PayloadInfo> remoteVideoPayloadInfo() const; // maps to local payloadinfo QList<AudioParams> audioParams() const; QList<VideoParams> videoParams() const; // parameter negotiation is independent of the existence of input and // output devices. you could perform a negotiation without // specifying any input devices, and this just means you won't be // able to transmit until you eventually do specify them. similarly, // you could have specified input devices but then later removed them // (by setting the device id to an empty string). the following // methods can be used to know what media types you're able to send. // in the case of devices, this is somewhat redundant information, // but the methods are useful in the case of using a file as input, // which might have varying media contained. bool canTransmitAudio() const; bool canTransmitVideo() const; // speaker int outputVolume() const; // 0 (mute) to 100 void setOutputVolume(int level); // microphone int inputVolume() const; // 0 (mute) to 100 void setInputVolume(int level); Error errorCode() const; RtpChannel *audioRtpChannel(); RtpChannel *videoRtpChannel(); signals: void started(); void preferencesUpdated(); void audioOutputIntensityChanged(int intensity); // 0-100, -1 for no signal void audioInputIntensityChanged(int intensity); // 0-100 void stoppedRecording(); void stopped(); void finished(); // for file playback only void error(); private: Q_DISABLE_COPY(RtpSession); friend class RtpSessionPrivate; RtpSessionPrivate *d; }; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psimedia/psimedia.cpp������������������������������������������������������������������0000644�0001750�0001750�00000060500�11305557613�015223� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008-2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "psimedia.h" #include <QCoreApplication> #include <QPluginLoader> #ifdef QT_GUI_LIB #include <QPainter> #endif #include "psimediaprovider.h" namespace PsiMedia { static AudioParams importAudioParams(const PAudioParams &pp) { AudioParams out; out.setCodec(pp.codec); out.setSampleRate(pp.sampleRate); out.setSampleSize(pp.sampleSize); out.setChannels(pp.channels); return out; } static PAudioParams exportAudioParams(const AudioParams &p) { PAudioParams out; out.codec = p.codec(); out.sampleRate = p.sampleRate(); out.sampleSize = p.sampleSize(); out.channels = p.channels(); return out; } static VideoParams importVideoParams(const PVideoParams &pp) { VideoParams out; out.setCodec(pp.codec); out.setSize(pp.size); out.setFps(pp.fps); return out; } static PVideoParams exportVideoParams(const VideoParams &p) { PVideoParams out; out.codec = p.codec(); out.size = p.size(); out.fps = p.fps(); return out; } static PayloadInfo importPayloadInfo(const PPayloadInfo &pp) { PayloadInfo out; out.setId(pp.id); out.setName(pp.name); out.setClockrate(pp.clockrate); out.setChannels(pp.channels); out.setPtime(pp.ptime); out.setMaxptime(pp.maxptime); QList<PayloadInfo::Parameter> list; foreach(const PPayloadInfo::Parameter &pi, pp.parameters) { PayloadInfo::Parameter i; i.name = pi.name; i.value = pi.value; list += i; } out.setParameters(list); return out; } static PPayloadInfo exportPayloadInfo(const PayloadInfo &p) { PPayloadInfo out; out.id = p.id(); out.name = p.name(); out.clockrate = p.clockrate(); out.channels = p.channels(); out.ptime = p.ptime(); out.maxptime = p.maxptime(); QList<PPayloadInfo::Parameter> list; foreach(const PayloadInfo::Parameter &i, p.parameters()) { PPayloadInfo::Parameter pi; pi.name = i.name; pi.value = i.value; list += pi; } out.parameters = list; return out; } //---------------------------------------------------------------------------- // Global //---------------------------------------------------------------------------- static Provider *g_provider = 0; static QPluginLoader *g_pluginLoader = 0; static void cleanupProvider(); static Provider *provider() { if(!g_provider) { // static plugin around? Provider *provider = 0; QObjectList list = QPluginLoader::staticInstances(); foreach(QObject *obj, list) { Plugin *instance = qobject_cast<Plugin *>(obj); if(!instance) continue; Provider *p = instance->createProvider(); if(p) { provider = p; break; } } if(provider) { if(!provider->init(QString())) { delete provider; return 0; } g_provider = provider; qAddPostRoutine(cleanupProvider); } } return g_provider; } bool isSupported() { return (provider() ? true : false); } PluginResult loadPlugin(const QString &fname, const QString &resourcePath) { if(g_provider) return PluginSuccess; QPluginLoader *loader = new QPluginLoader(fname); if(!loader->load()) { delete loader; return ErrorLoad; } Plugin *instance = qobject_cast<Plugin *>(loader->instance()); if(!instance) { delete loader; return ErrorVersion; } Provider *provider = instance->createProvider(); if(!provider) { loader->unload(); delete loader; return ErrorInit; } if(!provider->init(resourcePath)) { delete provider; loader->unload(); delete loader; return ErrorInit; } g_provider = provider; g_pluginLoader = loader; qAddPostRoutine(cleanupProvider); return PluginSuccess; } void cleanupProvider() { if(!g_provider) return; delete g_provider; g_provider = 0; if(g_pluginLoader) { g_pluginLoader->unload(); delete g_pluginLoader; g_pluginLoader = 0; } } void unloadPlugin() { cleanupProvider(); } QString creditName() { return provider()->creditName(); } QString creditText() { return provider()->creditText(); } class Device::Private { public: Device::Type type; QString id; QString name; }; class Global { public: static Device importDevice(const PDevice &pd) { Device dev; dev.d = new Device::Private; dev.d->type = (Device::Type)pd.type; dev.d->id = pd.id; dev.d->name = pd.name; return dev; } }; //---------------------------------------------------------------------------- // Device //---------------------------------------------------------------------------- Device::Device() : d(0) { } Device::Device(const Device &other) : d(other.d ? new Private(*other.d) : 0) { } Device::~Device() { delete d; } Device & Device::operator=(const Device &other) { if(d) { if(other.d) { *d = *other.d; } else { delete d; d = 0; } } else { if(other.d) d = new Private(*other.d); } return *this; } bool Device::isNull() const { return (d ? false : true); } Device::Type Device::type() const { return d->type; } QString Device::name() const { return d->name; } QString Device::id() const { return d->id; } #ifdef QT_GUI_LIB //---------------------------------------------------------------------------- // VideoWidget //---------------------------------------------------------------------------- class VideoWidgetPrivate : public QObject, public VideoWidgetContext { Q_OBJECT public: friend class VideoWidget; VideoWidget *q; QSize videoSize; VideoWidgetPrivate(VideoWidget *_q) : QObject(_q), q(_q) { } virtual QObject *qobject() { return this; } virtual QWidget *qwidget() { return q; } virtual void setVideoSize(const QSize &size) { videoSize = size; emit q->videoSizeChanged(); } signals: void resized(const QSize &newSize); void paintEvent(QPainter *p); }; VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { d = new VideoWidgetPrivate(this); } VideoWidget::~VideoWidget() { delete d; } QSize VideoWidget::sizeHint() const { return d->videoSize; } void VideoWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); emit d->paintEvent(&p); } void VideoWidget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); emit d->resized(size()); } #endif //---------------------------------------------------------------------------- // AudioParams //---------------------------------------------------------------------------- class AudioParams::Private { public: QString codec; int sampleRate; int sampleSize; int channels; Private() : sampleRate(0), sampleSize(0), channels(0) { } }; AudioParams::AudioParams() : d(new Private) { } AudioParams::AudioParams(const AudioParams &other) : d(new Private(*other.d)) { } AudioParams::~AudioParams() { delete d; } AudioParams & AudioParams::operator=(const AudioParams &other) { *d = *other.d; return *this; } QString AudioParams::codec() const { return d->codec; } int AudioParams::sampleRate() const { return d->sampleRate; } int AudioParams::sampleSize() const { return d->sampleSize; } int AudioParams::channels() const { return d->channels; } void AudioParams::setCodec(const QString &s) { d->codec = s; } void AudioParams::setSampleRate(int n) { d->sampleRate = n; } void AudioParams::setSampleSize(int n) { d->sampleSize = n; } void AudioParams::setChannels(int n) { d->channels = n; } bool AudioParams::operator==(const AudioParams &other) const { if(d->codec == other.d->codec && d->sampleRate == other.d->sampleRate && d->sampleSize == other.d->sampleSize && d->channels == other.d->channels) { return true; } else return false; } //---------------------------------------------------------------------------- // VideoParams //---------------------------------------------------------------------------- class VideoParams::Private { public: QString codec; QSize size; int fps; Private() : fps(0) { } }; VideoParams::VideoParams() : d(new Private) { } VideoParams::VideoParams(const VideoParams &other) : d(new Private(*other.d)) { } VideoParams::~VideoParams() { delete d; } VideoParams & VideoParams::operator=(const VideoParams &other) { *d = *other.d; return *this; } QString VideoParams::codec() const { return d->codec; } QSize VideoParams::size() const { return d->size; } int VideoParams::fps() const { return d->fps; } void VideoParams::setCodec(const QString &s) { d->codec = s; } void VideoParams::setSize(const QSize &s) { d->size = s; } void VideoParams::setFps(int n) { d->fps = n; } bool VideoParams::operator==(const VideoParams &other) const { if(d->codec == other.d->codec && d->size == other.d->size && d->fps == other.d->fps) { return true; } else return false; } //---------------------------------------------------------------------------- // Features //---------------------------------------------------------------------------- static QList<Device> importDevices(const QList<PDevice> &in) { QList<Device> out; foreach(const PDevice &pd, in) out += Global::importDevice(pd); return out; } static QList<AudioParams> importAudioModes(const QList<PAudioParams> &in) { QList<AudioParams> out; foreach(const PAudioParams &pp, in) out += importAudioParams(pp); return out; } static QList<VideoParams> importVideoModes(const QList<PVideoParams> &in) { QList<VideoParams> out; foreach(const PVideoParams &pp, in) out += importVideoParams(pp); return out; } class Features::Private : public QObject { Q_OBJECT public: Features *q; FeaturesContext *c; QList<Device> audioOutputDevices; QList<Device> audioInputDevices; QList<Device> videoInputDevices; QList<AudioParams> supportedAudioModes; QList<VideoParams> supportedVideoModes; Private(Features *_q) : QObject(_q), q(_q) { c = provider()->createFeatures(); c->qobject()->setParent(this); connect(c->qobject(), SIGNAL(finished()), SLOT(c_finished())); } ~Private() { delete c; } void clearResults() { audioOutputDevices.clear(); audioInputDevices.clear(); videoInputDevices.clear(); supportedAudioModes.clear(); supportedVideoModes.clear(); } void importResults(const PFeatures &in) { audioOutputDevices = importDevices(in.audioOutputDevices); audioInputDevices = importDevices(in.audioInputDevices); videoInputDevices = importDevices(in.videoInputDevices); supportedAudioModes = importAudioModes(in.supportedAudioModes); supportedVideoModes = importVideoModes(in.supportedVideoModes); } private slots: void c_finished() { importResults(c->results()); emit q->finished(); } }; Features::Features(QObject *parent) : QObject(parent) { d = new Private(this); } Features::~Features() { delete d; } void Features::lookup(int types) { int ptypes = 0; if(types & AudioOut) ptypes |= FeaturesContext::AudioOut; if(types & AudioIn) ptypes |= FeaturesContext::AudioIn; if(types & VideoIn) ptypes |= FeaturesContext::VideoIn; if(types & AudioModes) ptypes |= FeaturesContext::AudioModes; if(types & VideoModes) ptypes |= FeaturesContext::VideoModes; d->clearResults(); d->c->lookup(ptypes); } bool Features::waitForFinished(int msecs) { bool ok = d->c->waitForFinished(msecs); if(ok) d->importResults(d->c->results()); return ok; } QList<Device> Features::audioOutputDevices() { return d->audioOutputDevices; } QList<Device> Features::audioInputDevices() { return d->audioInputDevices; } QList<Device> Features::videoInputDevices() { return d->videoInputDevices; } QList<AudioParams> Features::supportedAudioModes() { return d->supportedAudioModes; } QList<VideoParams> Features::supportedVideoModes() { return d->supportedVideoModes; } //---------------------------------------------------------------------------- // RtpPacket //---------------------------------------------------------------------------- class RtpPacket::Private : public QSharedData { public: QByteArray rawValue; int portOffset; Private(const QByteArray &_rawValue, int _portOffset) : rawValue(_rawValue), portOffset(_portOffset) { } }; RtpPacket::RtpPacket() : d(0) { } RtpPacket::RtpPacket(const QByteArray &rawValue, int portOffset) : d(new Private(rawValue, portOffset)) { } RtpPacket::RtpPacket(const RtpPacket &other) : d(other.d) { } RtpPacket::~RtpPacket() { } RtpPacket & RtpPacket::operator=(const RtpPacket &other) { d = other.d; return *this; } bool RtpPacket::isNull() const { return (d ? false : true); } QByteArray RtpPacket::rawValue() const { return d->rawValue; } int RtpPacket::portOffset() const { return d->portOffset; } //---------------------------------------------------------------------------- // RtpChannel //---------------------------------------------------------------------------- class RtpChannelPrivate : public QObject { Q_OBJECT public: RtpChannel *q; RtpChannelContext *c; bool enabled; int readyReadListeners; RtpChannelPrivate(RtpChannel *_q) : QObject(_q), q(_q), c(0), enabled(false), readyReadListeners(0) { } void setContext(RtpChannelContext *_c) { if(c) { c->qobject()->disconnect(this); c->qobject()->setParent(0); enabled = false; c = 0; } if(!_c) return; c = _c; c->qobject()->setParent(this); connect(c->qobject(), SIGNAL(readyRead()), SLOT(c_readyRead())); connect(c->qobject(), SIGNAL(packetsWritten(int)), SLOT(c_packetsWritten(int))); connect(c->qobject(), SIGNAL(destroyed()), SLOT(c_destroyed())); if(readyReadListeners > 0) { enabled = true; c->setEnabled(true); } } private slots: void c_readyRead() { emit q->readyRead(); } void c_packetsWritten(int count) { emit q->packetsWritten(count); } void c_destroyed() { enabled = false; c = 0; } }; RtpChannel::RtpChannel() { d = new RtpChannelPrivate(this); } RtpChannel::~RtpChannel() { delete d; } int RtpChannel::packetsAvailable() const { if(d->c) return d->c->packetsAvailable(); else return 0; } RtpPacket RtpChannel::read() { if(d->c) { PRtpPacket pp = d->c->read(); return RtpPacket(pp.rawValue, pp.portOffset); } else return RtpPacket(); } void RtpChannel::write(const RtpPacket &rtp) { if(d->c) { if(!d->enabled) { d->enabled = true; d->c->setEnabled(true); } PRtpPacket pp; pp.rawValue = rtp.rawValue(); pp.portOffset = rtp.portOffset(); d->c->write(pp); } } void RtpChannel::connectNotify(const char *signal) { int oldtotal = d->readyReadListeners; if(QLatin1String(signal) == QMetaObject::normalizedSignature(SIGNAL(readyRead())).data()) ++d->readyReadListeners; int total = d->readyReadListeners; if(d->c && oldtotal == 0 && total > 0) { d->enabled = true; d->c->setEnabled(true); } } void RtpChannel::disconnectNotify(const char *signal) { int oldtotal = d->readyReadListeners; if(QLatin1String(signal) == QMetaObject::normalizedSignature(SIGNAL(readyRead())).data()) --d->readyReadListeners; int total = d->readyReadListeners; if(d->c && oldtotal > 0 && total == 0) { d->enabled = false; d->c->setEnabled(false); } } //---------------------------------------------------------------------------- // PayloadInfo //---------------------------------------------------------------------------- bool PayloadInfo::Parameter::operator==(const PayloadInfo::Parameter &other) const { // according to xep-167, parameter names are case-sensitive if(name == other.name && value == other.value) return true; else return false; } class PayloadInfo::Private { public: int id; QString name; int clockrate; int channels; int ptime; int maxptime; QList<PayloadInfo::Parameter> parameters; Private() : id(-1), clockrate(-1), channels(-1), ptime(-1), maxptime(-1) { } bool operator==(const Private &other) const { // according to xep-167, parameters are unordered if(id == other.id && name.compare(other.name, Qt::CaseInsensitive) && clockrate == other.clockrate && channels == other.channels && ptime == other.ptime && maxptime == other.maxptime && compareUnordered(parameters, other.parameters)) { return true; } else return false; } static bool compareUnordered(const QList<PayloadInfo::Parameter> &a, const QList<PayloadInfo::Parameter> &b) { if(a.count() != b.count()) return false; // for every parameter in 'a' foreach(const PayloadInfo::Parameter &p, a) { // make sure it is found in 'b' if(!b.contains(p)) return false; } return true; } }; PayloadInfo::PayloadInfo() : d(new Private) { } PayloadInfo::PayloadInfo(const PayloadInfo &other) : d(new Private(*other.d)) { } PayloadInfo::~PayloadInfo() { delete d; } PayloadInfo & PayloadInfo::operator=(const PayloadInfo &other) { *d = *other.d; return *this; } bool PayloadInfo::isNull() const { return (d->id == -1); } int PayloadInfo::id() const { return d->id; } QString PayloadInfo::name() const { return d->name; } int PayloadInfo::clockrate() const { return d->clockrate; } int PayloadInfo::channels() const { return d->channels; } int PayloadInfo::ptime() const { return d->ptime; } int PayloadInfo::maxptime() const { return d->maxptime; } QList<PayloadInfo::Parameter> PayloadInfo::parameters() const { return d->parameters; } void PayloadInfo::setId(int i) { d->id = i; } void PayloadInfo::setName(const QString &str) { d->name = str; } void PayloadInfo::setClockrate(int i) { d->clockrate = i; } void PayloadInfo::setChannels(int num) { d->channels = num; } void PayloadInfo::setPtime(int i) { d->ptime = i; } void PayloadInfo::setMaxptime(int i) { d->maxptime = i; } void PayloadInfo::setParameters(const QList<PayloadInfo::Parameter> ¶ms) { d->parameters = params; } bool PayloadInfo::operator==(const PayloadInfo &other) const { return (*d == *other.d); } //---------------------------------------------------------------------------- // RtpSession //---------------------------------------------------------------------------- class RtpSessionPrivate : public QObject { Q_OBJECT public: RtpSession *q; RtpSessionContext *c; RtpChannel audioRtpChannel; RtpChannel videoRtpChannel; RtpSessionPrivate(RtpSession *_q) : QObject(_q), q(_q) { c = provider()->createRtpSession(); c->qobject()->setParent(this); connect(c->qobject(), SIGNAL(started()), SLOT(c_started())); connect(c->qobject(), SIGNAL(preferencesUpdated()), SLOT(c_preferencesUpdated())); connect(c->qobject(), SIGNAL(audioOutputIntensityChanged(int)), SLOT(c_audioOutputIntensityChanged(int))); connect(c->qobject(), SIGNAL(audioInputIntensityChanged(int)), SLOT(c_audioInputIntensityChanged(int))); connect(c->qobject(), SIGNAL(stoppedRecording()), SLOT(c_stoppedRecording())); connect(c->qobject(), SIGNAL(stopped()), SLOT(c_stopped())); connect(c->qobject(), SIGNAL(finished()), SLOT(c_finished())); connect(c->qobject(), SIGNAL(error()), SLOT(c_error())); } ~RtpSessionPrivate() { delete c; } private slots: void c_started() { audioRtpChannel.d->setContext(c->audioRtpChannel()); videoRtpChannel.d->setContext(c->videoRtpChannel()); emit q->started(); } void c_preferencesUpdated() { emit q->preferencesUpdated(); } void c_audioOutputIntensityChanged(int intensity) { emit q->audioOutputIntensityChanged(intensity); } void c_audioInputIntensityChanged(int intensity) { emit q->audioInputIntensityChanged(intensity); } void c_stoppedRecording() { emit q->stoppedRecording(); } void c_stopped() { audioRtpChannel.d->setContext(0); videoRtpChannel.d->setContext(0); emit q->stopped(); } void c_finished() { audioRtpChannel.d->setContext(0); videoRtpChannel.d->setContext(0); emit q->finished(); } void c_error() { audioRtpChannel.d->setContext(0); videoRtpChannel.d->setContext(0); emit q->error(); } }; RtpSession::RtpSession(QObject *parent) : QObject(parent) { d = new RtpSessionPrivate(this); } RtpSession::~RtpSession() { delete d; } void RtpSession::reset() { delete d; d = new RtpSessionPrivate(this); } void RtpSession::setAudioOutputDevice(const QString &deviceId) { d->c->setAudioOutputDevice(deviceId); } #ifdef QT_GUI_LIB void RtpSession::setVideoOutputWidget(VideoWidget *widget) { d->c->setVideoOutputWidget(widget ? widget->d : 0); } #endif void RtpSession::setAudioInputDevice(const QString &deviceId) { d->c->setAudioInputDevice(deviceId); } void RtpSession::setVideoInputDevice(const QString &deviceId) { d->c->setVideoInputDevice(deviceId); } void RtpSession::setFileInput(const QString &fileName) { d->c->setFileInput(fileName); } void RtpSession::setFileDataInput(const QByteArray &fileData) { d->c->setFileDataInput(fileData); } void RtpSession::setFileLoopEnabled(bool enabled) { d->c->setFileLoopEnabled(enabled); } #ifdef QT_GUI_LIB void RtpSession::setVideoPreviewWidget(VideoWidget *widget) { d->c->setVideoPreviewWidget(widget ? widget->d : 0); } #endif void RtpSession::setRecordingQIODevice(QIODevice *dev) { d->c->setRecorder(dev); } void RtpSession::stopRecording() { d->c->stopRecording(); } void RtpSession::setLocalAudioPreferences(const QList<AudioParams> ¶ms) { QList<PAudioParams> list; foreach(const AudioParams &p, params) list += exportAudioParams(p); d->c->setLocalAudioPreferences(list); } void RtpSession::setLocalVideoPreferences(const QList<VideoParams> ¶ms) { QList<PVideoParams> list; foreach(const VideoParams &p, params) list += exportVideoParams(p); d->c->setLocalVideoPreferences(list); } void RtpSession::setMaximumSendingBitrate(int kbps) { d->c->setMaximumSendingBitrate(kbps); } void RtpSession::setRemoteAudioPreferences(const QList<PayloadInfo> &info) { QList<PPayloadInfo> list; foreach(const PayloadInfo &p, info) list += exportPayloadInfo(p); d->c->setRemoteAudioPreferences(list); } void RtpSession::setRemoteVideoPreferences(const QList<PayloadInfo> &info) { QList<PPayloadInfo> list; foreach(const PayloadInfo &p, info) list += exportPayloadInfo(p); d->c->setRemoteVideoPreferences(list); } void RtpSession::start() { d->c->start(); } void RtpSession::updatePreferences() { d->c->updatePreferences(); } void RtpSession::transmitAudio() { d->c->transmitAudio(); } void RtpSession::transmitVideo() { d->c->transmitVideo(); } void RtpSession::pauseAudio() { d->c->pauseAudio(); } void RtpSession::pauseVideo() { d->c->pauseVideo(); } void RtpSession::stop() { d->c->stop(); } QList<PayloadInfo> RtpSession::localAudioPayloadInfo() const { QList<PayloadInfo> out; foreach(const PPayloadInfo &pp, d->c->localAudioPayloadInfo()) out += importPayloadInfo(pp); return out; } QList<PayloadInfo> RtpSession::localVideoPayloadInfo() const { QList<PayloadInfo> out; foreach(const PPayloadInfo &pp, d->c->localVideoPayloadInfo()) out += importPayloadInfo(pp); return out; } QList<PayloadInfo> RtpSession::remoteAudioPayloadInfo() const { QList<PayloadInfo> out; foreach(const PPayloadInfo &pp, d->c->remoteAudioPayloadInfo()) out += importPayloadInfo(pp); return out; } QList<PayloadInfo> RtpSession::remoteVideoPayloadInfo() const { QList<PayloadInfo> out; foreach(const PPayloadInfo &pp, d->c->remoteVideoPayloadInfo()) out += importPayloadInfo(pp); return out; } QList<AudioParams> RtpSession::audioParams() const { QList<AudioParams> out; foreach(const PAudioParams &pp, d->c->audioParams()) out += importAudioParams(pp); return out; } QList<VideoParams> RtpSession::videoParams() const { QList<VideoParams> out; foreach(const PVideoParams &pp, d->c->videoParams()) out += importVideoParams(pp); return out; } bool RtpSession::canTransmitAudio() const { return d->c->canTransmitAudio(); } bool RtpSession::canTransmitVideo() const { return d->c->canTransmitVideo(); } int RtpSession::outputVolume() const { return d->c->outputVolume(); } void RtpSession::setOutputVolume(int level) { d->c->setOutputVolume(level); } int RtpSession::inputVolume() const { return d->c->inputVolume(); } void RtpSession::setInputVolume(int level) { d->c->setInputVolume(level); } RtpSession::Error RtpSession::errorCode() const { return (RtpSession::Error)d->c->errorCode(); } RtpChannel *RtpSession::audioRtpChannel() { return &d->audioRtpChannel; } RtpChannel *RtpSession::videoRtpChannel() { return &d->videoRtpChannel; } } #include "psimedia.moc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/proxy.ui�������������������������������������������������������������������������������0000644�0001750�0001750�00000014720�11305557613�012654� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Proxy</class> <widget class="QDialog" name="Proxy"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>622</width> <height>346</height> </rect> </property> <property name="windowTitle"> <string>Proxy Profiles</string> </property> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <layout class="QVBoxLayout"> <item> <widget class="QListWidget" name="lbx_proxy"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> </item> <item> <layout class="QHBoxLayout"> <item> <widget class="IconButton" name="pb_new" native="true"> <property name="text" stdset="0"> <string>&New</string> </property> <property name="psiIconName" stdset="0"> <string>psi/addContact</string> </property> </widget> </item> <item> <widget class="IconButton" name="pb_remove" native="true"> <property name="text" stdset="0"> <string>Rem&ove</string> </property> <property name="psiIconName" stdset="0"> <string>psi/remove</string> </property> </widget> </item> </layout> </item> </layout> </item> <item row="0" column="1"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QHBoxLayout"> <item> <widget class="QLabel" name="textLabel2"> <property name="text"> <string>Type:</string> </property> </widget> </item> <item> <widget class="QComboBox" name="cb_type"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> </item> </layout> </item> <item> <widget class="QGroupBox" name="groupBox"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="title"> <string/> </property> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Host:</string> </property> </widget> </item> <item row="0" column="1" colspan="2"> <widget class="QLineEdit" name="le_host"/> </item> <item row="0" column="3"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Port:</string> </property> </widget> </item> <item row="0" column="4"> <widget class="QLineEdit" name="le_port"> <property name="minimumSize"> <size> <width>0</width> <height>0</height> </size> </property> <property name="maximumSize"> <size> <width>64</width> <height>16777215</height> </size> </property> </widget> </item> <item row="1" column="0" colspan="2"> <widget class="QLabel" name="lb_url"> <property name="text"> <string>Polling URL:</string> </property> </widget> </item> <item row="1" column="2" colspan="3"> <widget class="QLineEdit" name="le_url"/> </item> <item row="2" column="0" colspan="5"> <widget class="QGroupBox" name="gr_auth"> <property name="title"> <string>Use authentication</string> </property> <property name="checkable"> <bool>true</bool> </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Username:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLineEdit" name="le_user"/> </item> <item row="1" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> <string>Password:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLineEdit" name="le_pass"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>13</height> </size> </property> </spacer> </item> </layout> </item> <item row="1" column="0" colspan="2"> <widget class="Line" name="line2"> <property name="frameShape"> <enum>QFrame::HLine</enum> </property> <property name="frameShadow"> <enum>QFrame::Sunken</enum> </property> </widget> </item> <item row="2" column="0" colspan="2"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set> </property> </widget> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> <customwidgets> <customwidget> <class>IconButton</class> <extends>QWidget</extends> <header>iconbutton.h</header> </customwidget> </customwidgets> <tabstops> <tabstop>cb_type</tabstop> <tabstop>le_host</tabstop> <tabstop>le_port</tabstop> <tabstop>le_url</tabstop> <tabstop>gr_auth</tabstop> <tabstop>le_user</tabstop> <tabstop>le_pass</tabstop> <tabstop>buttonBox</tabstop> <tabstop>lbx_proxy</tabstop> </tabstops> <resources/> <connections/> </ui> ������������������������������������������������psi-0.14/src/ahcexecutetask.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000004067�11305557613�014644� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ahcexecutetask.cpp - Ad-Hoc Command Execute Task * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "ahcexecutetask.h" #include "ahcformdlg.h" #include "xmpp_xmlcommon.h" #include "psiaccount.h" using namespace XMPP; AHCExecuteTask::AHCExecuteTask(const Jid& j, const AHCommand& command, Task* t) : Task(t), receiver_(j), command_(command) { } void AHCExecuteTask::onGo() { QDomElement e = createIQ(doc(), "set", receiver_.full(), id()); e.appendChild(command_.toXml(doc(),true)); send(e); } bool AHCExecuteTask::take(const QDomElement& e) { if(!iqVerify(e, receiver_, id())) { return false; } // Result of a command if (e.attribute("type") == "result") { bool found; QDomElement i = findSubTag(e, "command", &found); if (found) { AHCommand c(i); if (c.status() == AHCommand::Executing) { AHCFormDlg *w = new AHCFormDlg(c,receiver_,client()); w->show(); } else if (c.status() == AHCommand::Completed && i.childNodes().count() > 0) { AHCFormDlg *w = new AHCFormDlg(c,receiver_,client(), true); w->show(); } setSuccess(); return true; } } // Error /*else if (e.attribute("type") == "set") { AHCError err(e); if (err.type() != None) { QMessageBox::critical(0, tr("Error"), AHCommand::error2description(err.type()), QMessageBox::Ok, QMessageBox::NoButton); } return true; }*/ setError(e); return false; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/rosteritemexchangetask.h���������������������������������������������������������������0000644�0001750�0001750�00000002326�11305557613�016067� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * rosteritemexchangetask.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ROSTERITEMEXCHANGETASK_H #define ROSTERITEMEXCHANGETASK_H #include <QDomElement> #include "xmpp_task.h" #include "xmpp_rosterx.h" using namespace XMPP; class RosterItemExchangeTask : public Task { Q_OBJECT public: RosterItemExchangeTask(Task*); bool take(const QDomElement&); void setIgnoreNonRoster(bool); signals: void rosterItemExchange(const Jid&, const RosterExchangeItems&); private: bool ignoreNonRoster_; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/statuspreset.cpp�����������������������������������������������������������������������0000644�0001750�0001750�00000006650�11305557613�014411� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * statuspreset.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QString> #include "utilities/maybe.h" #include "statuspreset.h" //----------------------------------------------------------------------------- // StatusPreset //----------------------------------------------------------------------------- StatusPreset::StatusPreset() : name_(""), message_(""), status_(XMPP::Status::Away) { } StatusPreset::StatusPreset(QString name, QString message, XMPP::Status::Type status) : name_(name), message_(message), status_(status) { } StatusPreset::StatusPreset(QString name, int priority, QString message, XMPP::Status::Type status) : name_(name), message_(message), status_(status) { setPriority(priority); } StatusPreset::StatusPreset(const QDomElement& el) : name_(""), message_(""), status_(XMPP::Status::Away) { fromXml(el); } QString StatusPreset::name() const { return name_; } void StatusPreset::setName(const QString& name) { name_ = name; } QString StatusPreset::message() const { return message_; } void StatusPreset::setMessage(const QString& message) { message_ = message; } XMPP::Status::Type StatusPreset::status() const { return status_; } void StatusPreset::setStatus(XMPP::Status::Type status) { status_ = status; } Maybe<int> StatusPreset::priority() const { return priority_; } void StatusPreset::setPriority(int priority) { priority_ = Maybe<int>(priority); } void StatusPreset::clearPriority() { priority_ = Maybe<int>(); } QDomElement StatusPreset::toXml(QDomDocument& doc) const { QDomElement preset = doc.createElement("preset"); QDomText text = doc.createTextNode(message()); preset.appendChild(text); preset.setAttribute("name",name()); if (priority_.hasValue()) preset.setAttribute("priority", priority_.value()); preset.setAttribute("status", XMPP::Status(status()).typeString()); return preset; } void StatusPreset::fromXml(const QDomElement &el) { // FIXME: This is the old format. Should be removed in the future if (el.tagName() == "item") { setName(el.attribute("name")); setMessage(el.text()); return; } if (el.isNull() || el.tagName() != "preset") return; setName(el.attribute("name")); setMessage(el.text()); if (el.hasAttribute("priority")) setPriority(el.attribute("priority").toInt()); XMPP::Status status; status.setType(el.attribute("status", "away")); setStatus(status.type()); } void StatusPreset::toOptions(OptionsTree *o) { QString base = o->mapPut("options.status.presets", name()); o->setOption(base + ".message", message()); o->setOption(base + ".status", XMPP::Status(status()).typeString()); o->setOption(base + ".force-priority", priority().hasValue()); if (priority().hasValue()) { o->setOption(base + ".priority", priority().value()); } } ����������������������������������������������������������������������������������������psi-0.14/src/chatsplitter.h�������������������������������������������������������������������������0000644�0001750�0001750�00000003077�11305557613�014016� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * chatsplitter.h - QSplitter replacement that masquerades it * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CHATSPLITTER_H #define CHATSPLITTER_H #include <QWidget> #include <QList> class QSplitter; class ChatSplitter : public QWidget { Q_OBJECT public: ChatSplitter(QWidget* parent); void setOrientation(Qt::Orientation orientation); void addWidget(QWidget* widget); void setSizes(const QList<int>& list); protected: /** * Returns true if all child widgets are managed by QLayout. */ bool splitterEnabled() const { return splitterEnabled_; } void setSplitterEnabled(bool enable); public slots: void optionsChanged(); private slots: void childDestroyed(QObject* obj); private: void updateChildLayout(QWidget* child); void updateLayout(); bool splitterEnabled_; QList<QWidget*> children_; QSplitter* splitter_; QLayout* layout_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/jidutil.h������������������������������������������������������������������������������0000644�0001750�0001750�00000002637�11305557613�012755� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jidutil.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef JIDUTIL #define JIDUTIL class QString; namespace XMPP { class Jid; } class JIDUtil { public: static QString defaultDomain(); static void setDefaultDomain(QString domain); static QString accountToString(const XMPP::Jid&, bool withResource); static XMPP::Jid accountFromString(const QString&); static QString toString(const XMPP::Jid&, bool withResource); static XMPP::Jid fromString(const QString&); static QString encode(const QString &jid); static QString decode(const QString &jid); static QString nickOrJid(const QString&, const QString&); static QString encode822(const QString&); static QString decode822(const QString&); }; #endif �������������������������������������������������������������������������������������������������psi-0.14/src/vcardphotodlg.cpp����������������������������������������������������������������������0000644�0001750�0001750�00000004611�11305557613�014476� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "vcardphotodlg.h" #include <QMouseEvent> #include <QDialog> #include <QVBoxLayout> #include <QAction> #include <QFileDialog> #include "psiiconset.h" #include "fileutil.h" ShowPhotoDlg::ShowPhotoDlg(QWidget *parent, QPixmap &pixmap) : QDialog(parent), initSize(true) { setAttribute(Qt::WA_DeleteOnClose); photoPixmap = pixmap; setWindowTitle(QString(tr("Photo Preview: %1")).arg(parent->windowTitle())); label=new QLabel(this); label->setAlignment(Qt::AlignCenter); label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); label->setContentsMargins(0, 0, 0, 0); QVBoxLayout* layout = new QVBoxLayout(); toolbar = new QToolBar(this); toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); layout->setSpacing(0); layout->setMargin(0); layout->addWidget(toolbar); layout->addWidget(label); setLayout(layout); createActions(); toolbar->addAction(restoreAct); toolbar->addAction(saveAct); restore(); } void ShowPhotoDlg::createActions() { saveAct = new QAction(IconsetFactory::icon("psi/save").icon(), tr("&Save As..."), this); connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); restoreAct = new QAction(IconsetFactory::icon("psi/reload").icon(), tr("&Restore Size"), this); connect(restoreAct, SIGNAL(triggered()), this, SLOT(restore())); } void ShowPhotoDlg::save() { QString fileName = FileUtil::getSaveFileName(this, tr("Save As"), tr("photo.png"), tr("PNG File (*.png);;JPEG File (*.jpeg);;BMP File (*.bmp);;PPM File (*.ppm);;All Files (*)")); if (!fileName.isEmpty()) { photoPixmap.save(fileName); } } void ShowPhotoDlg::restore() { resize(photoPixmap.width(), photoPixmap.height() + toolbar->height()); } void ShowPhotoDlg::updatePhoto(const QSize size) { label->setPixmap(photoPixmap.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation )); } void ShowPhotoDlg::resizeEvent(QResizeEvent *) { if (initSize) { restore(); label->resize(photoPixmap.size()); //small hack to resize properly on init. initSize = false; } updatePhoto(label->size()); } void ShowPhotoDlg::wheelEvent(QWheelEvent * event) { int delta = event->delta() / 8; int width, height; QSize ps = label->pixmap()->size(); ps.scale(ps.width() + delta, ps.height() + delta, Qt::KeepAspectRatio); width = ps.width(); height = ps.height() + toolbar->height(); if ((event->x() < width) && (event->y() < height)) { resize(ps.width(), ps.height() + toolbar->height()); } } �����������������������������������������������������������������������������������������������������������������������psi-0.14/src/jinglevoicecaller.h��������������������������������������������������������������������0000644�0001750�0001750�00000004237�11305557613�014770� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jinglevoicecaller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef JINGLEVOICECALLER_H #define JINGLEVOICECALLER_H #include <qmap.h> #include "voicecaller.h" class PsiAccount; namespace cricket { class SocketServer; class Thread; class NetworkManager; class BasicPortAllocator; class SessionManager; class PhoneSessionClient; class Call; class SocketAddress; } namespace XMPP { class Jid; } class JingleClientSlots; class JingleCallSlots; using namespace XMPP; class JingleVoiceCaller : public VoiceCaller { Q_OBJECT friend class JingleClientSlots; public: JingleVoiceCaller(PsiAccount* account); ~JingleVoiceCaller(); virtual bool calling(const Jid&); virtual void initialize(); virtual void deinitialize(); virtual void call(const Jid&); virtual void accept(const Jid&); virtual void reject(const Jid&); virtual void terminate(const Jid&); protected: void sendStanza(const char*); void registerCall(const Jid&, cricket::Call*); void removeCall(const Jid&); protected slots: void receiveStanza(const QString&); private: bool initialized_; static cricket::SocketServer *socket_server_; static cricket::Thread *thread_; static cricket::NetworkManager *network_manager_; static cricket::BasicPortAllocator *port_allocator_; static cricket::SocketAddress *stun_addr_; cricket::SessionManager *session_manager_; cricket::PhoneSessionClient *phone_client_; JingleClientSlots *slots_; QMap<QString,cricket::Call*> calls_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psiapplication.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000021241�11305557613�014653� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psiapplication.cpp - subclass of QApplication to do some workarounds * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psiapplication.h" #include "resourcemenu.h" #include <QSessionManager> #ifdef Q_WS_MAC #include <Carbon/Carbon.h> #endif #ifdef Q_WS_X11 #include <stdio.h> #include <time.h> #include <sys/time.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <QX11Info> #include <QDesktopWidget> #include <QEvent> // Atoms required for monitoring the freedesktop.org notification area static Atom manager_atom = 0; static Atom tray_selection_atom = 0; Window root_window = 0; Window tray_owner = None; //static Atom atom_KdeNetUserTime; static Atom kde_net_wm_user_time = 0; Time qt_x_last_input_time = CurrentTime; //extern Time qt_x_time; #ifdef KeyPress #ifndef FIXX11H_KeyPress #define FIXX11H_KeyPress const int XKeyPress = KeyPress; #undef KeyPress const int KeyPress = XKeyPress; #endif #undef KeyPress #endif #endif #ifdef Q_WS_WIN #include "systemwatch_win.h" #endif // mblsha: // currently this file contains some Anti-"focus steling prevention" code by // Lubos Lunak (l.lunak@kde.org) // // This should resolve all bugs with KWin3 and old Qt, but maybe it'll be useful for // other window managers? #ifdef Q_WS_X11 //#undef Q_WS_X11 #endif #ifdef Q_WS_X11 void setTrayOwnerWindow(Display *dsp) { /* This code is basically trying to mirror what happens in * eggtrayicon.c:egg_tray_icon_update_manager_window() */ // ignore events from the old tray owner if (tray_owner != None) { XSelectInput(dsp, tray_owner, 0); } // obtain the Window handle for the new tray owner XGrabServer(dsp); tray_owner = XGetSelectionOwner(dsp, tray_selection_atom); // we have to be able to spot DestroyNotify messages on the tray owner if (tray_owner != None) { XSelectInput(dsp, tray_owner, StructureNotifyMask|PropertyChangeMask); } XUngrabServer(dsp); XFlush(dsp); } #endif //---------------------------------------------------------------------------- // PsiMacStyle //---------------------------------------------------------------------------- #ifdef Q_WS_MAC #include <QMacStyle> #include <QStyleOptionMenuItem> /** * Custom QStyle that helps to get rid of icons in all kinds of menus * on Mac OS X. */ class PsiMacStyle : public QMacStyle { public: PsiMacStyle() { // Since Qt 4.6, it's better to use QAction::setIconVisibleInMenu() // extern void qt_mac_set_menubar_icons(bool b); // qmenu_mac.cpp // qt_mac_set_menubar_icons(false); } void drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p, const QWidget *w) const { if (disableIconsForMenu(w) && ce == QStyle::CE_MenuItem) { if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { QStyleOptionMenuItem newopt(*mi); newopt.maxIconWidth = 0; newopt.icon = QIcon(); QMacStyle::drawControl(ce, &newopt, p, w); return; } } QMacStyle::drawControl(ce, opt, p, w); } QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz, const QWidget *widget) const { if (disableIconsForMenu(widget) && ct == QStyle::CT_MenuItem) { if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { QStyleOptionMenuItem newopt(*mi); newopt.maxIconWidth = 0; newopt.icon = QIcon(); return QMacStyle::sizeFromContents(ct, &newopt, csz, widget); } } return QMacStyle::sizeFromContents(ct, opt, csz, widget); } private: /** * This function provides means to override the icon-disabling * behavior. For instance, ResourceMenu's items are shown * with icons on screen. */ bool disableIconsForMenu(const QWidget *menu) const { return !menu || !dynamic_cast<const ResourceMenu*>(menu); } }; #endif //---------------------------------------------------------------------------- // PsiApplication //---------------------------------------------------------------------------- PsiApplication::PsiApplication(int &argc, char **argv, bool GUIenabled) : QApplication(argc, argv, GUIenabled) { init(GUIenabled); } PsiApplication::~PsiApplication() { } void PsiApplication::init(bool GUIenabled) { Q_UNUSED(GUIenabled); #ifdef Q_WS_MAC setStyle(new PsiMacStyle()); #endif #ifdef Q_WS_X11 if ( GUIenabled ) { const int max = 20; Atom* atoms[max]; char* names[max]; Atom atoms_return[max]; int n = 0; //atoms[n] = &atom_KdeNetUserTime; //names[n++] = (char *) "_KDE_NET_USER_TIME"; atoms[n] = &kde_net_wm_user_time; names[n++] = (char *) "_NET_WM_USER_TIME"; atoms[n] = &manager_atom; names[n++] = (char *) "MANAGER"; Display *dsp = QX11Info::display(); XInternAtoms( dsp, names, n, false, atoms_return ); for (int i = 0; i < n; i++ ) *atoms[i] = atoms_return[i]; // get the selection type we'll use to locate the notification tray char buf[32]; snprintf(buf, sizeof(buf), "_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen( XDefaultScreenOfDisplay(dsp) )); tray_selection_atom = XInternAtom(dsp, buf, false); // make a note of the window handle for the root window root_window = QApplication::desktop()->winId(); XWindowAttributes attr; // this is actually futile, since Qt overrides it at some // unknown point in the near future. XGetWindowAttributes(dsp, root_window, &attr); XSelectInput(dsp, root_window, attr.your_event_mask | StructureNotifyMask); setTrayOwnerWindow(dsp); } #endif } bool PsiApplication::notify(QObject *receiver, QEvent *event) { #ifdef Q_WS_X11 if( event->type() == QEvent::Show && receiver->isWidgetType()) { QWidget* w = static_cast< QWidget* >( receiver ); if( w->isTopLevel() && qt_x_last_input_time != CurrentTime ) // CurrentTime means no input event yet XChangeProperty( QX11Info::display(), w->winId(), kde_net_wm_user_time, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&qt_x_last_input_time, 1 ); } if( event->type() == QEvent::Hide && receiver->isWidgetType()) { QWidget* w = static_cast< QWidget* >( receiver ); if( w->isTopLevel() && w->winId() != 0 ) XDeleteProperty( QX11Info::display(), w->winId(), kde_net_wm_user_time ); } #endif return QApplication::notify(receiver, event); } #ifdef Q_WS_X11 bool PsiApplication::x11EventFilter( XEvent *_event ) { switch ( _event->type ) { case ClientMessage: if (_event->xclient.window == root_window && _event->xclient.message_type == manager_atom) { // A new notification area application has // announced its presence setTrayOwnerWindow(_event->xclient.display); newTrayOwner(); } break; case DestroyNotify: if (_event->xdestroywindow.event == tray_owner) { // there is now no known notification area. // We're still looking out for the MANAGER // message sent to the root window, at which // point we'll have another look to see // whether a notification area is available. tray_owner = 0; trayOwnerDied(); } break; case ButtonPress: case XKeyPress: { if( _event->type == ButtonPress ) qt_x_last_input_time = _event->xbutton.time; else // KeyPress qt_x_last_input_time = _event->xkey.time; QWidget *w = activeWindow(); if( w ) { XChangeProperty( QX11Info::display(), w->winId(), kde_net_wm_user_time, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&qt_x_last_input_time, 1 ); /*timeval tv; gettimeofday( &tv, NULL ); unsigned long now = tv.tv_sec * 10 + tv.tv_usec / 100000; XChangeProperty(qt_xdisplay(), w->winId(), atom_KdeNetUserTime, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&now, 1);*/ } break; } default: break; } // process the event normally return false; } #endif #ifdef Q_WS_MAC bool PsiApplication::macEventFilter( EventHandlerCallRef, EventRef inEvent ) { UInt32 eclass = GetEventClass(inEvent); int etype = GetEventKind(inEvent); if(eclass == 'eppc' && etype == kEventAppleEvent) { dockActivated(); } return false; } #endif void PsiApplication::commitData(QSessionManager& manager) { Q_UNUSED(manager); emit forceSavePreferences(); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psipopup.cpp���������������������������������������������������������������������������0000644�0001750�0001750�00000030412�11305557613�013513� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psipopup.cpp - the Psi passive popup class * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psipopup.h" #include "common.h" #include "fancypopup.h" #include "fancylabel.h" #include "userlist.h" #include "alerticon.h" #include "psievent.h" #include "psicon.h" #include "textutil.h" #include "psiaccount.h" #include "psiiconset.h" #include "iconlabel.h" #include "psioptions.h" #include <qapplication.h> #include <qlayout.h> //Added by qt3to4: #include <QLabel> #include <QVBoxLayout> #include <QHBoxLayout> #include <QBoxLayout> #include <QList> #include <QTextDocument> /** * Limits number of popups that could be displayed * simultaneously on screen. Old popups momentally * disappear when new ones appear. */ static int MaxPopups = 5; /** * Holds a list of Psi Popups. */ static QList<PsiPopup *> *psiPopupList = 0; //---------------------------------------------------------------------------- // PsiPopup::Private //---------------------------------------------------------------------------- class PsiPopup::Private : public QObject { Q_OBJECT public: Private(PsiPopup *p); ~Private(); void init(const PsiIcon *titleIcon, QString titleText, PsiAccount *_acc, PopupType type); QString clipText(QString); QBoxLayout *createContactInfo(const PsiIcon *icon, QString text); private slots: void popupDestroyed(); void popupClicked(int); void eventDestroyed(); public: PsiCon *psi; PsiAccount *account; FancyPopup *popup; PsiPopup *psiPopup; QString id; PopupType popupType; Jid jid; Status status; PsiEvent *event; PsiIcon *titleIcon; bool display; }; PsiPopup::Private::Private(PsiPopup *p) { psiPopup = p; popup = 0; popupType = AlertNone; event = 0; titleIcon = 0; } PsiPopup::Private::~Private() { if ( psiPopupList ) psiPopupList->removeAll(psiPopup); if ( popup ) delete popup; if ( titleIcon ) delete titleIcon; popup = 0; } void PsiPopup::Private::init(const PsiIcon *_titleIcon, QString titleText, PsiAccount *acc, PopupType type) { psi = acc->psi(); account = acc; display = true; if ( !PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.enabled").toBool() ) return; if ( !psiPopupList ) psiPopupList = new QList<PsiPopup *>(); if ( psiPopupList->count() >= MaxPopups && MaxPopups > 0 ) delete psiPopupList->first(); FancyPopup *lastPopup = 0; if ( psiPopupList->count() && psiPopupList->last() ) lastPopup = psiPopupList->last()->popup(); if ( type != AlertNone ) titleIcon = new AlertIcon(_titleIcon); else titleIcon = new PsiIcon(*_titleIcon); FancyPopup::setHideTimeout( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.duration").toInt() ); FancyPopup::setBorderColor( PsiOptions::instance()->getOption("options.ui.look.colors.passive-popup.border").value<QColor>() ); popup = new FancyPopup(titleText, titleIcon, lastPopup, false); connect(popup, SIGNAL(clicked(int)), SLOT(popupClicked(int))); connect(popup, SIGNAL(destroyed()), SLOT(popupDestroyed())); // create id if ( _titleIcon ) id += _titleIcon->name(); id += titleText; } void PsiPopup::Private::popupDestroyed() { popup = 0; psiPopup->deleteLater(); } void PsiPopup::Private::popupClicked(int button) { if ( button == (int)Qt::LeftButton ) { if ( event ) psi->processEvent(event, UserAction); else if ( account ) { // FIXME: it should work in most cases, but // maybe it's better to fix UserList::find()? Jid j( jid.bare() ); account->actionDefault( j ); } } } void PsiPopup::Private::eventDestroyed() { popup->deleteLater(); event = 0; } QString PsiPopup::Private::clipText(QString text) { if ( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-text-length").toInt() > 0 ) { // richtext will give us trouble here if ( ((int)text.length()) > PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-text-length").toInt() ) { text = text.left( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-text-length").toInt() ); // delete last unclosed tag /*if ( text.find("</") > text.find(">") ) { text = text.left( text.find("</") ); }*/ text += "..."; } } return text; } QBoxLayout *PsiPopup::Private::createContactInfo(const PsiIcon *icon, QString text) { QHBoxLayout *dataBox = new QHBoxLayout(); if ( icon ) { IconLabel *iconLabel = new IconLabel(popup); iconLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); iconLabel->setPsiIcon(icon); dataBox->addWidget(iconLabel); dataBox->addSpacing(5); } QLabel *textLabel = new QLabel(popup); QFont font; font.fromString( PsiOptions::instance()->getOption("options.ui.look.font.passive-popup").toString() ); textLabel->setFont(font); textLabel->setWordWrap(false); textLabel->setText(QString("<qt>%1</qt>").arg(clipText(text))); textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); dataBox->addWidget(textLabel); return dataBox; } //---------------------------------------------------------------------------- // PsiPopup //---------------------------------------------------------------------------- PsiPopup::PsiPopup(const PsiIcon *titleIcon, QString titleText, PsiAccount *acc) { d = new Private(this); d->init(titleIcon, titleText, acc, AlertNone); } PsiPopup::~PsiPopup() { delete d; } PsiPopup::PsiPopup(PopupType type, PsiAccount *acc) { d = new Private(this); d->popupType = type; PsiIcon *icon = 0; QString text = "Psi: "; bool doAlertIcon = false; switch(type) { case AlertOnline: text += PsiPopup::tr("Contact online"); icon = (PsiIcon *)IconsetFactory::iconPtr("status/online"); break; case AlertOffline: text += PsiPopup::tr("Contact offline"); icon = (PsiIcon *)IconsetFactory::iconPtr("status/offline"); break; case AlertStatusChange: text += PsiPopup::tr("Status change"); icon = (PsiIcon *)IconsetFactory::iconPtr("status/online"); break; case AlertMessage: text += PsiPopup::tr("Incoming message"); icon = (PsiIcon *)IconsetFactory::iconPtr("psi/message"); doAlertIcon = true; break; case AlertChat: text += PsiPopup::tr("Incoming chat message"); icon= (PsiIcon *)IconsetFactory::iconPtr("psi/chat"); doAlertIcon = true; break; case AlertHeadline: text += PsiPopup::tr("Headline"); icon= (PsiIcon *)IconsetFactory::iconPtr("psi/headline"); doAlertIcon = true; break; case AlertFile: text += PsiPopup::tr("Incoming file"); icon= (PsiIcon *)IconsetFactory::iconPtr("psi/file"); doAlertIcon = true; break; case AlertAvCall: text += PsiPopup::tr("Incoming call"); icon= (PsiIcon *)IconsetFactory::iconPtr("psi/call"); doAlertIcon = true; break; default: break; } d->init(icon, text, acc, doAlertIcon ? type : AlertNone); } void PsiPopup::setData(const PsiIcon *icon, QString text) { if ( !d->popup ) { deleteLater(); return; } d->popup->addLayout( d->createContactInfo(icon, text) ); // update id if ( icon ) d->id += icon->name(); d->id += text; show(); } void PsiPopup::setData(const Jid &j, const Resource &r, const UserListItem *u, const PsiEvent *event) { if ( !d->popup ) { deleteLater(); return; } d->jid = j; d->status = r.status(); d->event = (PsiEvent *)event; if ( event ) connect(event, SIGNAL(destroyed()), d, SLOT(eventDestroyed())); PsiIcon *icon = PsiIconset::instance()->statusPtr(j, r.status()); QString text; QString jid = j.full(); if ( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-jid-length").toInt() > 0 && ((int)jid.length()) > PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-jid-length").toInt() ) jid = jid.left( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-jid-length").toInt() ) + "..."; QString status; if ( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-status-length").toInt() != 0 ) status = r.status().status(); if ( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-status-length").toInt() > 0 ) if ( ((int)status.length()) > PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-status-length").toInt() ) status = status.left ( PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-status-length").toInt() ) + "..."; QString name; if ( u && !u->name().isEmpty() ) { name = u->name(); } else if (event && event->type() == PsiEvent::Auth) { name = ((AuthEvent*) event)->nick(); } else if (event && event->type() == PsiEvent::Message) { name = ((MessageEvent*) event)->nick(); } if (!name.isEmpty()) { if ( !PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.maximum-jid-length").toInt() ) name = "<nobr>" + Qt::escape(name) + "</nobr>"; else name = "<nobr>" + Qt::escape(name) + " <" + Qt::escape(jid) + ">" + "</nobr>"; } else name = "<nobr><" + Qt::escape(jid) + "></nobr>"; QString statusString = TextUtil::plain2rich(status); if ( PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool() ) statusString = TextUtil::emoticonify(statusString); if( PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool() ) statusString = TextUtil::legacyFormat(statusString); if ( !statusString.isEmpty() ) statusString = "<br>" + statusString; QString contactText = "<font size=\"+1\">" + name + "</font>" + statusString; // hack for duplicate "Contact Online"/"Status Change" popups foreach (PsiPopup *pp, *psiPopupList) { if ( d->jid.full() == pp->d->jid.full() && d->status.show() == pp->d->status.show() && d->status.status() == d->status.status() ) { if ( d->popupType == AlertStatusChange && pp->d->popupType == AlertOnline ) { d->display = false; deleteLater(); break; } } } // show popup if ( d->popupType != AlertHeadline && (d->popupType != AlertFile || !PsiOptions::instance()->getOption("options.ui.file-transfer.auto-popup").toBool()) ) setData(icon, contactText); else if ( d->popupType == AlertHeadline ) { QVBoxLayout *vbox = new QVBoxLayout; vbox->addLayout( d->createContactInfo(icon, contactText) ); vbox->addSpacing(5); const Message *jmessage = &((MessageEvent *)event)->message(); QString message; if ( !jmessage->subject().isEmpty() ) message += "<font color=\"red\"><b>" + tr("Subject:") + ' ' + jmessage->subject() + "</b></font><br>"; message += TextUtil::plain2rich( jmessage->body() ); QLabel *messageLabel = new QLabel(d->popup); QFont font = messageLabel->font(); font.setPointSize(common_smallFontSize); messageLabel->setFont(font); messageLabel->setWordWrap(true); messageLabel->setTextFormat(Qt::RichText); messageLabel->setText( d->clipText(TextUtil::linkify( message )) ); messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); vbox->addWidget(messageLabel); // update id if ( icon ) d->id += icon->name(); d->id += contactText; d->id += message; d->popup->addLayout( vbox ); show(); } } void PsiPopup::show() { if ( !d->popup ) { deleteLater(); return; } if ( !d->id.isEmpty() /*&& LEGOPTS.ppNoDupes*/ ) { foreach (PsiPopup *pp, *psiPopupList) { if ( d->id == pp->id() && pp->popup() ) { pp->popup()->restartHideTimer(); d->display = false; break; } } } if ( d->display ) { psiPopupList->append( this ); d->popup->show(); } else { deleteLater(); } } QString PsiPopup::id() const { return d->id; } FancyPopup *PsiPopup::popup() { return d->popup; } void PsiPopup::deleteAll() { if ( !psiPopupList ) return; psiPopupList->clear(); delete psiPopupList; psiPopupList = 0; } #include "psipopup.moc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/accountregdlg.cpp����������������������������������������������������������������������0000644�0001750�0001750�00000024732�11305557613�014465� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * accountregdlg.cpp - dialogs for manipulating PsiAccounts * Copyright (C) 2001, 2002, 2006 Justin Karneges, Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <QtCrypto> #include <QMessageBox> #include <QScrollArea> #include "accountregdlg.h" #include "proxy.h" #include "serverlistquerier.h" #include "miniclient.h" #include "xmpp_tasks.h" #include "psioptions.h" #include "jidutil.h" #include "textutil.h" #include "xdata_widget.h" using namespace XMPP; AccountRegDlg::AccountRegDlg(ProxyManager *pm, QWidget *parent) : QDialog(parent) { ui_.setupUi(this); setModal(false); // TODO: If the domain is fixed, and the connection settings are fixed, skip first // step // Initialize settings ssl_ = UserAccount::SSL_Auto; legacy_ssl_probe_ = true; port_ = 5222; // Server select button connect(ui_.le_server,SIGNAL(popup()),SLOT(selectServer())); serverlist_querier_ = new ServerListQuerier(this); connect(serverlist_querier_,SIGNAL(listReceived(const QStringList&)),SLOT(serverListReceived(const QStringList&))); connect(serverlist_querier_,SIGNAL(error(const QString&)),SLOT(serverListError(const QString&))); // Manual Host/Port ui_.le_host->setEnabled(false); ui_.lb_host->setEnabled(false); ui_.le_port->setEnabled(false); ui_.lb_port->setEnabled(false); connect(ui_.ck_host, SIGNAL(toggled(bool)), SLOT(hostToggled(bool))); // SSL ui_.cb_ssl->addItem(tr("Always"),UserAccount::SSL_Yes); ui_.cb_ssl->addItem(tr("When available"),UserAccount::SSL_Auto); ui_.cb_ssl->addItem(tr("Legacy SSL"), UserAccount::SSL_Legacy); ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(ssl_)); connect(ui_.cb_ssl, SIGNAL(activated(int)), SLOT(sslActivated(int))); ui_.ck_legacy_ssl_probe->setChecked(legacy_ssl_probe_); // Cancel and next buttons connect(ui_.pb_cancel, SIGNAL(clicked()), SLOT(close())); connect(ui_.pb_next, SIGNAL(clicked()), SLOT(next())); // Proxy proxy_manager_ = pm; proxy_chooser_ = proxy_manager_->createProxyChooser(ui_.gb_connection); replaceWidget(ui_.lb_proxychooser, proxy_chooser_); proxy_chooser_->setCurrentItem(0); // Fields pane QVBoxLayout *fields_layout = new QVBoxLayout(ui_.page_fields); fields_layout->setMargin(0); fields_container_ = new QScrollArea(ui_.page_fields); fields_layout->addWidget(fields_container_); fields_container_->setWidgetResizable(true); fields_layout->addStretch(20); fields_ = NULL; ui_.le_port->setText(QString::number(port_)); ui_.le_host->setFocus(); client_ = new MiniClient; connect(client_, SIGNAL(handshaken()), SLOT(client_handshaken())); connect(client_, SIGNAL(error()), SLOT(client_error())); if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) { ui_.gb_server->hide(); } } AccountRegDlg::~AccountRegDlg() { delete client_; } void AccountRegDlg::done(int r) { if(ui_.busy->isActive()) { int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel the registration?"), tr("&Yes"), tr("&No")); if(n != 0) return; } client_->close(); QDialog::done(r); } void AccountRegDlg::sslActivated(int i) { if ((ui_.cb_ssl->itemData(i) == UserAccount::SSL_Yes || ui_.cb_ssl->itemData(i) == UserAccount::SSL_Legacy) && !checkSSL()) { ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(UserAccount::SSL_Auto)); } else if (ui_.cb_ssl->itemData(i) == UserAccount::SSL_Legacy && !ui_.ck_host->isChecked()) { QMessageBox::critical(this, tr("Error"), tr("Legacy SSL is only available in combination with manual host/port.")); ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(UserAccount::SSL_Auto)); } } bool AccountRegDlg::checkSSL() { if(!QCA::isSupported("tls")) { QMessageBox::information(this, tr("SSL error"), tr("Cannot enable SSL/TLS. QCA2 Plugin not found.")); return false; } return true; } void AccountRegDlg::hostToggled(bool on) { ui_.le_host->setEnabled(on); ui_.le_port->setEnabled(on); ui_.lb_host->setEnabled(on); ui_.lb_port->setEnabled(on); if (!on && ui_.cb_ssl->currentIndex() == ui_.cb_ssl->findData(UserAccount::SSL_Legacy)) { ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(UserAccount::SSL_Auto)); } } void AccountRegDlg::selectServer() { if (ui_.le_server->count() == 0) { ui_.busy->start(); block(); serverlist_querier_->getList(); } } void AccountRegDlg::serverListReceived(const QStringList& list) { ui_.busy->stop(); unblock(); ui_.le_server->clear(); ui_.le_server->addItems(list); ui_.le_server->showPopup(); } void AccountRegDlg::serverListError(const QString& e) { ui_.busy->stop(); unblock(); QString error = tr("There was an error retrieving the server list"); if (!e.isEmpty()) { error += ".\n" + tr("Reason: ") + e; } qWarning("%s", qPrintable(error)); //QMessageBox::critical(this, tr("Error"), error); ui_.le_server->setFocus(); } void AccountRegDlg::next() { if (ui_.sw_register->currentWidget() == ui_.page_server) { // Update settings server_ = JIDUtil::accountFromString(ui_.le_server->currentText().trimmed()); ssl_ = (UserAccount::SSLFlag) ui_.cb_ssl->itemData(ui_.cb_ssl->currentIndex()).toInt(); legacy_ssl_probe_ = ui_.ck_legacy_ssl_probe->isChecked(); opt_host_ = ui_.ck_host->isChecked(); host_ = ui_.le_host->text(); port_ = ui_.le_port->text().toInt(); proxy_ = proxy_chooser_->currentItem(); // Sanity check if (server_.isNull() || !server_.node().isEmpty() || !server_.resource().isEmpty()) { QMessageBox::critical(this, tr("Error"), tr("You have entered an invalid server name")); return; } // Connect to the server ui_.busy->start(); block(); client_->connectToServer(server_, legacy_ssl_probe_, ssl_ == UserAccount::SSL_Legacy, ssl_ == UserAccount::SSL_Yes, opt_host_ ? host_ : QString(), port_, proxy_manager_, proxy_); } else if (ui_.sw_register->currentWidget() == ui_.page_fields) { // Initialize the form XMPP::XData fields; fields.setFields(fields_->fields()); // Determine the username and password foreach(XMPP::XData::Field field, fields.fields()) { if (field.var() == "username" && !field.value().isEmpty()) { jid_ = Jid(field.value().at(0), server_.bare(), ""); } else if (field.var() == "password" && !field.value().isEmpty()) { pass_ = field.value().at(0); } } // Register ui_.busy->start(); block(); JT_Register *reg = new JT_Register(client_->client()->rootTask()); connect(reg, SIGNAL(finished()), SLOT(setFields_finished())); if (isOld_) { Form form = convertFromXData(fields); form.setJid(server_); reg->setForm(form); } else { reg->setForm(server_,fields); } reg->go(true); } } void AccountRegDlg::client_handshaken() { // try to register an account JT_Register *reg = new JT_Register(client_->client()->rootTask()); connect(reg, SIGNAL(finished()), SLOT(getFields_finished())); reg->getForm(server_); reg->go(true); } void AccountRegDlg::client_error() { ui_.busy->stop(); unblock(); if (ui_.sw_register->currentWidget() == ui_.page_fields) { // Start over delete fields_; fields_ = NULL; ui_.sw_register->setCurrentWidget(ui_.page_server); } } void AccountRegDlg::getFields_finished() { JT_Register *reg = (JT_Register *)sender(); ui_.busy->stop(); if (reg->success()) { unblock(); fields_ = new XDataWidget(ui_.page_fields); XData xdata; if (reg->hasXData()) { isOld_ = false; xdata = reg->xdata(); } else { isOld_ = true; xdata = convertToXData(reg->form()); } if (xdata.instructions().isEmpty()) xdata.setInstructions(tr("Please provide the following information:")); xdata.setInstructions(TextUtil::linkify(xdata.instructions())); fields_->setForm(xdata); fields_container_->setWidget(fields_); fields_container_->updateGeometry(); ui_.sw_register->setCurrentWidget(ui_.page_fields); } else { QMessageBox::critical(this, tr("Error"), tr("This server does not support registration")); unblock(); } } void AccountRegDlg::setFields_finished() { JT_Register *reg = (JT_Register *)sender(); ui_.busy->stop(); if (reg->success()) { QMessageBox::information(this, tr("Success"), QString(tr("You have succesfully registered your account with Jabber ID '%1'")).arg(jid_.bare())); tlsOverrideCert_ = client_->tlsOverrideCert; tlsOverrideDomain_ = client_->tlsOverrideDomain; client_->close(); accept(); } else { unblock(); QMessageBox::critical(this, tr("Error"), QString(tr("There was an error registering the account.\nReason: %1")).arg(reg->statusString())); } } XMPP::XData AccountRegDlg::convertToXData(const XMPP::Form& form) { // Convert the fields XData::FieldList fields; foreach(FormField f, form) { XData::Field field; field.setLabel(f.fieldName()); field.setVar(f.realName()); field.setRequired(true); if (f.isSecret()) { field.setType(XData::Field::Field_TextPrivate); } else { field.setType(XData::Field::Field_TextSingle); } fields.push_back(field); } // Create the form XData xdata; xdata.setInstructions(form.instructions()); xdata.setFields(fields); return xdata; } XMPP::Form AccountRegDlg::convertFromXData(const XMPP::XData& xdata) { Form form; foreach(XMPP::XData::Field field, xdata.fields()) { if (!field.value().isEmpty()) { FormField f; f.setType(field.var()); f.setValue(field.value().at(0)); form.push_back(f); } } return form; } void AccountRegDlg::block() { if (ui_.sw_register->currentWidget() == ui_.page_server) { ui_.gb_server->setEnabled(false); ui_.gb_connection->setEnabled(false); ui_.pb_next->setEnabled(false); } else if (ui_.sw_register->currentWidget() == ui_.page_fields) { if (fields_) fields_->setEnabled(false); } } void AccountRegDlg::unblock() { if (ui_.sw_register->currentWidget() == ui_.page_server) { ui_.gb_server->setEnabled(true); ui_.gb_connection->setEnabled(true); ui_.pb_next->setEnabled(true); } else if (ui_.sw_register->currentWidget() == ui_.page_fields) { ui_.pb_next->setEnabled(true); if (fields_) fields_->setEnabled(true); } } ��������������������������������������psi-0.14/src/ahcommand.h����������������������������������������������������������������������������0000644�0001750�0001750�00000006362�11305557613�013237� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ahcommand.h - Ad-Hoc Command * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHCOMMAND_H #define AHCOMMAND_H #include <QString> #include "xmpp_xdata.h" class QDomElement; class QDomDocument; class AHCError { public: enum ErrorType { None, MalformedAction, BadAction, BadLocale, BadPayload, BadSessionID, SessionExpired, Forbidden, ItemNotFound, FeatureNotImplemented }; AHCError(ErrorType = None); AHCError(const QDomElement& e); ErrorType type() const { return type_; } static QString error2description(const AHCError&); QDomElement toXml(QDomDocument* doc) const; protected: static ErrorType strings2error(const QString&, const QString&); private: ErrorType type_; }; class AHCommand { public: // Types enum Action { NoAction, Execute, Prev, Next, Complete, Cancel }; enum Status { NoStatus, Completed, Executing, Canceled }; typedef QList<Action> ActionList; // Constructors AHCommand(const QString& node, const QString& sessionId = "", Action action = Execute); AHCommand(const QString& node, XMPP::XData data, const QString& sessionId = "", Action action = Execute); AHCommand(const QDomElement &e); // Inspectors const QString& node() const { return node_; } bool hasData() const { return hasData_; } const XMPP::XData& data() const { return data_; } const ActionList& actions() const { return actions_; } Action defaultAction() const { return defaultAction_; } Status status() const { return status_; } Action action() const { return action_; } const QString& sessionId() const { return sessionId_; } const AHCError& error() const { return error_; } // XML conversion QDomElement toXml(QDomDocument* doc, bool submit) const; // Helper constructors static AHCommand formReply(const AHCommand&, const XMPP::XData&); static AHCommand formReply(const AHCommand&, const XMPP::XData&, const QString& sessionId); static AHCommand canceledReply(const AHCommand&); static AHCommand completedReply(const AHCommand&); static AHCommand completedReply(const AHCommand&, const XMPP::XData&); //static AHCommand errorReply(const AHCommand&, const AHCError&); protected: void setStatus(Status s); void setError(const AHCError& e); void setDefaultAction(Action a); static QString action2string(Action); static QString status2string(Status); static Action string2action(const QString&); static Status string2status(const QString&); private: QString node_; bool hasData_; XMPP::XData data_; Status status_; Action defaultAction_; ActionList actions_; Action action_; QString sessionId_; AHCError error_; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/shortcutmanager.h����������������������������������������������������������������������0000644�0001750�0001750�00000001125�11305557613�014506� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef SHORTCUTMANAGER_H #define SHORTCUTMANAGER_H #include <QObject> #include <QList> class QKeySequence; class QString; class PsiOptions; class ShortcutManager : public QObject { public: static ShortcutManager* instance(); static void connect(const QString& path, QObject *parent, const char* slot); QKeySequence shortcut(const QString& name); QList<QKeySequence> shortcuts(const QString& name); // utils static QList<QKeySequence> readShortcutsFromOptions(const QString& name, const PsiOptions* options); private: ShortcutManager(); static ShortcutManager* instance_; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psioptionseditor.cpp�������������������������������������������������������������������0000644�0001750�0001750�00000017076�11305557613�015265� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <QVBoxLayout> #include <QHBoxLayout> #include <QDialog> #include <QVariant> #include <QMessageBox> #include <QTextDocument> #include "psioptionseditor.h" #include "psioptions.h" #include "common.h" #include "iconset.h" #include "ui_optioneditor.h" class OptionEditor : public QDialog, protected Ui_OptionEditor { Q_OBJECT public: OptionEditor(bool new_, QString name, QVariant value); signals: void commit(QString name, QVariant value); protected slots: void finished(); protected: struct supportedType { const char *name; QVariant::Type typ; }; static supportedType supportedTypes[]; }; OptionEditor::supportedType OptionEditor::supportedTypes[] = { {"bool", QVariant::Bool}, {"int", QVariant::Int}, {"QKeySequence", QVariant::KeySequence}, {"QSize", QVariant::Size}, {"QString", QVariant::String}, // {"QStringList", QVariant::StringList}, does't work {0, QVariant::Invalid}}; OptionEditor::OptionEditor(bool new_, QString name_, QVariant value_) { setupUi(this); if (new_) { setWindowTitle(tr("Psi: Option Editor")); } else { setWindowTitle(tr("Psi: Edit Option %1").arg(name_)); } connect(buttonBox, SIGNAL(accepted()), this, SLOT(finished())); for (int i=0; supportedTypes[i].name; i++) { cb_typ->addItem(supportedTypes[i].name); } le_option->setText(name_); if (!new_) { le_option->setReadOnly(false); lb_comment->setText(PsiOptions::instance()->getComment(name_)); } if (value_.isValid()) { bool ok=false; for (int i=0; supportedTypes[i].name; i++) { if (value_.type() == supportedTypes[i].typ) { cb_typ->setCurrentIndex(i); le_value->setText(value_.toString()); ok = true; break; } } if (!ok) { QMessageBox::critical(this, tr("Psi: Option Editor"), tr("Can't edit this type of setting, sorry."), QMessageBox::Close); deleteLater(); } } resize(sizeHint()); show(); } void OptionEditor::finished() { QString option = le_option->text(); if (option.isEmpty() || option.endsWith(".") || option.contains("..") || !PsiOptions::isValidName(option)) { QMessageBox::critical(this, tr("Psi: Option Editor"), tr("Please enter option name.\n\n" "Option names may not be empty, end in '.' or contain '..'."), QMessageBox::Close); return; } QVariant strval(le_value->text()); QVariant::Type type = supportedTypes[cb_typ->currentIndex()].typ; QVariant newval = strval; newval.convert(type); PsiOptions::instance()->setOption(option, newval); accept(); } PsiOptionsEditor::PsiOptionsEditor(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_DeleteOnClose, true); setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); o_ = PsiOptions::instance(); tm_ = new OptionsTreeModel(o_); QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); tv_ = new QTreeView(this); tv_->setModel(tm_); tv_->setAlternatingRowColors(true); layout->addWidget(tv_); tv_->setColumnHidden(1, true); tv_->setColumnHidden(3, true); tv_->resizeColumnToContents(0); tv_colWidth = tv_->columnWidth(0); QHBoxLayout *infoLine = new QHBoxLayout; layout->addLayout(infoLine); lb_path = new QLabel(this); lb_path->setTextInteractionFlags(Qt::TextSelectableByMouse); lb_path->setToolTip(tr("Full name of the currently selected option.")); infoLine->addWidget(lb_path); infoLine->addStretch(1); lb_type = new QLabel(this); lb_type->setText(tr("(no selection)")); lb_type->setTextFormat(Qt::RichText); infoLine->addWidget(lb_type); lb_comment = new QLabel(this); lb_comment->setTextInteractionFlags(Qt::TextSelectableByMouse); lb_comment->setText(" "); lb_comment->setWordWrap(true); lb_comment->setTextFormat(Qt::PlainText); layout->addWidget(lb_comment); QHBoxLayout* buttonLine = new QHBoxLayout; layout->addLayout(buttonLine); cb_ = new QCheckBox(this); cb_->setText(tr("Flat")); cb_->setToolTip(tr("Display all options as a flat list.")); cb_->setProperty("isOption", false); connect(cb_,SIGNAL(toggled(bool)),tm_,SLOT(setFlat(bool))); buttonLine->addWidget(cb_); buttonLine->addStretch(1); if (1) { // FIXME pb_delete = new QPushButton(tr("Delete"), this); buttonLine->addWidget(pb_delete); connect(pb_delete, SIGNAL(clicked()), SLOT(deleteit())); } pb_edit = new QPushButton(tr("Edit..."), this); buttonLine->addWidget(pb_edit); connect(pb_edit, SIGNAL(clicked()), SLOT(edit())); pb_new = new QPushButton(tr("Add..."), this); buttonLine->addWidget(pb_new); connect(pb_new, SIGNAL(clicked()), SLOT(add())); if (parent) { pb_detach = new QToolButton(this); pb_detach->setIcon(IconsetFactory::iconPixmap("psi/advanced")); pb_detach->setIconSize(QSize(16,16)); pb_detach->setToolTip(tr("Open a detached option editor window.")); buttonLine->addWidget(pb_detach); connect(pb_detach, SIGNAL(clicked()), SLOT(detach())); } connect(tv_->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), SLOT(selectionChanged(const QModelIndex &))); connect(tv_,SIGNAL(activated(const QModelIndex&)),SLOT(tv_edit(const QModelIndex&))); connect(tv_,SIGNAL(expanded(const QModelIndex&)), SLOT(updateWidth())); connect(tv_,SIGNAL(collapsed(const QModelIndex&)), SLOT(updateWidth())); tv_->setCurrentIndex(tm_->index(0,0, QModelIndex())); if (!parent) show(); } void PsiOptionsEditor::tv_edit( const QModelIndex &idx) { //QModelIndex idx = tv_->currentIndex(); QString option = tm_->indexToOptionName(idx); QVariant value = PsiOptions::instance()->getOption(option); if (value.type() == QVariant::Bool) { PsiOptions::instance()->setOption(option, QVariant(!value.toBool())); } else { edit(); } } void PsiOptionsEditor::updateWidth() { if (tv_->columnWidth(0) == tv_colWidth) { tv_->resizeColumnToContents(0); tv_colWidth = tv_->columnWidth(0); } } void PsiOptionsEditor::selectionChanged( const QModelIndex &idx) { QString type = tm_->data(idx.sibling(idx.row(), 1), Qt::DisplayRole).toString(); QString comment = tm_->data(idx.sibling(idx.row(), 3), Qt::DisplayRole).toString(); lb_path->setText("<b>"+Qt::escape(tm_->indexToOptionName(idx))+"</b>"); lb_comment->setText(comment); updateWidth(); QString option = tm_->indexToOptionName(idx); QString typ; if (o_->isInternalNode(option)) { typ = tr("(internal node)"); pb_edit->setEnabled(false); } else { typ = tr("Type:") + " <b>" + Qt::escape(type) + "</b>"; pb_edit->setEnabled(true); } lb_type->setText("   " + typ); } void PsiOptionsEditor::add() { QModelIndex idx = tv_->currentIndex(); QString option = tm_->indexToOptionName(idx); if (o_->isInternalNode(option)) { option += "."; } else { option = option.left(option.lastIndexOf(".")+1); } new OptionEditor(true, option, QVariant()); } void PsiOptionsEditor::edit() { QModelIndex idx = tv_->currentIndex(); QString option = tm_->indexToOptionName(idx); if (!o_->isInternalNode(option)) { new OptionEditor(false, option, PsiOptions::instance()->getOption(option)); } } void PsiOptionsEditor::deleteit() { QModelIndex idx = tv_->currentIndex(); QString option = tm_->indexToOptionName(idx); bool sub = false; QString confirm = tr("Really delete options %1?"); if (o_->isInternalNode(option)) { sub = true; confirm = tr("Really delete all options starting with %1.?"); } if (QMessageBox::Yes == QMessageBox::warning(this, tr("Psi: Option Editor"), confirm.arg(option), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel)) { PsiOptions::instance()->removeOption( option, sub); } } void PsiOptionsEditor::detach() { new PsiOptionsEditor(); } void PsiOptionsEditor::bringToFront() { ::bringToFront(this, true); } #include "psioptionseditor.moc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/ahcommandserver.cpp��������������������������������������������������������������������0000644�0001750�0001750�00000002445�11305557613�015017� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ahcommandserver.cpp - Server implementation of JEP-50 (Ad-Hoc Commands) * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "ahcommandserver.h" #include "ahcservermanager.h" // -------------------------------------------------------------------------- // AHCommandServer: The server-side implementation of an Ad-hoc command. // -------------------------------------------------------------------------- AHCommandServer::AHCommandServer(AHCServerManager* manager) : manager_(manager) { manager_->addServer(this); } AHCommandServer::~AHCommandServer() { manager_->removeServer(this); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/psi_profiles.cpp�����������������������������������������������������������������������0000644�0001750�0001750�00000135620�11305557613�014341� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * profiles.cpp - deal with profiles * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "profiles.h" #include "common.h" #include "applicationinfo.h" #include <qdir.h> #include <qfileinfo.h> #include <qdom.h> #include <qapplication.h> //Added by qt3to4: #include <QTextStream> #include <QtCrypto> #include <QList> #include "eventdlg.h" #include "chatdlg.h" #include "pgputil.h" #include "xmpp_xmlcommon.h" #include "fancylabel.h" #include "advwidget.h" #include "psioptions.h" #include "varlist.h" #include "atomicxmlfile.h" #include "psitoolbar.h" #include "optionstree.h" using namespace XMPP; using namespace XMLHelper; #define PROXY_NONE 0 #define PROXY_HTTPS 1 #define PROXY_SOCKS4 2 #define PROXY_SOCKS5 3 template<typename T, typename F> void migrateEntry(const QDomElement& element, const QString& entry, const QString& option, F f) { bool found; findSubTag(element, entry, &found); if (found) { T value; f(element, entry, &value); PsiOptions::instance()->setOption(option, value); } } void migrateIntEntry(const QDomElement& element, const QString& entry, const QString& option) { migrateEntry<int>(element, entry, option, readNumEntry); } void migrateBoolEntry(const QDomElement& element, const QString& entry, const QString& option) { migrateEntry<bool>(element, entry, option, readBoolEntry); } void migrateSizeEntry(const QDomElement& element, const QString& entry, const QString& option) { migrateEntry<QSize>(element, entry, option, readSizeEntry); } void migrateStringEntry(const QDomElement& element, const QString& entry, const QString& option) { migrateEntry<QString>(element, entry, option, readEntry); } void migrateStringList(const QDomElement& element, const QString& entry, const QString& option) { migrateEntry<QStringList>(element, entry, option, xmlToStringList); } void migrateColorEntry(const QDomElement& element, const QString &entry, const QString &option) { migrateEntry<QColor>(element, entry, option, readColorEntry); } void migrateRectEntry(const QDomElement& element, const QString &entry, const QString &option) { migrateEntry<QRect>(element, entry, option, readRectEntry); } UserAccount::UserAccount() { reset(); } void UserAccount::reset() { name = "Default"; opt_enabled = true; opt_auto = false; tog_offline = true; tog_away = true; tog_hidden = false; tog_agents = true; tog_self = false; customAuth = false; req_mutual_auth = false; legacy_ssl_probe = true; security_level = QCA::SL_None; ssl = SSL_Auto; jid = ""; pass = ""; opt_pass = false; port = 5222; opt_host = false; host = ""; opt_automatic_resource = true; resource = "Psi"; priority = 5; opt_keepAlive = true; allow_plain = XMPP::ClientStream::AllowPlainOverTLS; opt_compress = false; opt_log = true; opt_reconn = false; opt_connectAfterSleep = false; opt_ignoreSSLWarnings = false; proxy_index = 0; proxy_type = PROXY_NONE; proxy_host = ""; proxy_port = 8080; proxy_user = ""; proxy_pass = ""; stunPort = 3478; keybind.clear(); roster.clear(); } UserAccount::~UserAccount() { } void UserAccount::fromOptions(OptionsTree *o, QString base) { // WARNING: If you add any new option here, only read the option if // allSetOptions (defined below) contains the new option. If not // the code should just leave the default value from the reset() // call in place. optionsBase = base; reset(); QStringList allSetOptions = o->getChildOptionNames(base, true, true); opt_enabled = o->getOption(base + ".enabled").toBool(); opt_auto = o->getOption(base + ".auto").toBool(); opt_keepAlive = o->getOption(base + ".keep-alive").toBool(); opt_compress = o->getOption(base + ".compress").toBool(); req_mutual_auth = o->getOption(base + ".require-mutual-auth").toBool(); legacy_ssl_probe = o->getOption(base + ".legacy-ssl-probe").toBool(); opt_automatic_resource = o->getOption(base + ".automatic-resource").toBool(); opt_log = o->getOption(base + ".log").toBool(); opt_reconn = o->getOption(base + ".reconn").toBool(); opt_ignoreSSLWarnings = o->getOption(base + ".ignore-SSL-warnings").toBool(); // FIX-ME: See FS#771 if (o->getChildOptionNames().contains(base + ".connect-after-sleep")) { opt_connectAfterSleep = o->getOption(base + ".connect-after-sleep").toBool(); } else { o->setOption(base + ".connect-after-sleep", opt_connectAfterSleep); } name = o->getOption(base + ".name").toString(); jid = o->getOption(base + ".jid").toString(); customAuth = o->getOption(base + ".custom-auth.use").toBool(); authid = o->getOption(base + ".custom-auth.authid").toString(); realm = o->getOption(base + ".custom-auth.realm").toString(); // read password (we must do this after reading the jid, to decode properly) QString tmp = o->getOption(base + ".password").toString(); if(!tmp.isEmpty()) { opt_pass = true; pass = decodePassword(tmp, jid); } opt_host = o->getOption(base + ".use-host").toBool(); security_level = o->getOption(base + ".security-level").toInt(); tmp = o->getOption(base + ".ssl").toString(); if (tmp == "no") { ssl = SSL_No; } else if (tmp == "yes") { ssl = SSL_Yes; } else if (tmp == "auto") { ssl = SSL_Auto; } else if (tmp == "legacy") { ssl = SSL_Legacy; } else { ssl = SSL_Yes; } host = o->getOption(base + ".host").toString(); port = o->getOption(base + ".port").toInt(); resource = o->getOption(base + ".resource").toString(); priority = o->getOption(base + ".priority").toInt(); QString pgpSecretKeyID = o->getOption(base + ".pgp-secret-key-id").toString(); if (!pgpSecretKeyID.isEmpty()) { QCA::KeyStoreEntry e = PGPUtil::instance().getSecretKeyStoreEntry(pgpSecretKeyID); if (!e.isNull()) pgpSecretKey = e.pgpSecretKey(); } tmp = o->getOption(base + ".allow-plain").toString(); if (tmp == "never") { allow_plain = XMPP::ClientStream::NoAllowPlain; } else if (tmp == "always") { allow_plain = XMPP::ClientStream::AllowPlain; } else if (tmp == "over encryped") { allow_plain = XMPP::ClientStream::AllowPlainOverTLS; } else { allow_plain = XMPP::ClientStream::NoAllowPlain; } QStringList rosterCache = o->getChildOptionNames(base + ".roster-cache", true, true); foreach(QString rbase, rosterCache) { RosterItem ri; ri.setJid(Jid(o->getOption(rbase + ".jid").toString())); ri.setName(o->getOption(rbase + ".name").toString()); Subscription s; s.fromString(o->getOption(rbase + ".subscription").toString()); ri.setSubscription(s); ri.setAsk(o->getOption(rbase + ".ask").toString()); ri.setGroups(o->getOption(rbase + ".groups").toStringList()); roster += ri; } groupState.clear(); QVariantList states = o->mapKeyList(base + ".group-state"); foreach(QVariant k, states) { GroupData gd; QString sbase = o->mapLookup(base + ".group-state", k); gd.open = o->getOption(sbase + ".open").toBool(); gd.rank = o->getOption(sbase + ".rank").toInt(); groupState.insert(k.toString(), gd); } proxyID = o->getOption(base + ".proxy-id").toString(); keybind.fromOptions(o, base + ".pgp-key-bindings"); dtProxy = o->getOption(base + ".bytestreams-proxy").toString(); if (allSetOptions.contains(base + ".stun-host")) { stunHost = o->getOption(base + ".stun-host").toString(); } if (allSetOptions.contains(base + ".stun-port")) { int tmpPort = o->getOption(base + ".stun-port").toInt(); // a few days in the 0.13-dev development cycle the code set // 0 as port when first adding this option. Ignore 0 for now // and use default if (tmpPort != 0) stunPort = tmpPort; } if (allSetOptions.contains(base + ".tls")) { tlsOverrideCert = o->getOption(base + ".tls.override-certificate").toByteArray(); tlsOverrideDomain = o->getOption(base + ".tls.override-domain").toString(); } } void UserAccount::toOptions(OptionsTree *o, QString base) { if (base.isEmpty()) { base = optionsBase; } // clear old data away o->removeOption(base, true); o->setOption(base + ".enabled", opt_enabled); o->setOption(base + ".auto", opt_auto); o->setOption(base + ".keep-alive", opt_keepAlive); o->setOption(base + ".compress", opt_compress); o->setOption(base + ".require-mutual-auth", req_mutual_auth); o->setOption(base + ".legacy-ssl-probe", legacy_ssl_probe); o->setOption(base + ".automatic-resource", opt_automatic_resource); o->setOption(base + ".log", opt_log); o->setOption(base + ".reconn", opt_reconn); o->setOption(base + ".connect-after-sleep", opt_connectAfterSleep); o->setOption(base + ".ignore-SSL-warnings", opt_ignoreSSLWarnings); o->setOption(base + ".name", name); o->setOption(base + ".jid", jid); o->setOption(base + ".custom-auth.use", customAuth); o->setOption(base + ".custom-auth.authid", authid); o->setOption(base + ".custom-auth.realm", realm); if(opt_pass) { o->setOption(base + ".password", encodePassword(pass, jid)); } else { o->setOption(base + ".password", ""); } o->setOption(base + ".use-host", opt_host); o->setOption(base + ".security-level", security_level); switch (ssl) { case SSL_No: o->setOption(base + ".ssl", "no"); break; case SSL_Yes: o->setOption(base + ".ssl", "yes"); break; case SSL_Auto: o->setOption(base + ".ssl", "auto"); break; case SSL_Legacy: o->setOption(base + ".ssl", "legacy"); break; default: qFatal("unknown ssl enum value in UserAccount::toOptions"); } o->setOption(base + ".host", host); o->setOption(base + ".port", port); o->setOption(base + ".resource", resource); o->setOption(base + ".priority", priority); if (!pgpSecretKey.isNull()) { o->setOption(base + ".pgp-secret-key-id", pgpSecretKey.keyId()); } else { o->setOption(base + ".pgp-secret-key-id", ""); } switch (allow_plain) { case XMPP::ClientStream::NoAllowPlain: o->setOption(base + ".allow-plain", "never"); break; case XMPP::ClientStream::AllowPlain: o->setOption(base + ".allow-plain", "always"); break; case XMPP::ClientStream::AllowPlainOverTLS: o->setOption(base + ".allow-plain", "over encryped"); break; default: qFatal("unknown allow_plain enum value in UserAccount::toOptions"); } int idx = 0; foreach(RosterItem ri, roster) { QString rbase = base + ".roster-cache.a" + QString::number(idx++); o->setOption(rbase + ".jid", ri.jid().full()); o->setOption(rbase + ".name", ri.name()); o->setOption(rbase + ".subscription", ri.subscription().toString()); o->setOption(rbase + ".ask", ri.ask()); o->setOption(rbase + ".groups", ri.groups()); } // now we check for redundant entries QStringList groupList; QSet<QString> removeList; groupList << "/\\/" + name + "\\/\\"; // account name is a very 'special' group // special groups that should also have their state remembered groupList << qApp->translate("ContactProfile", "General"); groupList << qApp->translate("ContactProfile", "Agents/Transports"); // first, add all groups' names to groupList foreach(RosterItem i, roster) { groupList += i.groups(); } // now, check if there's groupState name entry in groupList foreach(QString group, groupState.keys()) { if (!groupList.contains(group)) { removeList << group; } } // remove redundant groups foreach(QString group, removeList) { groupState.remove( group ); } // and finally, save the data foreach(QString group, groupState.keys()) { QString groupBase = o->mapPut(base + ".group-state", group); o->setOption(groupBase + ".open", groupState[group].open); o->setOption(groupBase + ".rank", groupState[group].rank); } o->setOption(base + ".proxy-id", proxyID); keybind.toOptions(o, base + ".pgp-key-bindings"); o->setOption(base + ".bytestreams-proxy", dtProxy.full()); o->setOption(base + ".stun-host", stunHost); o->setOption(base + ".stun-port", QString::number(stunPort)); o->setOption(base + ".tls.override-certificate", tlsOverrideCert); o->setOption(base + ".tls.override-domain", tlsOverrideDomain); } void UserAccount::fromXml(const QDomElement &a) { reset(); bool found; readEntry(a, "name", &name); readBoolAttribute(a, "enabled", &opt_enabled); readBoolAttribute(a, "auto", &opt_auto); readBoolAttribute(a, "showOffline", &tog_offline); readBoolAttribute(a, "showAway", &tog_away); readBoolAttribute(a, "showHidden", &tog_hidden); readBoolAttribute(a, "showAgents", &tog_agents); readBoolAttribute(a, "showSelf", &tog_self); readBoolAttribute(a, "keepAlive", &opt_keepAlive); readBoolAttribute(a, "compress", &opt_compress); readBoolAttribute(a, "require-mutual-auth", &req_mutual_auth); readBoolAttribute(a, "legacy-ssl-probe", &legacy_ssl_probe); readBoolAttribute(a, "log", &opt_log); readBoolAttribute(a, "reconn", &opt_reconn); readBoolAttribute(a, "ignoreSSLWarnings", &opt_ignoreSSLWarnings); //readBoolAttribute(a, "gpg", &opt_gpg); if (a.hasAttribute("automatic-resource")) { readBoolAttribute(a, "automatic-resource", &opt_automatic_resource); } else { opt_automatic_resource = false; } // Will be overwritten if there is a new option bool opt_plain = false; readBoolAttribute(a, "plain", &opt_plain); allow_plain = (opt_plain ? XMPP::ClientStream::AllowPlain : XMPP::ClientStream::NoAllowPlain); readNumEntry(a, "allow-plain", (int*) &allow_plain); // Will be overwritten if there is a new option bool opt_ssl = true; readBoolAttribute(a, "ssl", &opt_ssl); if (opt_ssl) ssl = UserAccount::SSL_Legacy; readNumEntry(a, "security-level", &security_level); readNumEntry(a, "ssl", (int*) &ssl); readEntry(a, "host", &host); readNumEntry(a, "port", &port); // 0.8.6 and >= 0.9 QDomElement j = findSubTag(a, "jid", &found); if(found) { readBoolAttribute(j, "manual", &opt_host); jid = tagContent(j); } // 0.8.7 else { QString user, vhost; readEntry(a, "username", &user); QDomElement j = findSubTag(a, "vhost", &found); if(found) { readBoolAttribute(j, "manual", &opt_host); vhost = tagContent(j); } else { opt_host = false; vhost = host; host = ""; port = 0; } jid = user + '@' + vhost; } readBoolEntry(a, "useHost", &opt_host); // read password (we must do this after reading the jid, to decode properly) readEntry(a, "password", &pass); if(!pass.isEmpty()) { opt_pass = true; pass = decodePassword(pass, jid); } QDomElement ca = findSubTag(a, "custom-auth", &found); if(found) { readBoolAttribute(ca, "use", &customAuth); QDomElement authid_el = findSubTag(ca, "authid", &found); if (found) authid = tagContent(authid_el); QDomElement realm_el = findSubTag(ca, "realm", &found); if (found) realm = tagContent(realm_el); } readEntry(a, "resource", &resource); readNumEntry(a, "priority", &priority); QString pgpSecretKeyID; readEntry(a, "pgpSecretKeyID", &pgpSecretKeyID); if (!pgpSecretKeyID.isEmpty()) { QCA::KeyStoreEntry e = PGPUtil::instance().getSecretKeyStoreEntry(pgpSecretKeyID); if (!e.isNull()) pgpSecretKey = e.pgpSecretKey(); } QDomElement r = findSubTag(a, "roster", &found); if(found) { for(QDomNode n = r.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { RosterItem ri; if(!ri.fromXml(i)) continue; roster += ri; } } } groupState.clear(); QDomElement gs = findSubTag(a, "groupState", &found); if (found) { for (QDomNode n = gs.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if (i.isNull()) continue; if (i.tagName() == "group") { GroupData gd; gd.open = i.attribute("open") == "true"; gd.rank = i.attribute("rank").toInt(); groupState.insert(i.attribute("name"), gd); } } } readNumEntry(a, "proxyindex", &proxy_index); readNumEntry(a, "proxytype", &proxy_type); readEntry(a, "proxyhost", &proxy_host); readNumEntry(a, "proxyport", &proxy_port); readEntry(a, "proxyuser", &proxy_user); readEntry(a, "proxypass", &proxy_pass); if(!proxy_pass.isEmpty()) proxy_pass = decodePassword(proxy_pass, jid); r = findSubTag(a, "pgpkeybindings", &found); if(found) keybind.fromXml(r); QString str; readEntry(a, "dtProxy", &str); dtProxy = str; } static ToolbarPrefs loadToolbarData( const QDomElement &e ) { QDomElement tb_prefs = e; ToolbarPrefs tb; readEntry(tb_prefs, "name", &tb.name); readBoolEntry(tb_prefs, "on", &tb.on); readBoolEntry(tb_prefs, "locked", &tb.locked); // readBoolEntry(tb_prefs, "stretchable", &tb.stretchable); xmlToStringList(tb_prefs, "keys", &tb.keys); bool found3 = false; QDomElement tb_position = findSubTag(tb_prefs, "position", &found3); if (found3) { QString dockStr; Qt3Dock dock = Qt3Dock_Top; readEntry(tb_position, "dock", &dockStr); if (dockStr == "DockTop") dock = Qt3Dock_Top; else if (dockStr == "DockBottom") dock = Qt3Dock_Bottom; else if (dockStr == "DockLeft") dock = Qt3Dock_Left; else if (dockStr == "DockRight") dock = Qt3Dock_Right; else if (dockStr == "DockMinimized") dock = Qt3Dock_Minimized; else if (dockStr == "DockTornOff") dock = Qt3Dock_TornOff; else if (dockStr == "DockUnmanaged") dock = Qt3Dock_Unmanaged; tb.dock = dock; // readNumEntry(tb_position, "index", &tb.index); readBoolEntry(tb_position, "nl", &tb.nl); // readNumEntry(tb_position, "extraOffset", &tb.extraOffset); } return tb; } bool OptionsMigration::fromFile(const QString &fname) { QString confver; QDomDocument doc; QString progver; AtomicXmlFile f(fname); if (!f.loadDocument(&doc)) return false; QDomElement base = doc.documentElement(); if(base.tagName() != "psiconf") return false; confver = base.attribute("version"); if(confver != "1.0") return false; readEntry(base, "progver", &progver); // migrateRectEntry(base, "geom", "options.ui.contactlist.saved-window-geometry"); migrateStringList(base, "recentGCList", "options.muc.recent-joins.jids"); migrateStringList(base, "recentBrowseList", "options.ui.service-discovery.recent-jids"); migrateStringEntry(base, "lastStatusString", "options.status.last-message"); migrateBoolEntry(base, "useSound", "options.ui.notifications.sounds.enable"); bool found; QDomElement accs = findSubTag(base, "accounts", &found); if(found) { for(QDomNode n = accs.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement a = n.toElement(); if(a.isNull()) continue; if(a.tagName() == "account") { UserAccount ua; ua.fromXml(a); accMigration.append(ua); } } } // convert old proxy config into new for(UserAccountList::Iterator it = accMigration.begin(); it != accMigration.end(); ++it) { UserAccount &a = *it; if(a.proxy_type > 0) { ProxyItem p; p.name = QObject::tr("%1 Proxy").arg(a.name); p.type = "http"; p.settings.host = a.proxy_host; p.settings.port = a.proxy_port; p.settings.useAuth = !a.proxy_user.isEmpty(); p.settings.user = a.proxy_user; p.settings.pass = a.proxy_pass; proxyMigration.append(p); a.proxy_index = proxyMigration.count(); // 1 and up are proxies } } QDomElement prox = findSubTag(base, "proxies", &found); if(found) { QDomNodeList list = prox.elementsByTagName("proxy"); for(int n = 0; n < list.count(); ++n) { QDomElement e = list.item(n).toElement(); ProxyItem p; p.name = ""; p.type = ""; readEntry(e, "name", &p.name); readEntry(e, "type", &p.type); if(p.type == "0") p.type = "http"; QDomElement pset = e.elementsByTagName("proxySettings").item(0).toElement(); if(!pset.isNull()) p.settings.fromXml(pset); proxyMigration.append(p); } } // assign storage IDs to proxies and update accounts for (int i=0; i < proxyMigration.size(); i++) { proxyMigration[i].id = "a"+QString::number(i); } for (int i=0; i < accMigration.size(); i++) { if (accMigration[i].proxy_index != 0) { accMigration[i].proxyID = proxyMigration[accMigration[i].proxy_index-1].id; } } PsiOptions::instance()->setOption("options.ui.contactlist.show.offline-contacts", true); PsiOptions::instance()->setOption("options.ui.contactlist.show.away-contacts", true); PsiOptions::instance()->setOption("options.ui.contactlist.show.hidden-contacts-group", true); PsiOptions::instance()->setOption("options.ui.contactlist.show.agent-contacts", true); PsiOptions::instance()->setOption("options.ui.contactlist.show.self-contact", true); for (int i=0; i < accMigration.size(); i++) { if (!accMigration[i].opt_enabled) continue; PsiOptions::instance()->setOption("options.ui.contactlist.show.offline-contacts", accMigration[i].tog_offline); PsiOptions::instance()->setOption("options.ui.contactlist.show.away-contacts", accMigration[i].tog_away); PsiOptions::instance()->setOption("options.ui.contactlist.show.hidden-contacts-group", accMigration[i].tog_hidden); PsiOptions::instance()->setOption("options.ui.contactlist.show.agent-contacts", accMigration[i].tog_agents); PsiOptions::instance()->setOption("options.ui.contactlist.show.self-contact", accMigration[i].tog_self); break; } QDomElement p = findSubTag(base, "preferences", &found); if(found) { bool found; QDomElement p_general = findSubTag(p, "general", &found); if(found) { bool found; QDomElement p_roster = findSubTag(p_general, "roster", &found); if(found) { migrateBoolEntry(p_roster, "useleft", "options.ui.contactlist.use-left-click"); migrateBoolEntry(p_roster, "singleclick", "options.ui.contactlist.use-single-click"); bool hideMenu; readBoolEntry(p_roster, "hideMenubar", &hideMenu); PsiOptions::instance()->setOption("options.ui.contactlist.show-menubar", !hideMenu); int defaultAction; readNumEntry(p_roster, "defaultAction", &defaultAction); PsiOptions::instance()->setOption("options.messages.default-outgoing-message-type", defaultAction == 0 ? "message" : "chat"); migrateBoolEntry(p_roster, "useTransportIconsForContacts", "options.ui.contactlist.use-transport-icons"); QDomElement sorting = findSubTag(p_roster, "sortStyle", &found); if(found) { QString name; migrateStringEntry(sorting, "contact", "options.ui.contactlist.contact-sort-style"); migrateStringEntry(sorting, "group", "options.ui.contactlist.group-sort-style"); migrateStringEntry(sorting, "account", "options.ui.contactlist.account-sort-style"); /* FIXME readEntry(sorting, "contact", &name); if ( name == "alpha" ) lateMigrationData.rosterContactSortStyle = Options::ContactSortStyle_Alpha; else lateMigrationData.rosterContactSortStyle = Options::ContactSortStyle_Status; readEntry(sorting, "group", &name); if ( name == "rank" ) lateMigrationData.rosterGroupSortStyle = Options::GroupSortStyle_Rank; else lateMigrationData.rosterGroupSortStyle = Options::GroupSortStyle_Alpha; readEntry(sorting, "account", &name); if ( name == "rank" ) lateMigrationData.rosterAccountSortStyle = Options::AccountSortStyle_Rank; else lateMigrationData.rosterAccountSortStyle = Options::AccountSortStyle_Alpha; */ } } QDomElement tag = findSubTag(p_general, "misc", &found); if(found) { int delafterint; readNumEntry(tag, "delChats", &delafterint); QString delafter; switch (delafterint) { case 0: delafter = "instant"; break; case 1: delafter = "hour"; break; case 2: delafter = "day"; break; case 3: delafter = "never"; break; } PsiOptions::instance()->setOption("options.ui.chat.delete-contents-after", delafter); migrateBoolEntry(tag, "alwaysOnTop", "options.ui.contactlist.always-on-top"); migrateBoolEntry(tag, "keepSizes", "options.ui.remember-window-sizes"); migrateBoolEntry(tag, "ignoreHeadline", "options.messages.ignore-headlines"); migrateBoolEntry(tag, "ignoreNonRoster", "options.messages.ignore-non-roster-contacts"); migrateBoolEntry(tag, "excludeGroupChatIgnore", "options.messages.exclude-muc-from-ignore"); migrateBoolEntry(tag, "scrollTo", "options.ui.contactlist.ensure-contact-visible-on-event"); migrateBoolEntry(tag, "useEmoticons", "options.ui.emoticons.use-emoticons"); migrateBoolEntry(tag, "alertOpenChats", "options.ui.chat.alert-for-already-open-chats"); migrateBoolEntry(tag, "raiseChatWindow", "options.ui.chat.raise-chat-windows-on-new-messages"); migrateBoolEntry(tag, "showSubjects", "options.ui.message.show-subjects"); migrateBoolEntry(tag, "showGroupCounts", "options.ui.contactlist.show-group-counts"); migrateBoolEntry(tag, "showCounter", "options.ui.message.show-character-count"); migrateBoolEntry(tag, "chatSays", "options.ui.chat.use-chat-says-style"); migrateBoolEntry(tag, "jidComplete", "options.ui.message.use-jid-auto-completion"); migrateBoolEntry(tag, "grabUrls", "options.ui.message.auto-grab-urls-from-clipboard"); migrateBoolEntry(tag, "smallChats", "options.ui.chat.use-small-chats"); migrateBoolEntry(tag, "brushedMetal", "options.ui.mac.use-brushed-metal-windows"); migrateBoolEntry(tag, "chatLineEdit", "options.ui.chat.use-expanding-line-edit"); migrateBoolEntry(tag, "useTabs", "options.ui.tabs.use-tabs"); migrateBoolEntry(tag, "putTabsAtBottom", "options.ui.tabs.put-tabs-at-bottom"); migrateBoolEntry(tag, "autoRosterSize", "options.ui.contactlist.automatically-resize-roster"); migrateBoolEntry(tag, "autoRosterSizeGrowTop", "options.ui.contactlist.grow-roster-upwards"); migrateBoolEntry(tag, "autoResolveNicksOnAdd", "options.contactlist.resolve-nicks-on-contact-add"); migrateBoolEntry(tag, "messageEvents", "options.messages.send-composing-events"); migrateBoolEntry(tag, "inactiveEvents", "options.messages.send-inactivity-events"); migrateStringEntry(tag, "lastPath", "options.ui.last-used-open-path"); migrateStringEntry(tag, "lastSavePath", "options.ui.last-used-save-path"); migrateBoolEntry(tag, "autoCopy", "options.ui.automatically-copy-selected-text"); migrateBoolEntry(tag, "useCaps", "options.service-discovery.enable-entity-capabilities"); migrateBoolEntry(tag, "rc", "options.external-control.adhoc-remote-control.enable"); // Migrating for soft return option bool found; findSubTag(tag, "chatSoftReturn", &found); if (found) { bool soft; readBoolEntry(tag, "chatSoftReturn", &soft); QVariantList vl; if (soft) vl << qVariantFromValue(QKeySequence(Qt::Key_Enter)) << qVariantFromValue(QKeySequence(Qt::Key_Return)); else vl << qVariantFromValue(QKeySequence(Qt::Key_Enter+Qt::CTRL)) << qVariantFromValue(QKeySequence(Qt::CTRL+Qt::Key_Return)); PsiOptions::instance()->setOption("options.shortcuts.chat.send",vl); } } tag = findSubTag(p_general, "dock", &found); if(found) { migrateBoolEntry(tag, "useDock", "options.ui.systemtray.enable"); migrateBoolEntry(tag, "dockDCstyle", "options.ui.systemtray.use-double-click"); migrateBoolEntry(tag, "dockHideMW", "options.contactlist.hide-on-start"); migrateBoolEntry(tag, "dockToolMW", "options.contactlist.use-toolwindow"); } /*tag = findSubTag(p_general, "security", &found); if(found) { readEntry(tag, "pgp", &prefs.pgp); }*/ } QDomElement p_events = findSubTag(p, "events", &found); if(found) { bool found; int alertstyle; readNumEntry(p_events, "alertstyle", &alertstyle); QString ase[3] = {"no", "blink", "animate"}; PsiOptions::instance()->setOption("options.ui.notifications.alert-style", ase[alertstyle]); migrateBoolEntry(p_events, "autoAuth", "options.subscriptions.automatically-allow-authorization"); migrateBoolEntry(p_events, "notifyAuth", "options.ui.notifications.successful-subscription"); QDomElement tag = findSubTag(p_events, "receive", &found); if(found) { migrateBoolEntry(tag, "popupMsgs", "options.ui.message.auto-popup"); migrateBoolEntry(tag, "popupChats", "options.ui.chat.auto-popup"); migrateBoolEntry(tag, "popupHeadlines", "options.ui.message.auto-popup-headlines"); migrateBoolEntry(tag, "popupFiles", "options.ui.file-transfer.auto-popup"); migrateBoolEntry(tag, "noAwayPopup", "options.ui.notifications.popup-dialogs.suppress-while-away"); migrateBoolEntry(tag, "noUnlistedPopup", "options.ui.notifications.popup-dialogs.suppress-when-not-on-roster"); migrateBoolEntry(tag, "raise", "options.ui.contactlist.raise-on-new-event"); int force; readNumEntry(tag, "incomingAs", &force); QString fe[4] = {"no", "message", "chat", "current-open"}; PsiOptions::instance()->setOption("options.messages.force-incoming-message-type", fe[force]); } } QDomElement p_pres = findSubTag(p, "presence", &found); if(found) { bool found; QDomElement tag = findSubTag(p_pres, "misc", &found); if(found) { migrateBoolEntry(tag, "askOnline", "options.status.ask-for-message-on-online"); migrateBoolEntry(tag, "askOffline", "options.status.ask-for-message-on-offline"); migrateBoolEntry(tag, "rosterAnim", "options.ui.contactlist.use-status-change-animation"); migrateBoolEntry(tag, "autoVCardOnLogin", "options.vcard.query-own-vcard-on-login"); migrateBoolEntry(tag, "xmlConsoleOnLogin", "options.xml-console.enable-at-login"); } tag = findSubTag(p_pres, "autostatus", &found); if(found) { bool found; bool use; QDomElement e; e = findSubTag(tag, "away", &found); if(found) { if(e.hasAttribute("use")) { readBoolAttribute(e, "use", &use); PsiOptions::instance()->setOption("options.status.auto-away.use-away", use); } } e = findSubTag(tag, "xa", &found); if(found) { if(e.hasAttribute("use")) readBoolAttribute(e, "use", &use); PsiOptions::instance()->setOption("options.status.auto-away.use-not-availible", use); } e = findSubTag(tag, "offline", &found); if(found) { if(e.hasAttribute("use")) readBoolAttribute(e, "use", &use); PsiOptions::instance()->setOption("options.status.auto-away.use-offline", use); } migrateIntEntry(tag, "away", "options.status.auto-away.away-after"); migrateIntEntry(tag, "xa", "options.status.auto-away.not-availible-after"); migrateIntEntry(tag, "offline", "options.status.auto-away.offline-after"); migrateStringEntry(tag, "message", "options.status.auto-away.message"); } tag = findSubTag(p_pres, "statuspresets", &found); if(found) { lateMigrationData.sp.clear(); for(QDomNode n = tag.firstChild(); !n.isNull(); n = n.nextSibling()) { StatusPreset preset(n.toElement()); if (!preset.name().isEmpty()) lateMigrationData.sp[preset.name()] = preset; } } } QDomElement p_lnf = findSubTag(p, "lookandfeel", &found); if(found) { bool found; migrateBoolEntry(p_lnf, "newHeadings", "options.ui.look.contactlist.use-slim-group-headings"); migrateBoolEntry(p_lnf, "outline-headings", "options.ui.look.contactlist.use-outlined-group-headings"); migrateIntEntry(p_lnf, "chat-opacity", "options.ui.chat.opacity"); migrateIntEntry(p_lnf, "roster-opacity", "options.ui.contactlist.opacity"); QDomElement tag = findSubTag(p_lnf, "colors", &found); if(found) { migrateColorEntry(tag, "online", "options.ui.look.colors.contactlist.status.online"); migrateColorEntry(tag, "listback", "options.ui.look.colors.contactlist.background"); migrateColorEntry(tag, "away", "options.ui.look.colors.contactlist.status.away"); migrateColorEntry(tag, "dnd", "options.ui.look.colors.contactlist.status.do-not-disturb"); migrateColorEntry(tag, "offline", "options.ui.look.colors.contactlist.status.offline"); migrateColorEntry(tag, "status", "options.ui.look.colors.contactlist.status-messages"); migrateColorEntry(tag, "groupfore", "options.ui.look.colors.contactlist.grouping.header-foreground"); migrateColorEntry(tag, "groupback", "options.ui.look.colors.contactlist.grouping.header-background"); migrateColorEntry(tag, "profilefore", "options.ui.look.colors.contactlist.profile.header-foreground"); migrateColorEntry(tag, "profileback", "options.ui.look.colors.contactlist.profile.header-background"); migrateColorEntry(tag, "animfront", "options.ui.look.contactlist.status-change-animation.color1"); migrateColorEntry(tag, "animback", "options.ui.look.contactlist.status-change-animation.color2"); } tag = findSubTag(p_lnf, "fonts", &found); if(found) { migrateStringEntry(tag, "roster", "options.ui.look.font.contactlist"); migrateStringEntry(tag, "message", "options.ui.look.font.message"); migrateStringEntry(tag, "chat", "options.ui.look.font.chat"); migrateStringEntry(tag, "popup", "options.ui.look.font.passive-popup"); } } QDomElement p_sound = findSubTag(p, "sound", &found); if(found) { bool found; QString oldplayer; readEntry(p_sound, "player", &oldplayer); // psi now auto detects "play" or "aplay" // force auto detection on for old default and simple case of aplay on // alsa enabled systems. if (oldplayer != soundDetectPlayer() && oldplayer != "play") { PsiOptions::instance()->setOption("options.ui.notifications.sounds.unix-sound-player", oldplayer); } else { PsiOptions::instance()->setOption("options.ui.notifications.sounds.unix-sound-player", ""); } migrateBoolEntry(p_sound, "noawaysound", "options.ui.notifications.sounds.silent-while-away"); bool noGCSound; readBoolEntry(p_sound, "noGCSound", &noGCSound); PsiOptions::instance()->setOption("options.ui.notifications.sounds.notify-every-muc-message", !noGCSound); QDomElement tag = findSubTag(p_sound, "onevent", &found); if(found) { migrateStringEntry(tag, "message", "options.ui.notifications.sounds.incoming-message"); migrateStringEntry(tag, "chat1", "options.ui.notifications.sounds.new-chat"); migrateStringEntry(tag, "chat2", "options.ui.notifications.sounds.chat-message"); migrateStringEntry(tag, "system", "options.ui.notifications.sounds.system-message"); migrateStringEntry(tag, "headline", "options.ui.notifications.sounds.incoming-headline"); migrateStringEntry(tag, "online", "options.ui.notifications.sounds.contact-online"); migrateStringEntry(tag, "offline", "options.ui.notifications.sounds.contact-offline"); migrateStringEntry(tag, "send", "options.ui.notifications.sounds.outgoing-chat"); migrateStringEntry(tag, "incoming_ft", "options.ui.notifications.sounds.incoming-file-transfer"); migrateStringEntry(tag, "ft_complete", "options.ui.notifications.sounds.completed-file-transfer"); } } QDomElement p_sizes = findSubTag(p, "sizes", &found); if(found) { migrateSizeEntry(p_sizes, "eventdlg", "options.ui.message.size"); migrateSizeEntry(p_sizes, "chatdlg", "options.ui.chat.size"); migrateSizeEntry(p_sizes, "tabdlg", "options.ui.tabs.size"); } QDomElement p_toolbars = findSubTag(p, "toolbars", &found); if (found) { QStringList goodTags; goodTags << "toolbar"; goodTags << "mainWin"; bool mainWinCleared = false; bool oldStyle = true; for(QDomNode n = p_toolbars.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if( e.isNull() ) continue; QString tbGroup; bool isGood = false; QStringList::Iterator it = goodTags.begin(); for ( ; it != goodTags.end(); ++it ) { if ( e.tagName().left( (*it).length() ) == *it ) { isGood = true; if ( e.tagName().left(7) == "toolbar" ) tbGroup = "mainWin"; else { tbGroup = *it; oldStyle = false; } break; } } if ( isGood ) { if ( tbGroup != "mainWin" || !mainWinCleared ) { lateMigrationData.toolbars[tbGroup].clear(); if ( tbGroup == "mainWin" ) mainWinCleared = true; } if ( oldStyle ) { ToolbarPrefs tb = loadToolbarData( e ); lateMigrationData.toolbars[tbGroup].append(tb); } else { for(QDomNode nn = e.firstChild(); !nn.isNull(); nn = nn.nextSibling()) { QDomElement ee = nn.toElement(); if( ee.isNull() ) continue; if ( ee.tagName() == "toolbar" ) { ToolbarPrefs tb = loadToolbarData( ee ); lateMigrationData.toolbars[tbGroup].append(tb); } } } } } // event notifier in these versions was not implemented as an action, so add it if ( progver == "0.9" || progver == "0.9-CVS" ) { // at first, we need to scan the options, to determine, whether event_notifier already available bool found = false; QList<ToolbarPrefs>::Iterator it = lateMigrationData.toolbars["mainWin"].begin(); for ( ; it != lateMigrationData.toolbars["mainWin"].end(); ++it) { QStringList::Iterator it2 = (*it).keys.begin(); for ( ; it2 != (*it).keys.end(); ++it2) { if ( *it2 == "event_notifier" ) { found = true; break; } } } if ( !found ) { ToolbarPrefs tb; tb.name = QObject::tr("Event notifier"); tb.on = false; tb.locked = true; // tb.stretchable = true; tb.keys << "event_notifier"; tb.dock = Qt3Dock_Bottom; // tb.index = 0; lateMigrationData.toolbars["mainWin"].append(tb); } } } //group chat QDomElement p_groupchat = findSubTag(p, "groupchat", &found); if (found) { migrateBoolEntry(p_groupchat, "nickcoloring", "options.ui.muc.use-nick-coloring"); migrateBoolEntry(p_groupchat, "highlighting", "options.ui.muc.use-highlighting"); migrateStringList(p_groupchat, "highlightwords", "options.ui.muc.highlight-words"); migrateStringList(p_groupchat, "nickcolors", "options.ui.look.colors.muc.nick-colors"); } // Bouncing dock icon (Mac OS X) QDomElement p_dock = findSubTag(p, "dock", &found); if(found) { PsiOptions::instance()->setOption("options.ui.notifications.bounce-dock", p_dock.attribute("bounce")); /* FIXME convert back to some modern enum? if (p_dock.attribute("bounce") == "once") { lateMigrationData.bounceDock = Options::BounceOnce; } else if (p_dock.attribute("bounce") == "forever") { lateMigrationData.bounceDock = Options::BounceForever; } else if (p_dock.attribute("bounce") == "never") { lateMigrationData.bounceDock = Options::NoBounce; }*/ } QDomElement p_popup = findSubTag(p, "popups", &found); if(found) { migrateBoolEntry(p_popup, "on", "options.ui.notifications.passive-popups.enabled"); migrateBoolEntry(p_popup, "online", "options.ui.notifications.passive-popups.status.online"); migrateBoolEntry(p_popup, "offline", "options.ui.notifications.passive-popups.status.offline"); migrateBoolEntry(p_popup, "statusChange", "options.ui.notifications.passive-popups.status.other-changes"); migrateBoolEntry(p_popup, "message", "options.ui.notifications.passive-popups.incoming-message"); migrateBoolEntry(p_popup, "chat", "options.ui.notifications.passive-popups.incoming-chat"); migrateBoolEntry(p_popup, "headline", "options.ui.notifications.passive-popups.incoming-headline"); migrateBoolEntry(p_popup, "file", "options.ui.notifications.passive-popups.incoming-file-transfer"); migrateIntEntry(p_popup, "jidClip", "options.ui.notifications.passive-popups.maximum-jid-length"); migrateIntEntry(p_popup, "statusClip", "options.ui.notifications.passive-popups.maximum-status-length"); migrateIntEntry(p_popup, "textClip", "options.ui.notifications.passive-popups.maximum-text-length"); migrateIntEntry(p_popup, "hideTime", "options.ui.notifications.passive-popups.duration"); migrateColorEntry(p_popup, "borderColor", "options.ui.look.colors.passive-popup.border"); } QDomElement p_lockdown = findSubTag(p, "lockdown", &found); if(found) { migrateBoolEntry(p_lockdown, "roster", "options.ui.contactlist.lockdown-roster"); migrateBoolEntry(p_lockdown, "services", "options.ui.contactlist.disable-service-discovery"); } QDomElement p_iconset = findSubTag(p, "iconset", &found); if(found) { migrateStringEntry(p_iconset, "system", "options.iconsets.system"); QDomElement roster = findSubTag(p_iconset, "roster", &found); if (found) { migrateStringEntry(roster, "default", "options.iconsets.status"); QDomElement service = findSubTag(roster, "service", &found); if (found) { lateMigrationData.serviceRosterIconset.clear(); for (QDomNode n = service.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if ( i.isNull() ) continue; lateMigrationData.serviceRosterIconset[i.attribute("service")] = i.attribute("iconset"); } } QDomElement custom = findSubTag(roster, "custom", &found); if (found) { lateMigrationData.customRosterIconset.clear(); for (QDomNode n = custom.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if ( i.isNull() ) continue; lateMigrationData.customRosterIconset[i.attribute("regExp")] = i.attribute("iconset"); } } } QDomElement emoticons = findSubTag(p_iconset, "emoticons", &found); if (found) { QStringList emoticons_list; for (QDomNode n = emoticons.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if ( i.isNull() ) continue; if ( i.tagName() == "item" ) { QString is = i.text(); emoticons_list << is; } } PsiOptions::instance()->setOption("options.iconsets.emoticons", emoticons_list); } } QDomElement p_tip = findSubTag(p, "tipOfTheDay", &found); if (found) { migrateIntEntry(p_tip, "num", "options.ui.tip.number"); migrateBoolEntry(p_tip, "show", "options.ui.tip.show"); } QDomElement p_disco = findSubTag(p, "disco", &found); if (found) { migrateBoolEntry(p_disco, "items", "options.ui.service-discovery.automatically-get-items"); migrateBoolEntry(p_disco, "info", "options.ui.service-discovery.automatically-get-info"); } QDomElement p_dt = findSubTag(p, "dt", &found); if (found) { migrateIntEntry(p_dt, "port", "options.p2p.bytestreams.listen-port"); migrateStringEntry(p_dt, "external", "options.p2p.bytestreams.external-address"); } QDomElement p_globalAccel = findSubTag(p, "globalAccel", &found); if (found) { for (QDomNode n = p_globalAccel.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if ( i.isNull() ) continue; if ( i.tagName() == "command" && i.hasAttribute("type") ) { QVariant k = qVariantFromValue(QKeySequence(i.text())); QString shortcut; if (i.attribute("type") == "processNextEvent") shortcut = "event"; else shortcut = "toggle-visibility"; PsiOptions::instance()->setOption(QString("options.shortcuts.global.") + shortcut, k); } } } QDomElement p_advWidget = findSubTag(p, "advancedWidget", &found); if (found) { QDomElement stick = findSubTag(p_advWidget, "sticky", &found); if (found) { bool enabled, toWindows; int offs; readBoolAttribute(stick, "enabled", &enabled); readNumEntry(stick, "offset", &offs); readBoolEntry(stick, "stickToWindows", &toWindows); GAdvancedWidget::setStickEnabled( enabled ); GAdvancedWidget::setStickAt( offs ); GAdvancedWidget::setStickToWindows( toWindows ); } } } return true; } void OptionsMigration::lateMigration() { foreach(QString opt, PsiOptions::instance()->allOptionNames()) { if (opt.startsWith("options.status.presets.") || opt.startsWith("options.iconsets.service-status.") || opt.startsWith("options.iconsets.custom-status.")) { return; } } PsiOptions *o = PsiOptions::instance(); // QMap<QString, QString> serviceRosterIconset; QMapIterator<QString, QString> iSRI(lateMigrationData.serviceRosterIconset); while (iSRI.hasNext()) { iSRI.next(); QString base = o->mapPut("options.iconsets.service-status", iSRI.key()); o->setOption(base + ".iconset", iSRI.value()); } // QMap<QString, QString> customRosterIconset; int idx = 0; QMapIterator<QString, QString> iCRI(lateMigrationData.customRosterIconset); while (iCRI.hasNext()) { iCRI.next(); QString base = "options.iconsets.custom-status" ".a" + QString::number(idx++); o->setOption(base + ".regexp", iCRI.key()); o->setOption(base + ".iconset", iCRI.value()); } // QMap<QString,StatusPreset> sp; // Status message presets. foreach(StatusPreset sp, lateMigrationData.sp) { sp.toOptions(o); } // QMap< QString, QList<ToolbarPrefs> > toolbars; QList<ToolbarPrefs> toolbars; if(qVersionInt() >= 0x040300) { toolbars = lateMigrationData.toolbars["mainWin"]; } else { foreach(ToolbarPrefs tb, lateMigrationData.toolbars["mainWin"]) { toolbars.insert(0, tb); } } foreach(ToolbarPrefs tb, toolbars) { PsiToolBar::structToOptions(o, tb); } } QString pathToProfile(const QString &name) { return ApplicationInfo::profilesDir() + "/" + name; } QString pathToProfileConfig(const QString &name) { return pathToProfile(name) + "/config.xml"; } QStringList getProfilesList() { QStringList list; QDir d(ApplicationInfo::profilesDir()); if(!d.exists()) return list; QStringList entries = d.entryList(); for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { if(*it == "." || *it == "..") continue; QFileInfo info(d, *it); if(!info.isDir()) continue; list.append(*it); } list.sort(); return list; } bool profileExists(const QString &_name) { QString name = _name.toLower(); QStringList list = getProfilesList(); for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { if((*it).toLower() == name) return true; } return false; } bool profileNew(const QString &name) { if(name.isEmpty()) return false; // verify the string is sane for(int n = 0; n < (int)name.length(); ++n) { if(!name.at(n).isLetterOrNumber()) return false; } // make it QDir d(ApplicationInfo::profilesDir()); if(!d.exists()) return false; QDir p(ApplicationInfo::profilesDir() + "/" + name); if(!p.exists()) { if (!d.mkdir(name)) return false; } p.mkdir("history"); p.mkdir("vcard"); return true; } bool profileRename(const QString &oldname, const QString &name) { // verify the string is sane for(int n = 0; n < (int)name.length(); ++n) { if(!name.at(n).isLetterOrNumber()) return false; } // locate the folder QDir d(ApplicationInfo::profilesDir()); if(!d.exists()) return false; if(!d.rename(oldname, name)) return false; return true; } static bool folderRemove(const QDir &_d) { QDir d = _d; QStringList entries = d.entryList(); for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { if(*it == "." || *it == "..") continue; QFileInfo info(d, *it); if(info.isDir()) { if(!folderRemove(QDir(info.filePath()))) return false; } else { //printf("deleting [%s]\n", info.filePath().latin1()); d.remove(info.fileName()); } } QString name = d.dirName(); if(!d.cdUp()) return false; //printf("removing folder [%s]\n", d.filePath(name).latin1()); d.rmdir(name); return true; } bool profileDelete(const QString &path) { QDir d(path); if(!d.exists()) return true; return folderRemove(QDir(path)); } QString activeProfile; ����������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/���������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�013365� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/SparkleAutoUpdater.mm������������������������������������������������������0000644�0001750�0001750�00000001266�11305557613�017504� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #include "SparkleAutoUpdater.h" #include <Cocoa/Cocoa.h> #include <Sparkle/Sparkle.h> class SparkleAutoUpdater::Private { public: SUUpdater* updater; }; SparkleAutoUpdater::SparkleAutoUpdater(const QString& aUrl) { d = new Private; d->updater = [SUUpdater sharedUpdater]; [d->updater retain]; NSURL* url = [NSURL URLWithString: [NSString stringWithUTF8String: aUrl.toUtf8().data()]]; [d->updater setFeedURL: url]; } SparkleAutoUpdater::~SparkleAutoUpdater() { [d->updater release]; delete d; } void SparkleAutoUpdater::checkForUpdates() { [d->updater checkForUpdatesInBackground]; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/AutoUpdater.pri������������������������������������������������������������0000644�0001750�0001750�00000000404�11305557613�016334� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INCLUDEPATH *= $$PWD/.. DEPENDPATH *= $$PWD/.. HEADERS += \ $$PWD/AutoUpdater.h SOURCES += \ $$PWD/AutoUpdater.cpp Sparkle { HEADERS += \ $$PWD/SparkleAutoUpdater.h OBJECTIVE_SOURCES += \ $$PWD/SparkleAutoUpdater.mm LIBS += -framework Sparkle } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/AutoUpdater.cpp������������������������������������������������������������0000644�0001750�0001750�00000000224�11305557613�016324� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #include "AutoUpdater.h" AutoUpdater::~AutoUpdater() { } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/�������������������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�015051� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/guitest.pro��������������������������������������������������������0000644�0001750�0001750�00000000067�11305557613�017262� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = subdirs SUBDIRS = \ testapp-2.0 \ testapp �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/testapp-2.0/�������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�017026� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/testapp-2.0/testapp-2.0.pro����������������������������������������0000644�0001750�0001750�00000000150�11305557613�021521� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = app TARGET = testapp SOURCES = main.cpp QMAKE_POST_LINK = zip -r testapp-2.0.zip testapp.app ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/testapp-2.0/main.cpp�����������������������������������������������0000644�0001750�0001750�00000000275�11305557613�020462� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <QApplication> #include <QLabel> int main(int argc, char* argv[]) { QApplication app(argc, argv); QLabel l("This is AutoUpdater Test App 2.0"); l.show(); return app.exec(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/testapp/�����������������������������������������������������������0000755�0001750�0001750�00000000000�11305557613�016531� 5����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/testapp/testapp.pro������������������������������������������������0000644�0001750�0001750�00000000340�11305557613�020730� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = app QT += network CONFIG += debug CONFIG += Sparkle include(../../AutoUpdater.pri) include(../../../CocoaUtilities/CocoaUtilities.pri) SOURCES += main.cpp QMAKE_INFO_PLIST = Info.plist RESOURCES += testapp.qrc ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������psi-0.14/src/AutoUpdater/guitest/testapp/main.cpp���������������������������������������������������0000644�0001750�0001750�00000012605�11305557613�020165� 0����������������������������������������������������������������������������������������������������ustar �jan�����������������������������jan��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #include <QApplication> #include <QDir> #include <QWidget> #include <QPushButton> #include <QTcpServer> #include <QTcpSocket> #include <QVBoxLayout> #include <QFile> #include "AutoUpdater/AutoUpdater.h" #include "AutoUpdater/SparkleAutoUpdater.h" #include "CocoaUtilities/CocoaInitializer.h" class SimpleHTTPServer : public QObject { Q_OBJECT public: SimpleHTTPServer(int port = 0) { tcpServer_ = new QTcpServer(this); if (!tcpServer_->listen(QHostAddress::Any, port)) { Q_ASSERT(false); } connect(tcpServer_, SIGNAL(newConnection()), this, SLOT(incomingConnection())); }; ~SimpleHTTPServer() { delete tcpServer_; } unsigned int getPort() { return tcpServer_->serverPort(); } void setPage(const QString& url, const QByteArray& content) { pages_[url] = content; } public slots: void incomingConnection() { QTcpSocket* socket = tcpServer_->nextPendingConnection(); connect(socket, SIGNAL(readyRead()), SLOT(readBytes())); } void readBytes() { QTcpSocket* socket = static_cast<QTcpSocket*>(sender()); QByteArray data = socket->readAll(); // FIXME: Only do this for the initial request. // Wait for the request to finish QList<QByteArray> tokens = data.split(' '); if (tokens[0] == QString("GET")) { if (!pages_.contains(tokens[1])) { socket->write("HTTP/1.1 404 Not Found\n\n"); Q_ASSERT(false); } QByteArray responseData = pages_[tokens[1]]; QString response; response += "HTTP/1.1 200 OK\n"; if (tokens[1].endsWith(".html")) { response += "Content-Type: text/html\n"; } if (tokens[1].endsWith(".xml")) { response += "Content-Type: application/xml\n"; } else { response += "Content-Type: text/plain\n"; } response += "Content-Length: " + QString::number(responseData.size()) + "\n"; response += "\n"; socket->write(response.toUtf8()); socket->write(responseData); } } private: QTcpServer *tcpServer_; QMap<QString,QByteArray> pages_; }; class UpdaterWidget : public QWidget { Q_OBJECT public: UpdaterWidget() { QFile(QDir::homePath() + "/Library/Preferences/org.psi-im.autoupdater-test.plist").remove(); QVBoxLayout* layout = new QVBoxLayout(this); QPushButton* newButton = new QPushButton("Check with new release", this); connect(newButton, SIGNAL(clicked()), this, SLOT(doCheckWithNew())); layout->addWidget(newButton); QPushButton* noNewButton = new QPushButton("Check without new release", this); connect(noNewButton, SIGNAL(clicked()), this, SLOT(doCheckWithoutNew())); layout->addWidget(noNewButton); server_ = new SimpleHTTPServer(); QString baseURL = "http://localhost:" + QString::number(server_->getPort()); appCastURL_ = baseURL + "/appcast.xml"; releaseNotesURL_ = baseURL + "/releasenotes.html"; releaseURL_ = baseURL + "/testapp-2.0.zip"; QString releaseNotes = "<html><body><h2>My release notes</h2><ul><li>note 1</li><li>note 2</li></body></html>"; server_->setPage("/releasenotes.html", releaseNotes.toUtf8()); QFile app(":testapp-2.0.zip"); app.open(QIODevice::ReadOnly); server_->setPage("/testapp-2.0.zip", app.readAll()); app.close(); updater_ = new SparkleAutoUpdater(appCastURL_); } ~UpdaterWidget() { delete updater_; delete server_; } QByteArray createAppCast(bool withNewVersion = false) { QString appcast; appcast += "<?xml version=\"1.0\" encoding=\"utf-8\"?>"; appcast += "<rss version=\"2.0\" xmlns:sparkle=\"http://www.andymatuschak.org/xml-namespaces/sparkle\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">"; appcast += " <channel>"; appcast += " <title>Your Great App's Changelog"; appcast += " " + appCastURL_ + ""; appcast += " Most recent changes with links to updates."; if (withNewVersion) { appcast += " "; appcast += " Version 2.0 (2 bugs fixed; 3 new features)"; appcast += " " + releaseNotesURL_ + ""; appcast += " Wed, 09 Jan 2006 19:20:11 +0000"; appcast += " "; appcast += " "; } appcast += " "; appcast += " Version 1.0 (2 bugs fixed; 3 new features)"; appcast += " " + releaseNotesURL_ + ""; appcast += " Wed, 08 Jan 2006 19:20:11 +0000"; appcast += " "; appcast += " "; appcast += " "; appcast += ""; return appcast.toUtf8(); } public slots: void doCheckWithNew() { server_->setPage("/appcast.xml", createAppCast(true)); updater_->checkForUpdates(); } void doCheckWithoutNew() { server_->setPage("/appcast.xml", createAppCast(false)); updater_->checkForUpdates(); } private: AutoUpdater* updater_; SimpleHTTPServer* server_; QString appCastURL_, releaseNotesURL_, releaseURL_; }; int main(int argc, char* argv[]) { QApplication app(argc, argv); CocoaInitializer initializer; UpdaterWidget w; w.show(); app.exec(); return 0; } #include "main.moc" psi-0.14/src/AutoUpdater/guitest/testapp/Info.plist0000644000175000017500000000154711305557613020510 0ustar janjan CFBundleDevelopmentRegion English CFBundleExecutable sparkletestapp CFBundleGetInfoString Sparkle Test App CFBundleIdentifier org.psi-im.autoupdater-test CFBundleInfoDictionaryVersion 6.0 CFBundleName Sparkle Test App CFBundlePackageType APPL CFBundleShortVersionString SparkleTestApp 1.0 CFBundleSignature psi CFBundleVersion 1.0 CSResourcesFileMapped psi-0.14/src/AutoUpdater/guitest/testapp/testapp.qrc0000644000175000017500000000021311305557613020714 0ustar janjan ../testapp-2.0/testapp-2.0.zip psi-0.14/src/AutoUpdater/SparkleAutoUpdater.h0000644000175000017500000000063411305557613017320 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #ifndef SPARKLEAUTOUPDATER_H #define SPARKLEAUTOUPDATER_H #include #include "AutoUpdater/AutoUpdater.h" class SparkleAutoUpdater : public AutoUpdater { public: SparkleAutoUpdater(const QString& url); ~SparkleAutoUpdater(); void checkForUpdates(); private: class Private; Private* d; }; #endif psi-0.14/src/AutoUpdater/AutoUpdater.h0000644000175000017500000000036011305557613015772 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #ifndef AUTOUPDATER_H #define AUTOUPDATER_H class AutoUpdater { public: virtual ~AutoUpdater(); virtual void checkForUpdates() = 0; }; #endif psi-0.14/src/psioptions.h0000644000175000017500000000314511305557613013513 0ustar janjan/* * psioptions.h - Psi options class * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _PSIOPTIONS_H_ #define _PSIOPTIONS_H_ #include "optionstree.h" // Some hard coded options #define MINIMUM_OPACITY 10 namespace XMPP { class Client; } class QString; class QTimer; class PsiOptions : public OptionsTree//, QObject { Q_OBJECT public: static PsiOptions* instance(); static const PsiOptions* defaults(); static void reset(); static bool exists(QString fileName); ~PsiOptions(); bool load(QString file); void load(XMPP::Client* client); bool newProfile(); bool save(QString file); void autoSave(bool autoSave, QString autoFile = ""); // don't call this normally PsiOptions(); private slots: void saveToAutoFile(); void getOptionsStorage_finished(); private: QString autoFile_; QTimer *autoSaveTimer_; static PsiOptions* instance_; static PsiOptions* defaults_; }; #endif /* _PSIOPTIONS_H_ */ psi-0.14/src/capabilities/0000755000175000017500000000000011305557613013561 5ustar janjanpsi-0.14/src/capabilities/capabilities.pri0000644000175000017500000000031511305557613016725 0ustar janjanINCLUDEPATH *= $$PWD DEPENDPATH *= $$PWD HEADERS += \ $$PWD/capsspec.h \ $$PWD/capsregistry.h \ $$PWD/capsmanager.h SOURCES += \ $$PWD/capsspec.cpp \ $$PWD/capsregistry.cpp \ $$PWD/capsmanager.cpp psi-0.14/src/capabilities/capsregistry.cpp0000755000175000017500000001412211305557613017007 0ustar janjan/* * capsregistry.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include "xmpp_features.h" #include "capsregistry.h" #include "iodeviceopener.h" using namespace XMPP; // ----------------------------------------------------------------------------- CapsRegistry::CapsInfo::CapsInfo() { updateLastSeen(); } const XMPP::Features& CapsRegistry::CapsInfo::features() const { return features_; } const DiscoItem::Identities& CapsRegistry::CapsInfo::identities() const { return identities_; } void CapsRegistry::CapsInfo::setIdentities(const DiscoItem::Identities& i) { identities_ = i; } void CapsRegistry::CapsInfo::setFeatures(const XMPP::Features& f) { features_ = f; } void CapsRegistry::CapsInfo::updateLastSeen() { lastSeen_ = QDateTime::currentDateTime(); } QDomElement CapsRegistry::CapsInfo::toXml(QDomDocument *doc) const { QDomElement info = doc->createElement("info"); info.setAttribute("last-seen",lastSeen_.toString(Qt::ISODate)); // Identities for (DiscoItem::Identities::ConstIterator i = identities_.begin(); i != identities_.end(); ++i) { QDomElement identity = doc->createElement("identity"); identity.setAttribute("category",(*i).category); identity.setAttribute("name",(*i).name); identity.setAttribute("type",(*i).type); info.appendChild(identity); } // Features foreach(QString f, features_.list()) { QDomElement feature = doc->createElement("feature"); feature.setAttribute("node",f); info.appendChild(feature); } return info; } void CapsRegistry::CapsInfo::fromXml(const QDomElement& e) { if (e.tagName() != "info") { qWarning("caps.cpp: Invalid info element"); return; } if (!e.attribute("last-seen").isEmpty()) { QDateTime last = QDateTime::fromString(e.attribute("last-seen"),Qt::ISODate); if (last.isValid()) lastSeen_ = last; else qWarning("Invalid date in caps registry"); } for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) { qWarning("caps.cpp: Null element"); continue; } if(i.tagName() == "identity") { DiscoItem::Identity id; id.category = i.attribute("category"); id.name = i.attribute("name"); id.type = i.attribute("type"); identities_ += id; } else if (i.tagName() == "feature") { features_.addFeature(i.attribute("node")); } else { qWarning("caps.cpp: Unknown element"); } } } // ----------------------------------------------------------------------------- /** * \class CapsRegistry * \brief A singleton class managing the capabilities of clients. */ /** * \brief Default constructor. */ CapsRegistry::CapsRegistry() { } /** * \brief Convert all capabilities info to XML. */ void CapsRegistry::save(QIODevice& out) { // Generate XML QDomDocument doc; QDomElement capabilities = doc.createElement("capabilities"); doc.appendChild(capabilities); QMap::ConstIterator i = capsInfo_.begin(); for( ; i != capsInfo_.end(); i++) { QDomElement info = i.value().toXml(&doc); info.setAttribute("node",i.key().node()); info.setAttribute("ver",i.key().version()); info.setAttribute("ext",i.key().extensions()); capabilities.appendChild(info); } IODeviceOpener opener(&out, QIODevice::WriteOnly); if (!opener.isOpen()) { qWarning() << "Caps: Unable to open IO device"; return; } QTextStream t; t.setDevice(&out); t.setCodec(QTextCodec::codecForName("UTF-8")); t << doc.toString(); } /** * \brief Sets the file to save the capabilities info to */ void CapsRegistry::load(QIODevice& in) { // Load settings QDomDocument doc; IODeviceOpener opener(&in, QIODevice::ReadOnly); if (!opener.isOpen()) { qWarning() << "CapsRegistry: Cannot open input device"; return; } if (!doc.setContent(&in)) { qWarning() << "CapsRegistry: Cannnot parse input"; return; } QDomElement caps = doc.documentElement(); if (caps.tagName() != "capabilities") { qWarning("caps.cpp: Invalid capabilities element"); return; } for(QDomNode n = caps.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) { qWarning("capsregistry.cpp: Null element"); continue; } if(i.tagName() == "info") { CapsInfo info; info.fromXml(i); CapsSpec spec(i.attribute("node"),i.attribute("ver"),i.attribute("ext")); capsInfo_[spec] = info; //qDebug() << QString("Read %1 %2 %3").arg(spec.node()).arg(spec.version()).arg(spec.extensions()); } else { qWarning("capsregistry.cpp: Unknown element"); } } } /** * \brief Registers capabilities of a client. */ void CapsRegistry::registerCaps(const CapsSpec& spec,const XMPP::DiscoItem::Identities& identities,const XMPP::Features& features) { if (!isRegistered(spec)) { CapsInfo info; info.setIdentities(identities); info.setFeatures(features); capsInfo_[spec] = info; emit registered(spec); } } /** * \brief Checks if capabilities have been registered. */ bool CapsRegistry::isRegistered(const CapsSpec& spec) const { return capsInfo_.contains(spec); } /** * \brief Retrieves the features of a given caps spec. */ XMPP::Features CapsRegistry::features(const CapsSpec& spec) const { return capsInfo_[spec].features(); } /** * \brief Retrieves the identities of a given caps spec. */ XMPP::DiscoItem::Identities CapsRegistry::identities(const CapsSpec& spec) const { return capsInfo_[spec].identities(); } psi-0.14/src/capabilities/capsregistry.h0000755000175000017500000000402311305557613016453 0ustar janjan/* * capsregistry.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CAPSREGISTRY_H #define CAPSREGISTRY_H #include #include #include #include #include #include #include "xmpp_features.h" #include "xmpp_discoitem.h" #include "capsspec.h" class QDomDocument; class QDomElement; class CapsRegistry : public QObject { Q_OBJECT public: CapsRegistry(); void registerCaps(const CapsSpec&, const XMPP::DiscoItem::Identities&, const XMPP::Features& features); bool isRegistered(const CapsSpec&) const; XMPP::Features features(const CapsSpec&) const; XMPP::DiscoItem::Identities identities(const CapsSpec&) const; signals: void registered(const CapsSpec&); public slots: void load(QIODevice& target); void save(QIODevice& target); private: class CapsInfo { public: CapsInfo(); const XMPP::Features& features() const; const XMPP::DiscoItem::Identities& identities() const; void setIdentities(const XMPP::DiscoItem::Identities&); void setFeatures(const XMPP::Features&); QDomElement toXml(QDomDocument *) const; void fromXml(const QDomElement&); protected: void updateLastSeen(); private: XMPP::Features features_; XMPP::DiscoItem::Identities identities_; QDateTime lastSeen_; }; QMap capsInfo_; }; #endif psi-0.14/src/capabilities/capsmanager.cpp0000755000175000017500000002035111305557613016552 0ustar janjan/* * capsmanager.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // TODO: // - Fallback on another jid if a disco request should fail. This can be // done by keeping a second list of candidate jids to query // - Implement Server Optimization support (Section 5). // - Implement consistency checking (Section 8). #include #include #include #include #include #include "capsregistry.h" #include "capsmanager.h" //#define REQUEST_TIMEOUT 3000 using namespace XMPP; /** * \class CapsManager * \brief A class managing all the capabilities of JIDs and their * clients. */ /** * \brief Default constructor. */ CapsManager::CapsManager(const Jid& jid, CapsRegistry* registry, Protocol::DiscoInfoQuerier* discoInfoQuerier) : jid_(jid), registry_(registry), discoInfoQuerier_(discoInfoQuerier), isEnabled_(true) { connect(registry_,SIGNAL(registered(const CapsSpec&)),SLOT(capsRegistered(const CapsSpec&))); connect(discoInfoQuerier_, SIGNAL(getDiscoInfo_success(const XMPP::Jid&, const QString&, const XMPP::DiscoItem&)), SLOT(getDiscoInfo_success(const XMPP::Jid&, const QString&, const XMPP::DiscoItem&))); connect(discoInfoQuerier_, SIGNAL(getDiscoInfo_error(const XMPP::Jid&, const QString&, int, const QString&)), SLOT(getDiscoInfo_error(const XMPP::Jid&, const QString&, int, const QString&))); } CapsManager::~CapsManager() { delete discoInfoQuerier_; } /** * \brief Checks whether the caps manager is enabled (and does lookups). */ bool CapsManager::isEnabled() { return isEnabled_; } /** * \brief Enables or disables the caps manager. */ void CapsManager::setEnabled(bool b) { isEnabled_ = b; } /** * \brief Registers new incoming capabilities information of a JID. * If the features of the entity are unknown, discovery requests are sent to * retrieve the information. * * @param jid The entity's JID * @param node The entity's caps node * @param ver The entity's caps version * @param ext The entity's caps extensions */ void CapsManager::updateCaps(const Jid& jid, const QString& node, const QString& ver, const QString& ext) { if (jid.compare(jid_,false)) return; CapsSpec c(node,ver,ext); CapsSpecs caps = c.flatten(); if (capsSpecs_[jid.full()] != c) { //qDebug() << QString("caps.cpp: Updating caps for %1 (node=%2,ver=%3,ext=%4)").arg(QString(jid.full()).replace('%',"%%")).arg(node).arg(ver).arg(ext); // Unregister from all old caps nodes CapsSpecs old_caps = capsSpecs_[jid.full()].flatten(); foreach(CapsSpec s, old_caps) { if (s != CapsSpec()) { capsJids_[s].removeAll(jid.full()); } } if (!node.isEmpty() && !ver.isEmpty()) { // Register with all new caps nodes capsSpecs_[jid.full()] = c; foreach(CapsSpec s, caps) { if (!capsJids_[s].contains(jid.full())) { capsJids_[s].push_back(jid.full()); } } emit capsChanged(jid); // Register new caps and check if we need to discover features if (isEnabled()) { foreach(CapsSpec s, caps) { if (!registry_->isRegistered(s) && capsJids_[s].count() == 1) { //qDebug() << QString("caps.cpp: Sending disco request to %1, node=%2").arg(QString(jid.full()).replace('%',"%%")).arg(node + "#" + s.extensions()); discoInfoQuerier_->getDiscoInfo(jid,node + '#' + s.extensions()); } } } } else { // Remove all caps specifications qWarning() << QString("caps.cpp: Illegal caps info from %1: node=%2, ver=%3").arg(QString(jid.full()).replace('%',"%%")).arg(node).arg(ver); capsSpecs_.remove(jid.full()); } } else { // Add to the list of jids foreach(CapsSpec s, caps) { capsJids_[s].push_back(jid.full()); } } } /** * \brief Removes all feature information for a given JID. * * @param jid The entity's JID */ void CapsManager::disableCaps(const Jid& jid) { //qDebug() << QString("caps.cpp: Disabling caps for %1.").arg(QString(jid.full()).replace('%',"%%")); if (capsEnabled(jid)) { CapsSpecs cs = capsSpecs_[jid.full()].flatten(); foreach(CapsSpec s, cs) { if (s != CapsSpec()) { capsJids_[s].removeAll(jid.full()); } } capsSpecs_.remove(jid.full()); emit capsChanged(jid); } } /** * \brief Called when a reply to disco#info request was received. * If the result was succesful, the resulting features are recorded in the * features database for the requested node, and all the affected jids are * put in the queue for update notification. */ void CapsManager::getDiscoInfo_success(const XMPP::Jid& jid, const QString& node, const XMPP::DiscoItem& item) { //qDebug() << QString("caps.cpp: Disco response from %1, node=%2").arg(QString(jid.full()).replace('%',"%%")).arg(node); // Update features bool ok = false; CapsSpec cs(getCapsSpecForNode(jid, node, ok)); if (!ok) { return; } registry_->registerCaps(cs,item.identities(),item.features().list()); } void CapsManager::getDiscoInfo_error(const XMPP::Jid& jid, const QString& node, int, const QString&) { qWarning() << QString("capsmanager.cpp: Disco to '%1' at node '%2' failed.").arg(jid.full()).arg(node); } CapsSpec CapsManager::getCapsSpecForNode(const XMPP::Jid& jid, const QString& disco_node, bool& ok) const { int hash_index = disco_node.indexOf('#'); if (hash_index == -1) { qWarning() << "CapsManager: Node" << disco_node << "invalid"; ok = false; return CapsSpec(); } QString node = disco_node.left(hash_index); QString ext = disco_node.right(disco_node.length() - hash_index - 1); CapsSpec jid_cs = capsSpecs_[jid.full()]; if (jid_cs.node() == node) { ok = true; return CapsSpec(node,jid_cs.version(),ext); } else { ok = false; return CapsSpec(); } } /** * \brief This slot is called whenever capabilities of a client were discovered. * All jids with the corresponding client are updated. */ void CapsManager::capsRegistered(const CapsSpec& cs) { // Notify affected jids. foreach(QString s, capsJids_[cs]) { //qDebug() << QString("caps.cpp: Notifying %1.").arg(s.replace('%',"%%")); emit capsChanged(s); } } /** * \brief Checks whether a given JID is broadcastingn its entity capabilities. */ bool CapsManager::capsEnabled(const Jid& jid) const { return capsSpecs_.contains(jid.full()); } /** * \brief Requests the list of features of a given JID. */ XMPP::Features CapsManager::features(const Jid& jid) const { //qDebug() << "caps.cpp: Retrieving features of " << jid.full(); QStringList f; if (capsEnabled(jid)) { CapsSpecs cs = capsSpecs_[jid.full()].flatten(); foreach(CapsSpec s, cs) { //qDebug() << QString(" %1").arg(registry_->features(s).list().join("\n")); f += registry_->features(s).list(); } } return Features(f); } /** * \brief Returns the client name of a given jid. * \param jid the jid to retrieve the client name of */ QString CapsManager::clientName(const Jid& jid) const { if (capsEnabled(jid)) { QString name; CapsSpec cs = capsSpecs_[jid.full()]; const DiscoItem::Identities& i = registry_->identities(CapsSpec(cs.node(),cs.version(),cs.version())); if (i.count() > 0) { name = i.first().name; } // Try to be intelligent about the name if (name.isEmpty()) { name = cs.node(); if (name.startsWith("http://")) name = name.right(name.length() - 7); if (name.startsWith("www.")) name = name.right(name.length() - 4); int cut_pos = name.indexOf("/"); if (cut_pos != -1) name = name.left(cut_pos); } return name; } else { return QString(); } } /** * \brief Returns the client version of a given jid. */ QString CapsManager::clientVersion(const Jid& jid) const { return (capsEnabled(jid) ? capsSpecs_[jid.full()].version() : QString()); } psi-0.14/src/capabilities/capsmanager.h0000755000175000017500000000446411305557613016226 0ustar janjan/* * capsmanager.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CAPSMANAGER_H #define CAPSMANAGER_H #include #include #include #include #include #include "protocol/discoinfoquerier.h" #include "capsspec.h" #include "capsregistry.h" #include "xmpp_features.h" namespace XMPP { class Jid; } using namespace XMPP; class CapsManager : public QObject { Q_OBJECT public: CapsManager(const XMPP::Jid&, CapsRegistry* registry, Protocol::DiscoInfoQuerier* discoInfoQuerier); ~CapsManager(); bool isEnabled(); void setEnabled(bool); void updateCaps(const Jid& jid, const QString& node, const QString& ver, const QString& ext); void disableCaps(const Jid& jid); bool capsEnabled(const Jid& jid) const; XMPP::Features features(const Jid& jid) const; QString clientName(const Jid& jid) const; QString clientVersion(const Jid& jid) const; signals: /** * This signal is emitted when the feature list of a given JID have changed. */ void capsChanged(const Jid& jid); protected: CapsSpec getCapsSpecForNode(const XMPP::Jid& jid, const QString& disco_node, bool& ok) const; protected slots: void getDiscoInfo_success(const XMPP::Jid& jid, const QString& node, const XMPP::DiscoItem& item); void getDiscoInfo_error(const XMPP::Jid& jid, const QString& node, int error_code, const QString& error_string); void capsRegistered(const CapsSpec&); private: XMPP::Jid jid_; QPointer registry_; QPointer discoInfoQuerier_; bool isEnabled_; QMap capsSpecs_; QMap > capsJids_; }; #endif psi-0.14/src/capabilities/unittest/0000755000175000017500000000000011305557613015440 5ustar janjanpsi-0.14/src/capabilities/unittest/unittest.pri0000644000175000017500000000010211305557613020024 0ustar janjanSOURCES += \ $$PWD/capsmanagertest.cpp \ $$PWD/capsspectest.cpp psi-0.14/src/capabilities/unittest/capsspectest.cpp0000644000175000017500000000310311305557613020642 0ustar janjan/** * Copyright (C) 2007, Remko Troncon */ #include #include #include "qttestutil/qttestutil.h" #include "capabilities/capsspec.h" class CapsSpecTest : public QObject { Q_OBJECT private slots: void testConstructor() { CapsSpec c("a","b","c d"); QVERIFY(c.node() == "a"); QVERIFY(c.version() == "b"); QVERIFY(c.extensions() == "c d"); } void testEqualsNotEquals_Equal() { CapsSpec c1("a","b","c d"); CapsSpec c2("a","b","c d"); QVERIFY(c1 == c2); QVERIFY(!(c1 != c2)); } void testEqualsNotEquals_NotEqual() { CapsSpec c1("a","b","c d"); CapsSpec c2("a","e","c d"); QVERIFY(!(c1 == c2)); QVERIFY(c1 != c2); } void testSmallerThan() { CapsSpec c1("a","b","c"); CapsSpec c2("d","e","f"); QVERIFY(c1 < c2); QVERIFY(!(c2 < c1)); } void testSmallerThan_SameNode() { CapsSpec c1("a","b","c"); CapsSpec c2("a","e","f"); QVERIFY(c1 < c2); QVERIFY(!(c2 < c1)); } void testSmallerThan_SameNodeVersion() { CapsSpec c1("a","b","c"); CapsSpec c2("a","b","f"); QVERIFY(c1 < c2); QVERIFY(!(c2 < c1)); } void testSmallerThan_Equals() { CapsSpec c1("a","b","c"); CapsSpec c2("a","b","c"); QVERIFY(!(c1 < c2)); QVERIFY(!(c2 < c1)); } void testFlatten() { CapsSpec c("a","b","c d"); CapsSpecs cs = c.flatten(); QCOMPARE(cs.count(), 3); QVERIFY(cs[0] == CapsSpec("a", "b", "b")); QVERIFY(cs[1] == CapsSpec("a", "b", "c")); QVERIFY(cs[2] == CapsSpec("a", "b", "d")); } }; QTTESTUTIL_REGISTER_TEST(CapsSpecTest); #include "capsspectest.moc" psi-0.14/src/capabilities/unittest/capsmanagertest.cpp0000644000175000017500000000746511305557613021341 0ustar janjan/** * Copyright (C) 2007, Remko Troncon * See COPYING file for the detailed license. */ // FIXME: This test suite is far from complete #include #include #include "qttestutil/qttestutil.h" #include "protocol/discoinfoquerier.h" #include "xmpp/jid/jid.h" #include "capabilities/capsmanager.h" using namespace XMPP; // ----------------------------------------------------------------------------- class TestDiscoInfoQuerier : public Protocol::DiscoInfoQuerier { public: struct DiscoInfo { XMPP::Jid jid; QString node; XMPP::DiscoItem item; }; TestDiscoInfoQuerier() { nb_getdiscoinfo_called_ = 0; } void getDiscoInfo(const Jid& j, const QString& n) { emitDiscoInfo(j,n); } void emitDiscoInfo(const XMPP::Jid& j, const QString& n) { nb_getdiscoinfo_called_++; foreach(DiscoInfo info, infos_) { if (info.jid.compare(j,true) && info.node == n) { emit getDiscoInfo_success(j,n,info.item); return; } } } void addInfo(const XMPP::Jid& j, const QString& n, const XMPP::DiscoItem& it) { DiscoInfo i; i.jid = j; i.node = n; i.item = it; infos_ += i; } unsigned int nb_getdiscoinfo_called_; QList infos_; }; // ----------------------------------------------------------------------------- class CapsManagerTest : public QObject { Q_OBJECT private slots: void initTestCase() { manager_ = NULL; querier_ = new TestDiscoInfoQuerier(); } void cleanupTestCase() { delete manager_; } void testUpdateCaps() { QStringList capabilities; capabilities << "c1" << "c2" << "c3"; addContact("you@example.com/a", "myclient", "myversion", capabilities); CapsManager* manager = createManager("me@example.com"); manager->updateCaps("you@example.com/a", "myclient", "myversion", "c1 c2"); XMPP::Features features(manager->features("you@example.com/a")); QCOMPARE(querier_->nb_getdiscoinfo_called_, 3U); QVERIFY(features.test(QStringList("myversion_f1"))); QVERIFY(features.test(QStringList("c1_f1"))); QVERIFY(features.test(QStringList("c1_f2"))); QVERIFY(features.test(QStringList("c2_f1"))); QVERIFY(features.test(QStringList("c2_f2"))); } void testCapsEnabled() { QStringList capabilities; capabilities << "c1" << "c2"; addContact("you@example.com/a", "myclient", "myversion", capabilities); CapsManager* manager = createManager("me@example.com"); manager->updateCaps("you@example.com/a", "myclient", "myversion", "c1 c2"); QVERIFY(manager->capsEnabled("you@example.com/a")); } void testCapsEnabled_NoCaps() { CapsManager* manager = createManager("me@example.com/a"); QVERIFY(!manager->capsEnabled("you@example.com/b")); } void testDisableCaps() { QStringList capabilities; capabilities << "c1" << "c2"; addContact("you@example.com/a", "myclient", "myversion", capabilities); CapsManager* manager = createManager("me@example.com"); manager->updateCaps("you@example.com/a", "myclient", "myversion", "c1 c2"); manager->disableCaps("you@example.com/a"); QVERIFY(!manager->capsEnabled("you@example.com/a")); } private: void addContact(const QString& jid, const QString& client, const QString& version, const QStringList& capabilities) { XMPP::DiscoItem i; i.setFeatures(XMPP::Features(version + "_f1")); querier_->addInfo(jid, client + '#' + version, i); foreach(QString s, capabilities) { XMPP::DiscoItem i2; QStringList f; f << s + "_f1" << s + "_f2"; i2.setFeatures(XMPP::Features(f)); querier_->addInfo(jid, client + '#' + s, i2); } } CapsManager* createManager(const QString& jid) { manager_ = new CapsManager(jid, ®istry_, querier_); return manager_; } private: CapsRegistry registry_; TestDiscoInfoQuerier* querier_; CapsManager* manager_; }; QTTESTUTIL_REGISTER_TEST(CapsManagerTest); #include "capsmanagertest.moc" psi-0.14/src/capabilities/unittest/unittest.pro0000644000175000017500000000073711305557613020050 0ustar janjaninclude(../../modules.pri) include($$IRIS_XMPP_JID_MODULE) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$PSI_CAPABILITIES_MODULE) include($$PSI_UTILITIES_MODULE) include($$PSI_PROTOCOL_MODULE) include(unittest.pri) QT += xml # FIXME INCLUDEPATH += \ $$PWD/../../../iris/src/xmpp/xmpp-im DEPENDPATH += \ $$PWD/../../../iris/src/xmpp/xmpp-im SOURCES += \ $$PWD/../../../iris/src/xmpp/xmpp-im/xmpp_features.cpp \ $$PWD/../../../iris/src/xmpp/xmpp-im/xmpp_discoitem.cpp psi-0.14/src/capabilities/capsspec.cpp0000755000175000017500000000572011305557613016075 0ustar janjan/* * capsspec.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "capsspec.h" /** * \class CapsSpec * \brief A class representing an entity capability specification. * An entity capability is a combination of a node, a version, and a set of * extensions. */ /** * Default constructor. */ CapsSpec::CapsSpec() { } /** * \brief Basic constructor. * @param node the node * @param ven the version * @param ext the list of extensions (separated by spaces) */ CapsSpec::CapsSpec(const QString& node, const QString& ver, const QString& ext) : node_(node), ver_(ver), ext_(ext) { } /** * \brief Returns the node of the capabilities specification. */ const QString& CapsSpec::node() const { return node_; } /** * \brief Returns the version of the capabilities specification. */ const QString& CapsSpec::version() const { return ver_; } /** * \brief Returns the extensions of the capabilities specification. */ const QString& CapsSpec::extensions() const { return ext_; } /** * \brief Flattens the caps specification into the set of 'simple' * specifications. * A 'simple' specification is a specification with exactly one extension, * or with the version number as the extension. * * Example: A caps specification with node=http://psi-im.org, version=0.10, * and ext='achat vchat' would be expanded into the following list of specs: * node=http://psi-im.org, ver=0.10, ext=0.10 * node=http://psi-im.org, ver=0.10, ext=achat * node=http://psi-im.org, ver=0.10, ext=vchat */ CapsSpecs CapsSpec::flatten() const { CapsSpecs l; l.append(CapsSpec(node(),version(),version())); QStringList exts(extensions().split(' ',QString::SkipEmptyParts)); for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) { l.append(CapsSpec(node(),version(),*i)); } return l; } bool CapsSpec::operator==(const CapsSpec& s) const { return (node() == s.node() && version() == s.version() && extensions() == s.extensions()); } bool CapsSpec::operator!=(const CapsSpec& s) const { return !((*this) == s); } bool CapsSpec::operator<(const CapsSpec& s) const { return (node() != s.node() ? node() < s.node() : (version() != s.version() ? version() < s.version() : extensions() < s.extensions())); } psi-0.14/src/capabilities/capsspec.h0000755000175000017500000000245011305557613015537 0ustar janjan/* * capsspec.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CAPSSPEC_H #define CAPSSPEC_H #include #include class CapsSpec; typedef QList CapsSpecs; class CapsSpec { public: CapsSpec(); CapsSpec(const QString&, const QString&, const QString&); const QString& node() const; const QString& version() const; const QString& extensions() const; CapsSpecs flatten() const; bool operator==(const CapsSpec&) const; bool operator!=(const CapsSpec&) const; bool operator<(const CapsSpec&) const; private: QString node_, ver_, ext_; }; #endif psi-0.14/src/main.h0000644000175000017500000000243211305557613012226 0ustar janjan/* * main.h - initialization and profile/settings handling * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MAIN_H #define MAIN_H #include #include #include class PsiCon; class PsiMain : public QObject { Q_OBJECT public: PsiMain(const QMap& commandline, QObject *parent=0); ~PsiMain(); signals: void quit(); private slots: void chooseProfile(); void sessionStart(); void sessionQuit(int); void bail(); private: QString lastProfile, lastLang; bool autoOpen; QMap cmdline; PsiCon *pcon; }; #endif psi-0.14/src/fileutil.cpp0000644000175000017500000000617411305557613013461 0ustar janjan/* * fileutil.h - common file dialogs * Copyright (C) 2008 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "fileutil.h" #include #include #include #include #include "psioptions.h" static QString lastUsedOpenPathOptionPath = "options.ui.last-used-open-path"; static QString lastUsedSavePathOptionPath = "options.ui.last-used-save-path"; QString FileUtil::lastUsedOpenPath() { return PsiOptions::instance()->getOption(lastUsedOpenPathOptionPath).toString(); } void FileUtil::setLastUsedOpenPath(const QString& path) { QFileInfo fi(path); if (fi.exists()) { PsiOptions::instance()->setOption(lastUsedOpenPathOptionPath, path); } } QString FileUtil::lastUsedSavePath() { return PsiOptions::instance()->getOption(lastUsedSavePathOptionPath).toString(); } void FileUtil::setLastUsedSavePath(const QString& path) { QFileInfo fi(path); if (fi.exists()) { PsiOptions::instance()->setOption(lastUsedSavePathOptionPath, path); } } QString FileUtil::getOpenFileName(QWidget* parent, const QString& caption, const QString& filter, QString* selectedFilter) { while (1) { if (lastUsedOpenPath().isEmpty()) { setLastUsedOpenPath(QDir::homePath()); } QString fileName = QFileDialog::getOpenFileName(parent, caption, lastUsedOpenPath(), filter, selectedFilter); if (!fileName.isEmpty()) { QFileInfo fi(fileName); if (!fi.exists()) { QMessageBox::information(parent, tr("Error"), tr("The file specified does not exist.")); continue; } setLastUsedOpenPath(fi.path()); return fileName; } break; } return QString(); } QString FileUtil::getSaveFileName(QWidget* parent, const QString& caption, const QString& defaultFileName, const QString& filter, QString* selectedFilter) { if (lastUsedSavePath().isEmpty()) { if (!lastUsedOpenPath().isEmpty()) { setLastUsedSavePath(lastUsedOpenPath()); } else { setLastUsedSavePath(QDir::homePath()); } } QString dir = QDir(lastUsedSavePath()).filePath(defaultFileName); QString fileName = QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter); if (!fileName.isEmpty()) { QFileInfo fi(fileName); if (QDir(fi.path()).exists()) { setLastUsedSavePath(fi.path()); return fileName; } } return QString(); } QString FileUtil::getImageFileName(QWidget* parent) { return FileUtil::getOpenFileName(parent, tr("Choose a file"), tr("Images (*.png *.xpm *.jpg *.PNG *.XPM *.JPG)")); } psi-0.14/src/mcmdmanager.h0000644000175000017500000000453511305557613013563 0ustar janjan/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see . * */ // manager mini command system #ifndef MCMDMANAGER_H #define MCMDMANAGER_H #include #include #include #include #include #include // implementation in groupchatdlg.cpp void MiniCommand_Depreciation_Message(const QString &old,const QString &newCmd, QString &line1, QString &line2); class MCmdSimpleState : public QObject, public MCmdStateIface { Q_OBJECT public: MCmdSimpleState(QString name, QString prompt); MCmdSimpleState(QString name, QString prompt, int flags); virtual QString getName() { return name_;}; virtual QString getPrompt() { return prompt_;}; virtual int getFlags() { return flags_;}; virtual const QHash &getInfo() { return info_; }; virtual void dispose() { delete(this); }; virtual ~MCmdSimpleState(); QHash info_; signals: bool unhandled(QStringList command); protected: QString name_, prompt_; int flags_; }; class MCmdManager : public MCmdManagerIface { public: // UiSite -> Manager MCmdManager(MCmdUiSiteIface* site_); ~MCmdManager(); virtual bool processCommand(QString command); virtual QStringList completeCommand(QString &command, int pos, int &start, int &end); virtual bool open(MCmdStateIface *state, QStringList preset); virtual bool isActive(); // Provider registratation virtual void registerProvider(MCmdProviderIface *prov); protected: QStringList parseCommand(const QString command, int pos, int &part, QString &partial, int &start, int &end, char "edAtPos); QString serializeCommand(const QStringList &list); QList providers_; MCmdStateIface *state_; MCmdUiSiteIface *uiSite_; }; #endif psi-0.14/src/miniclient.cpp0000644000175000017500000001330211305557613013766 0ustar janjan/* * miniclient.cpp * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "applicationinfo.h" #include "miniclient.h" #include "proxy.h" #include "Certificates/CertificateHelpers.h" #include "Certificates/CertificateErrorDialog.h" #include "psiaccount.h" #include "xmpp_tasks.h" using namespace XMPP; MiniClient::MiniClient(QObject *parent) :QObject(parent) { _client = new Client; conn = 0; tls = 0; tlsHandler = 0; stream = 0; auth = false; force_ssl = false; error_disconnect = true; } MiniClient::~MiniClient() { delete _client; reset(); } void MiniClient::reset() { delete stream; stream = 0; delete tls; tls = 0; tlsHandler = 0; delete conn; conn = 0; } void MiniClient::connectToServer(const Jid &jid, bool legacy_ssl_probe, bool legacy_ssl, bool forcessl, const QString &_host, int _port, ProxyManager *pm, QString proxy, QString *_pass) { j = jid; QString host; int port = -1; bool useHost = false; force_ssl = forcessl; if(!_host.isEmpty()) { useHost = true; host = _host; port = _port; } AdvancedConnector::Proxy p; if(!proxy.isEmpty()) { const ProxyItem &pi = pm->getItem(proxy); if(pi.type == "http") // HTTP Connect p.setHttpConnect(pi.settings.host, pi.settings.port); else if(pi.type == "socks") // SOCKS p.setSocks(pi.settings.host, pi.settings.port); else if(pi.type == "poll") { // HTTP Poll QUrl u = pi.settings.url; if(u.queryItems().isEmpty()) { if (useHost) u.addQueryItem("server",host + ':' + QString::number(port)); else u.addQueryItem("server",jid.domain()); } p.setHttpPoll(pi.settings.host, pi.settings.port, u.toString()); p.setPollInterval(2); } if(pi.settings.useAuth) { p.setUserPass(pi.settings.user, pi.settings.pass); } } conn = new AdvancedConnector; if (QCA::isSupported("tls")) { tls = new QCA::TLS; tls->setTrustedCertificates(CertificateHelpers::allCertificates(ApplicationInfo::getCertificateStoreDirs())); tlsHandler = new QCATLSHandler(tls); tlsHandler->setXMPPCertCheck(true); connect(tlsHandler, SIGNAL(tlsHandshaken()), SLOT(tls_handshaken())); } conn->setProxy(p); if (useHost) { conn->setOptHostPort(host, port); conn->setOptSSL(legacy_ssl); } else { conn->setOptProbe(legacy_ssl_probe); } stream = new ClientStream(conn, tlsHandler); connect(stream, SIGNAL(connected()), SLOT(cs_connected())); connect(stream, SIGNAL(securityLayerActivated(int)), SLOT(cs_securityLayerActivated(int))); connect(stream, SIGNAL(needAuthParams(bool, bool, bool)), SLOT(cs_needAuthParams(bool, bool, bool))); connect(stream, SIGNAL(authenticated()), SLOT(cs_authenticated())); connect(stream, SIGNAL(connectionClosed()), SLOT(cs_connectionClosed())); connect(stream, SIGNAL(delayedCloseFinished()), SLOT(cs_delayedCloseFinished())); connect(stream, SIGNAL(warning(int)), SLOT(cs_warning(int))); connect(stream, SIGNAL(error(int)), SLOT(cs_error(int)), Qt::QueuedConnection); if(_pass) { auth = true; pass = *_pass; _client->connectToServer(stream, j); } else { auth = false; _client->connectToServer(stream, j, false); } } void MiniClient::close() { _client->close(); reset(); } Client *MiniClient::client() { return _client; } void MiniClient::setErrorOnDisconnect(bool b) { error_disconnect = b; } void MiniClient::tls_handshaken() { if (CertificateHelpers::checkCertificate(tls, tlsHandler, tlsOverrideDomain, tlsOverrideCert, 0, tr("Server Authentication"), j.domain())) { tlsHandler->continueAfterHandshake(); } else { close(); error(); } } void MiniClient::cs_connected() { } void MiniClient::cs_securityLayerActivated(int) { } void MiniClient::cs_needAuthParams(bool user, bool password, bool realm) { if(user) stream->setUsername(j.node()); if(password) stream->setPassword(pass); if(realm) stream->setRealm(j.domain()); stream->continueAfterParams(); } void MiniClient::cs_authenticated() { _client->start(j.domain(), j.node(), "", ""); if (!stream->old() && auth) { JT_Session *j = new JT_Session(_client->rootTask()); connect(j,SIGNAL(finished()),SLOT(sessionStart_finished())); j->go(true); } else { handshaken(); } } void MiniClient::sessionStart_finished() { JT_Session *j = (JT_Session*)sender(); if ( j->success() ) { handshaken(); } else { cs_error(-1); } } void MiniClient::cs_connectionClosed() { if (error_disconnect) cs_error(-1); else emit disconnected(); } void MiniClient::cs_delayedCloseFinished() { } void MiniClient::cs_warning(int err) { if (err == ClientStream::WarnNoTLS && force_ssl) { close(); QMessageBox::critical(0, tr("Server Error"), tr("The server does not support TLS encryption.")); } else { stream->continueAfterWarning(); } } void MiniClient::cs_error(int err) { QString str; bool reconn; PsiAccount::getErrorInfo(err, conn, stream, tlsHandler, &str, &reconn); close(); QMessageBox::critical(0, tr("Server Error"), tr("There was an error communicating with the Jabber server.\nDetails: %1").arg(str)); error(); } psi-0.14/src/pluginmanager.cpp0000644000175000017500000002275511305557613014500 0ustar janjan/* * (c) 2006 Kevin Smith * (c) 2008 Maciej Niedzielski */ #include "pluginmanager.h" #include #include #include #include #include "xmpp_client.h" #include "xmpp_task.h" #include "xmpp_message.h" #include "applicationinfo.h" #include "psioptions.h" #include "pluginhost.h" #include "psiplugin.h" #include "psiaccount.h" #include "stanzafilter.h" #include "stanzasender.h" #include "iqfilter.h" #include "iqnamespacefilter.h" #include "eventfilter.h" #include "optionaccessor.h" //TODO(mck) // - make sure PluginManager works correctly when changing profiles // - use native separators when displaying file path /** * Helper class used to process incoming XML in plugins. */ class PluginManager::StreamWatcher: public XMPP::Task { public: StreamWatcher(Task* t, PluginManager* m, int a) : Task(t), manager(m), account(a) {} bool take(const QDomElement& e) { return manager->incomingXml(account, e); } PluginManager* manager; int account; }; /** * Function to obtain all the directories in which plugins can be stored * \return List of plugin directories */ static QStringList pluginDirs() { QStringList l; l += ApplicationInfo::resourcesDir() + "/plugins"; l += ApplicationInfo::homeDir() + "/plugins"; return l; } /** * Method for accessing the singleton instance of the class. * Instanciates if no instance yet exists. * \return Pointer to the plugin manager. */ PluginManager* PluginManager::instance() { if (!instance_) { instance_ = new PluginManager(); } return instance_; } /** * Default constructor. Locates all plugins, sets watchers on those directories to * locate new ones and loads those enabled in the config. */ PluginManager::PluginManager() : QObject(NULL) { updatePluginsList(); loadEnabledPlugins(); foreach (QString path, pluginDirs()) { QCA::DirWatch *dw = new QCA::DirWatch(path, this); connect(dw, SIGNAL(changed()), SLOT(dirsChanged())); dirWatchers_.append(dw); } connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), this, SLOT(optionChanged(const QString&))); } /** * Updates list of known plugins by reading all plugin directories */ void PluginManager::updatePluginsList() { foreach (QString d, pluginDirs()) { QDir dir(d); foreach (QString file, dir.entryList()) { file = dir.absoluteFilePath(file); qWarning("Found plugin: %s", qPrintable(file)); if (!pluginByFile_.contains(file)) { PluginHost* host = new PluginHost(this, file); if (host->isValid()) { hosts_[host->name()] = host; pluginByFile_[file] = host; } } else { qWarning("Which we already knew about"); } } } } /** * This slot is executed when the contents of a plugin directory changes * It causes the available plugin list to be refreshed. * * TODO: it should also load the plugins if they're on the autoload list */ void PluginManager::dirsChanged() { updatePluginsList(); } /** * This causes all plugins that are both set for auto-load, and available * to be loaded. */ void PluginManager::loadEnabledPlugins() { qDebug("Loading enabled plugins"); foreach (PluginHost* plugin, hosts_.values()) { QString option = QString("%1.%2").arg(loadOptionPrefix).arg(plugin->shortName()); if (PsiOptions::instance()->getOption(option).toBool()) { qWarning("Plugin %s is enabled in config: loading", qPrintable(plugin->shortName())); plugin->load(); plugin->enable(); } } } /** * Called when an option changes to load or unload a plugin if it's a plugin * option * \param option Option changed */ void PluginManager::optionChanged(const QString& option) { //QString("%1.%2").arg(loadOptionPrefix).arg(shortNames_[plugin]); //TODO(mck): implement this... for now, enabling/disabling requires psi restart } /** * Loads all available plugins */ void PluginManager::loadAllPlugins() { qDebug("Loading all plugins"); //Any static (compiled in) plugins we happen to have /*foreach( QObject* plugin, QPluginLoader::staticInstances() ) { loadPlugin( plugin ); }*/ //Now look for external plugins foreach (PluginHost* plugin, hosts_.values()) { plugin->load(); plugin->enable(); } } /** * Unloads all Psi plugins. * \return Success of unloading all plugins; if any plugins couldn't be * unloaded, false. */ bool PluginManager::unloadAllPlugins() { qDebug("Unloading all plugins"); bool ok = true; foreach (PluginHost* plugin, hosts_.values()) { if (!plugin->disable()) { ok = false; } else if (plugin->unload()) { ok = false; } } return ok; } /** * Find the file which provides the named plugin. If the named plugin is not * known, an empty string is provided. * \param plugin Name of the plugin. * \return Path to the plugin file. */ QString PluginManager::pathToPlugin(const QString& plugin) { QString path; if (hosts_.contains(plugin)) { path = hosts_[plugin]->path(); } return path; } /** * Returns short name of the named plugin. If the named plugin is not * known, an empty string is provided. * \param plugin Name of the plugin. * \return Path to the plugin file. */ QString PluginManager::shortName(const QString& plugin) { QString name; if (hosts_.contains(plugin)) { name = hosts_[plugin]->shortName(); } return name; } /** * Returns a list of available plugin names found in all plugin directories. */ QStringList PluginManager::availablePlugins() { return hosts_.keys(); } /** * Provides a pointer to a QWidget providing the options dialog for the * named plugin, if it exists, else NULL. * \param plugin Name of the plugin. * \return Pointer to the options widget for the named plugin. */ QWidget* PluginManager::optionsWidget(const QString& plugin) { QWidget* widget = 0; if (hosts_.contains(plugin)) { widget = hosts_[plugin]->optionsWidget(); } else { qWarning("Attempting to get options for %s which doesn't exist", qPrintable(plugin)); } return widget; } /** * \brief Give each plugin the opportunity to process the incoming message event * * Each plugin is passed the event in turn. Any plugin may then modify the event * and may cause the event to be silently discarded. * * \param account Pointer to the PsiAccount responsible * \param event Incoming event * \return Continue processing the event; true if the event should be silently discarded. */ bool PluginManager::processMessage(const PsiAccount* account, const QString& jidFrom, const QString& body, const QString& subject) { bool handled = false; foreach (PluginHost* host, hosts_.values()) { if (host->processMessage(accountIds_[account], jidFrom, body, subject)) { handled = true; break; } } return handled; } /** * \brief Give each plugin the opportunity to process the incoming event * * Each plugin is passed the event in turn. Any plugin may then modify the event * and may cause the event to be silently discarded. * * \param account Pointer to the PsiAccount responsible * \param event Incoming event * \return Continue processing the event; true if the event should be silently discarded. */ bool PluginManager::processEvent(const PsiAccount* account, QDomElement& event) { bool handled = false; foreach (PluginHost* host, hosts_.values()) { if (host->processEvent(accountIds_[account], event)) { handled = true; break; } } return handled; } /** * \brief Give each plugin the opportunity to process the incoming xml * * Each plugin is passed the xml in turn using various filter interfaces * (for example, see StanzaFilter or IqFilter). * Any plugin may then modify the xml and may cause the stanza to be * silently discarded. * * \param account Identifier of the PsiAccount responsible * \param xml Incoming XML * \return Continue processing the event; true if the event should be silently discarded. */ bool PluginManager::incomingXml(int account, const QDomElement &xml) { bool handled = false; foreach (PluginHost* host, hosts_.values()) { if (host->incomingXml(account, xml)) { handled = true; break; } } return handled; } /** * Called by PluginHost when its hosted plugin wants to send xml stanza. * * \param account Identifier of the PsiAccount responsible * \param xml XML stanza to be sent */ void PluginManager::sendXml(int account, const QString& xml) { //TODO(mck) // - think if it is better to ask plugin(host) for string or xml node // - validate things // - add id if missing // - maybe use appropriate Task to send // - make psi aware of things that are being send // (for example, pipeline messages through history system) if (account < clients_.size()) { clients_[account]->send(xml); } } /** * Returns unique stanza identifier in account's stream * * \param account Identifier of the PsiAccount responsible * \return Unique ID to be used for when sending a stanza */ QString PluginManager::uniqueId(int account) { QString id; if (account < clients_.size()) { id = clients_[account]->genUniqueId(); } return id; } /** * Tells the plugin manager about an XMPP::Client and the owning PsiAccount */ void PluginManager::addAccount(const PsiAccount* account, XMPP::Client* client) { clients_.append(client); const int id = clients_.size() - 1; accountIds_[account] = id; new StreamWatcher(client->rootTask(), this, id); } /** * Performs basic validity checking on a stanza * TODO : populate verifyStanza method and use it */ bool PluginManager::verifyStanza(const QString& stanza) { Q_UNUSED(stanza); return true; } PluginManager* PluginManager::instance_ = NULL; const QString PluginManager::loadOptionPrefix = "plugins.auto-load"; const QString PluginManager::pluginOptionPrefix = "plugins.options"; psi-0.14/src/mood.h0000644000175000017500000000341311305557613012240 0ustar janjan/* * mood.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MOOD_H #define MOOD_H #include class QDomElement; class QDomDocument; class Mood { public: enum Type { Unknown, Afraid, Amazed, Angry, Annoyed, Anxious, Aroused, Ashamed, Bored, Brave, Calm, Cold, Confused, Contented, Cranky, Curious, Depressed, Disappointed, Disgusted, Distracted, Embarrassed, Excited, Flirtatious, Frustrated, Grumpy, Guilty, Happy, Hot, Humbled, Humiliated, Hungry, Hurt, Impressed, In_awe, In_love, Indignant, Interested, Intoxicated, Invincible, Jealous, Lonely, Mean, Moody, Nervous, Neutral, Offended, Playful, Proud, Relieved, Remorseful, Restless, Sad, Sarcastic, Serious, Shocked, Shy, Sick, Sleepy, Stressed, Surprised, Thirsty, Worried }; Mood(); Mood(Type, const QString& = QString()); Mood(const QDomElement&); Type type() const; QString typeText() const; const QString& text() const; bool isNull() const; QDomElement toXml(QDomDocument&); protected: void fromXml(const QDomElement&); private: Type type_; QString text_; }; #endif psi-0.14/src/mucmanager.h0000644000175000017500000001076711305557613013433 0ustar janjan/* * mucmanager.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MUCMANAGER_H #define MUCMANAGER_H #include #include "xmpp_muc.h" #include "xmpp_jid.h" class QString; namespace XMPP { class XData; class Client; } using namespace XMPP; class MUCManager : public QObject { Q_OBJECT public: enum Action { Unknown, Kick, Ban, GrantVoice, RevokeVoice, GrantMember, RevokeMember, GrantModerator, RevokeModerator, GrantAdmin, RevokeAdmin, GrantOwner, RevokeOwner, SetRole, SetAffiliation }; MUCManager(XMPP::Client* client, const Jid&); const Jid& room() const; void getConfiguration(); void setConfiguration(const XMPP::XData&); void setDefaultConfiguration(); void setItems(const QList&); void getItemsByAffiliation(MUCItem::Affiliation); void destroy(const QString& reason = QString(), const Jid& venue = Jid()); // Basic operations void kick(const QString&, const QString& = QString()); void grantVoice(const QString&, const QString& = QString()); void revokeVoice(const QString&, const QString& = QString()); void grantModerator(const QString&, const QString& = QString()); void revokeModerator(const QString&, const QString& = QString()); void ban(const Jid&, const QString& = QString()); void grantMember(const Jid&, const QString& = QString()); void revokeMember(const Jid&, const QString& = QString()); void grantOwner(const Jid&, const QString& = QString()); void revokeOwner(const Jid&, const QString& = QString()); void grantAdmin(const Jid&, const QString& = QString()); void revokeAdmin(const Jid&, const QString& = QString()); void setRole(const QString&, MUCItem::Role, const QString& = QString(), Action = Unknown); void setAffiliation(const Jid&, MUCItem::Affiliation, const QString& = QString(), Action = Unknown); // Tests static QString roleToString(XMPP::MUCItem::Role, bool p = false); static QString affiliationToString(XMPP::MUCItem::Affiliation, bool p = false); static bool canKick(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canGrantVoice(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canRevokeVoice(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canGrantModerator(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canRevokeModerator(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canBan(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canGrantMember(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canRevokeMember(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canGrantOwner(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canRevokeOwner(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canGrantAdmin(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canRevokeAdmin(const XMPP::MUCItem&, const XMPP::MUCItem&); static bool canSetRole(const XMPP::MUCItem&, const XMPP::MUCItem&, XMPP::MUCItem::Role); static bool canSetAffiliation(const XMPP::MUCItem&, const XMPP::MUCItem&, XMPP::MUCItem::Affiliation); signals: void getConfiguration_success(const XData&); void getConfiguration_error(int, const QString&); void setConfiguration_success(); void setConfiguration_error(int, const QString&); void destroy_success(); void destroy_error(int, const QString&); void setItems_success(); void setItems_error(int, const QString&); void getItemsByAffiliation_success(MUCItem::Affiliation, const QList&); void getItemsByAffiliation_error(MUCItem::Affiliation, int, const QString&); void action_success(MUCManager::Action); void action_error(MUCManager::Action, int, const QString&); protected slots: void getConfiguration_finished(); void setConfiguration_finished(); void destroy_finished(); void action_finished(); void getItemsByAffiliation_finished(); void setItems_finished(); private: XMPP::Client* client_; Jid room_; }; #endif psi-0.14/src/ahcexecutetask.h0000644000175000017500000000224511305557613014305 0ustar janjan/* * ahcexecutetask.h - Ad-Hoc Command Execute Task * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHCEXECUTETASK_H #define AHCEXECUTETASK_H #include "xmpp_task.h" #include "xmpp_jid.h" #include "ahcommand.h" class QDomElement; class AHCExecuteTask : public XMPP::Task { public: AHCExecuteTask(const XMPP::Jid& j, const AHCommand&, XMPP::Task* t); void onGo(); bool take(const QDomElement &x); private: XMPP::Jid receiver_; AHCommand command_; }; #endif psi-0.14/src/psitoolbar.h0000644000175000017500000000263211305557613013462 0ustar janjan/* * psitoolbar.h - the Psi toolbar class * Copyright (C) 2003-2008 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSITOOLBAR_H #define PSITOOLBAR_H #include class QContextMenuEvent; class ToolbarPrefs; class PsiOptions; #include "psiactionlist.h" class PsiToolBar : public QToolBar { Q_OBJECT public: PsiToolBar(const QString& base, QMainWindow* mainWindow, MetaActionList* actionList); ~PsiToolBar(); void initialize(); void updateVisibility(); static void structToOptions(PsiOptions* options, const ToolbarPrefs& s); signals: void customize(); protected: void contextMenuEvent(QContextMenuEvent* e); private: MetaActionList* actionList_; QAction* customizeAction_; QString base_; }; #endif psi-0.14/src/statusdlg.cpp0000644000175000017500000001642411305557613013655 0ustar janjan/* * statusdlg.cpp - dialogs for setting and reading status messages * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "statusdlg.h" #include #include #include #include #include #include #include #include #include #include #include "jidutil.h" #include "psicon.h" #include "psioptions.h" #include "psiaccount.h" #include "userlist.h" #include "common.h" #include "msgmle.h" #include "statuspreset.h" #include "statuscombobox.h" #include "shortcutmanager.h" //---------------------------------------------------------------------------- // StatusShowDlg // FIXME: Will no longer be needed once it is out of the groupchat contactview //---------------------------------------------------------------------------- StatusShowDlg::StatusShowDlg(const UserListItem &u) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); // build the dialog QVBoxLayout *vb = new QVBoxLayout(this); vb->setMargin(8); PsiTextView *te = new PsiTextView(this); vb->addWidget(te); QHBoxLayout *hb = new QHBoxLayout; vb->addLayout(hb); QPushButton *pb = new QPushButton(tr("&Close"), this); connect(pb, SIGNAL(clicked()), SLOT(close())); hb->addStretch(1); hb->addWidget(pb); hb->addStretch(1); // set the rest up te->setReadOnly(true); te->setAcceptRichText(true); te->setText(u.makeDesc()); setWindowTitle(tr("Status for %1").arg(JIDUtil::nickOrJid(u.name(), u.jid().full()))); resize(400,240); pb->setFocus(); } //---------------------------------------------------------------------------- // StatusSetDlg //---------------------------------------------------------------------------- class StatusSetDlg::Private { public: Private() {} PsiCon *psi; PsiAccount *pa; Status s; ChatView *te; StatusComboBox *cb_type; QComboBox *cb_preset; QLineEdit *le_priority; QCheckBox *save; }; StatusSetDlg::StatusSetDlg(PsiCon *psi, const Status &s) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); d = new Private; d->psi = psi; d->pa = 0; d->psi->dialogRegister(this); d->s = s; setWindowTitle(CAP(tr("Set Status: All accounts"))); init(); } StatusSetDlg::StatusSetDlg(PsiAccount *pa, const Status &s) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); d = new Private; d->psi = 0; d->pa = pa; d->pa->dialogRegister(this); d->s = s; setWindowTitle(CAP(tr("Set Status: %1").arg(d->pa->name()))); init(); } void StatusSetDlg::init() { int type = makeSTATUS(d->s); // build the dialog QVBoxLayout *vb = new QVBoxLayout(this); vb->setMargin(8); QHBoxLayout *hb1 = new QHBoxLayout; vb->addLayout(hb1); // Status QLabel *l; l = new QLabel(tr("Status:"), this); hb1->addWidget(l); d->cb_type = new StatusComboBox(this, static_cast(type)); hb1->addWidget(d->cb_type,3); // Priority l = new QLabel(tr("Priority:"), this); hb1->addWidget(l); d->le_priority = new QLineEdit(this); d->le_priority->setMinimumWidth(30); hb1->addWidget(d->le_priority,1); // Status preset l = new QLabel(tr("Preset:"), this); hb1->addWidget(l); d->cb_preset = new QComboBox(this); d->cb_preset->addItem(tr("")); QStringList presets; foreach(QVariant name, PsiOptions::instance()->mapKeyList("options.status.presets")) { presets += name.toString(); } presets.sort(); d->cb_preset->addItems(presets); connect(d->cb_preset, SIGNAL(currentIndexChanged(int)), SLOT(chooseStatusPreset(int))); hb1->addWidget(d->cb_preset,3); d->te = new ChatView(this); d->te->setDialog(this); d->te->setReadOnly(false); d->te->setAcceptRichText(false); d->te->setMinimumHeight(50); vb->addWidget(d->te); QHBoxLayout *hb = new QHBoxLayout; vb->addLayout(hb); QPushButton *pb1 = new QPushButton(tr("&Set"), this); QPushButton *pb2 = new QPushButton(tr("&Cancel"), this); d->save = new QCheckBox(this); d->save->setText(tr("Sa&ve as Preset")); d->save->setChecked(false); hb->addWidget(pb1); hb->addStretch(1); hb->addWidget(d->save); hb->addStretch(1); hb->addWidget(pb2); // set the rest up d->te->setAcceptRichText(false); d->te->setText(d->s.status()); d->te->selectAll(); connect(pb1, SIGNAL(clicked()), SLOT(doButton())); connect(pb2, SIGNAL(clicked()), SLOT(cancel())); d->te->setFocus(); ShortcutManager::connect("common.close", this, SLOT(close())); ShortcutManager::connect("status.set", this, SLOT(doButton())); resize(400,240); } StatusSetDlg::~StatusSetDlg() { if(d->psi) d->psi->dialogUnregister(this); else if(d->pa) d->pa->dialogUnregister(this); delete d; } void StatusSetDlg::doButton() { // Trim whitespace d->te->setText(d->te->getPlainText().trimmed()); // Save preset if (d->save->isChecked()) { QString text; while(1) { // Get preset bool ok = false; text = QInputDialog::getText(this, CAP(tr("New Status Preset")), tr("Please enter a name for the new status preset:"), QLineEdit::Normal, text, &ok); if (!ok) return; // Check preset name if (text.isEmpty()) { QMessageBox::information(this, tr("Error"), tr("Can't create a blank preset!")); } else if(PsiOptions::instance()->mapKeyList("options.status.presets").contains(text)) { QMessageBox::information(this, tr("Error"), tr("You already have a preset with that name!")); } else break; } // Store preset StatusPreset sp(text, d->te->getPlainText(), XMPP::Status(d->cb_type->status()).type()); if (!d->le_priority->text().isEmpty()) { sp.setPriority(d->le_priority->text().toInt()); } sp.toOptions(PsiOptions::instance()); QString base = PsiOptions::instance()->mapPut("options.status.presets", text); } // Set status int type = d->cb_type->status(); QString str = d->te->getPlainText(); if (d->le_priority->text().isEmpty()) emit set(makeStatus(type, str), false); else emit set(makeStatus(type, str, d->le_priority->text().toInt()), true); close(); } void StatusSetDlg::chooseStatusPreset(int x) { if(x < 1) return; QString base = PsiOptions::instance()->mapLookup("options.status.presets", d->cb_preset->itemText(x)); d->te->setText(PsiOptions::instance()->getOption(base+".message").toString()); if (PsiOptions::instance()->getOption(base+".force-priority").toBool()) { d->le_priority->setText(QString::number(PsiOptions::instance()->getOption(base+".priority").toInt())); } else { d->le_priority->clear(); } XMPP::Status status; status.setType(PsiOptions::instance()->getOption(base+".status").toString()); d->cb_type->setStatus(status.type()); } void StatusSetDlg::cancel() { emit cancelled(); close(); } void StatusSetDlg::reject() { cancel(); QDialog::reject(); } psi-0.14/src/pgptransaction.h0000644000175000017500000000324411305557613014340 0ustar janjan/* * pgptransaction.h * Copyright (C) 2001-2005 Justin Karneges * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PGPTRANSACTION_H #define PGPTRANSACTION_H #include #include #include "xmpp_jid.h" #include "xmpp_message.h" class PGPTransaction : public QCA::SecureMessage { Q_OBJECT public: PGPTransaction(QCA::SecureMessageSystem*); ~PGPTransaction(); int id() const; const XMPP::Message& message() const; void setMessage(const XMPP::Message&); const QDomElement & xml() const; void setXml(const QDomElement &); XMPP::Jid jid() const; void setJid(const XMPP::Jid &); private: QCA::SecureMessageSystem* system_; XMPP::Message message_; QDomElement xml_; XMPP::Jid jid_; int id_; static int idCounter_; }; #endif psi-0.14/src/disco.ui0000644000175000017500000001267111305557613012577 0ustar janjan Disco 0 0 523 404 Service Discovery 0 0 ToolBar will be placed here 11 6 0 6 &Address: cb_address 7 0 2 0 true &Node: cb_node 7 0 1 0 0 0 16777215 16777215 true &Browse Auto-browse into objects true Automatically get item information QFrame::HLine QFrame::Sunken Qt::Horizontal 0 6 Qt::Horizontal QSizePolicy::Expanding 349 20 &Close qPixmapFromMimeSource BusyWidget
busywidget.h
0
IconButton
iconbutton.h
0
psi-0.14/src/qwextend.h0000644000175000017500000000026711305557613013145 0ustar janjan#ifndef QWEXTEND_H #define QWEXTEND_H #include #include #ifdef Q_WS_X11 class QWidget; void reparent_good(QWidget *that, Qt::WFlags f, bool showIt); #endif #endif psi-0.14/src/geolocation.cpp0000644000175000017500000001054511305557613014144 0ustar janjan/* * geolocation.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "geolocation.h" GeoLocation::GeoLocation() { } GeoLocation::GeoLocation(const QDomElement& el) { fromXml(el); } QDomElement GeoLocation::toXml(QDomDocument& doc) { QDomElement geoloc = doc.createElement("geoloc"); geoloc.setAttribute("xmlns", "http://jabber.org/protocol/geoloc"); if (alt_.hasValue()) { QDomElement e = doc.createElement("alt"); e.appendChild(doc.createTextNode(QString::number(alt_.value()))); geoloc.appendChild(e); } if (bearing_.hasValue()) { QDomElement e = doc.createElement("bearing"); e.appendChild(doc.createTextNode(QString::number(bearing_.value()))); geoloc.appendChild(e); } if (error_.hasValue()) { QDomElement e = doc.createElement("error"); e.appendChild(doc.createTextNode(QString::number(error_.value()))); geoloc.appendChild(e); } if (lat_.hasValue()) { QDomElement e = doc.createElement("lat"); e.appendChild(doc.createTextNode(QString::number(lat_.value()))); geoloc.appendChild(e); } if (lon_.hasValue()) { QDomElement e = doc.createElement("lon"); e.appendChild(doc.createTextNode(QString::number(lon_.value()))); geoloc.appendChild(e); } if (!datum_.isEmpty()) { QDomElement e = doc.createElement("datum"); e.appendChild(doc.createTextNode(datum_)); geoloc.appendChild(e); } if (!description_.isEmpty()) { QDomElement e = doc.createElement("description"); e.appendChild(doc.createTextNode(description_)); geoloc.appendChild(e); } return geoloc; } void GeoLocation::fromXml(const QDomElement& e) { if (e.tagName() != "geoloc") return; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement m = n.toElement(); if (m.tagName() == "alt") alt_ = Maybe(m.text().toFloat()); if (m.tagName() == "bearing") bearing_ = Maybe(m.text().toFloat()); if (m.tagName() == "error") error_ = Maybe(m.text().toFloat()); if (m.tagName() == "lat") lat_ = Maybe(m.text().toFloat()); if (m.tagName() == "lon") lon_ = Maybe(m.text().toFloat()); if (m.tagName() == "datum") datum_ = m.text(); if (m.tagName() == "description") description_ = m.text(); } } void GeoLocation::setAlt(float alt) { alt_ = Maybe(alt); } void GeoLocation::setBearing(float bearing) { bearing_ = Maybe(bearing); } void GeoLocation::setError(float error) { error_ = Maybe(error); } void GeoLocation::setLat(float lat) { lat_ = Maybe(lat); } void GeoLocation::setLon(float lon) { lon_ = Maybe(lon); } void GeoLocation::setDatum(const QString& datum) { datum_ = datum; } void GeoLocation::setDescription(const QString& description) { description_ = description; } const Maybe& GeoLocation::alt() const { return alt_; } const Maybe& GeoLocation::bearing() const { return bearing_; } const Maybe& GeoLocation::error() const { return error_; } const Maybe& GeoLocation::lat() const { return lat_; } const Maybe& GeoLocation::lon() const { return lon_; } const QString& GeoLocation::datum() const { return datum_; } const QString& GeoLocation::description() const { return description_; } bool GeoLocation::isNull() const { return !lat_.hasValue() || !lon_.hasValue(); } bool GeoLocation::operator==(const GeoLocation& o) const { // FIXME bool equal = true; equal = equal && (lat_.hasValue() ? lat_.value() == o.lat().value() : !o.lat().hasValue()); equal = equal && (lon_.hasValue() ? lon_.value() == o.lon().value() : !o.lon().hasValue()); return equal; } bool GeoLocation::operator!=(const GeoLocation& o) const { return !((*this) == o); } psi-0.14/src/mooddlg.h0000644000175000017500000000201711305557613012726 0ustar janjan/* * mooddlg.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MOODDLG_H #define MOODDLG_H #include #include "ui_mood.h" class PsiAccount; class MoodDlg : public QDialog { Q_OBJECT public: MoodDlg(PsiAccount*); protected slots: void setMood(); private: Ui::Mood ui_; PsiAccount* pa_; }; #endif psi-0.14/src/CocoaUtilities/0000755000175000017500000000000011305557613014050 5ustar janjanpsi-0.14/src/CocoaUtilities/CocoaInitializer.mm0000644000175000017500000000106511305557613017635 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #include "CocoaUtilities/CocoaInitializer.h" #include #include #include class CocoaInitializer::Private { public: NSAutoreleasePool* autoReleasePool_; }; CocoaInitializer::CocoaInitializer() { #if 0 d = new CocoaInitializer::Private(); NSApplicationLoad(); d->autoReleasePool_ = [[NSAutoreleasePool alloc] init]; #endif } CocoaInitializer::~CocoaInitializer() { #if 0 [d->autoReleasePool_ release]; delete d; #endif } psi-0.14/src/CocoaUtilities/CocoaInitializer.h0000644000175000017500000000042611305557613017453 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING file for the detailed license. */ #ifndef COCOAINITIALIZER_H #define COCOAINITIALIZER_H class CocoaInitializer { public: CocoaInitializer(); ~CocoaInitializer(); private: class Private; Private* d; }; #endif psi-0.14/src/CocoaUtilities/CocoaUtilities.pri0000644000175000017500000000022011305557613017476 0ustar janjanINCLUDEPATH *= $$PWD/.. DEPENDPATH *= $$PWD $$PWD/.. HEADERS += \ $$PWD/CocoaInitializer.h OBJECTIVE_SOURCES += \ $$PWD/CocoaInitializer.mm psi-0.14/src/psioptionseditor.h0000644000175000017500000000150311305557613014716 0ustar janjan#ifndef _PSIOPTIONSEDITOR_H_ #define _PSIOPTIONSEDITOR_H_ #include #include #include #include #include #include #include "optionstreemodel.h" class PsiOptions; class PsiOptionsEditor : public QWidget { Q_OBJECT public: PsiOptionsEditor(QWidget *parent=0); void bringToFront(); private slots: void tv_edit(const QModelIndex &idx); void selectionChanged(const QModelIndex &idx); void updateWidth(); void add(); void edit(); void deleteit(); void detach(); private: PsiOptions *o_; QTreeView* tv_; int tv_colWidth; OptionsTreeModel* tm_; QCheckBox* cb_; QLabel* lb_type; QLabel* lb_path; QLabel* lb_comment; QPushButton *pb_delete; QPushButton *pb_edit; QPushButton *pb_new; QToolButton *pb_detach; }; #endif /* _PSIOPTIONSEDITOR_H_ */ psi-0.14/src/eventdlg.cpp0000644000175000017500000014416211305557613013454 0ustar janjan/* * eventdlg.cpp - dialog for sending / receiving messages and events * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eventdlg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psievent.h" #include "psicon.h" #include "psiaccount.h" #include "textutil.h" #include "psiiconset.h" #include "jidutil.h" #include "psioptions.h" #include "msgmle.h" #include "accountscombobox.h" #include "common.h" #include "pgputil.h" #include "xmpp_htmlelement.h" #include "userlist.h" #include "iconwidget.h" #include "fancylabel.h" #include "iconselect.h" #include "iconlabel.h" #include "iconwidget.h" #include "icontoolbutton.h" #include "psitooltip.h" #include "serverinfomanager.h" #include "alerticon.h" #include "shortcutmanager.h" #include "httpauthmanager.h" #include "psicontactlist.h" #include "accountlabel.h" #include "xdata_widget.h" #include "desktoputil.h" #include "psirichtext.h" static QString findJid(const QString &s, int x, int *p1, int *p2) { // scan backward for the beginning of a Jid int n1 = x; if(n1 >= (int)s.length()) n1 = s.length()-1; for(; n1 >= 0; --n1) { if(s.at(n1) == ',') { ++n1; break; } } if(n1 < 0) n1 = 0; // go forward, skipping whitespace for(; n1 < (int)s.length(); ++n1) { if(!s.at(n1).isSpace()) break; } // now find the end of the Jid int n2 = n1; for(; n2 < (int)s.length(); ++n2) { if(s.at(n2) == ',') break; } --n2; // scan backwards from the end, skipping whitespace for(; n2 > n1; --n2) { if(!s.at(n2).isSpace()) break; } ++n2; *p1 = n1; *p2 = n2; return s.mid(n1, n2-n1); } //---------------------------------------------------------------------------- // ELineEdit - a line edit that handles advanced Jid entry //---------------------------------------------------------------------------- // hack hack hack hack #ifdef __GNUC__ #warning "Disabled QLineEditPrivate (see below)" #endif //struct QLineEditPrivate //{ // // qt 3.3.1 // /*QLineEdit *q; // QString text; // int cursor; // int cursorTimer; // QPoint tripleClick; // int tripleClickTimer; // uint frame : 1; // uint cursorVisible : 1; // uint separator : 1; // uint readOnly : 1; // uint modified : 1; // uint direction : 5; // uint dragEnabled : 1; // uint alignment : 3; // uint echoMode : 2; // uint textDirty : 1; // uint selDirty : 1; // uint validInput : 1; // int ascent; // int maxLength; // int menuId; // int hscroll;*/ // // char pad[sizeof(QLineEdit *) + sizeof(QString) + (sizeof(int)*2) + sizeof(QPoint) + sizeof(int) + 3 + (sizeof(int)*3)]; // int hscroll; //}; ELineEdit::ELineEdit(EventDlg *parent, const char *name) :QLineEdit(parent) { setObjectName(name); setAcceptDrops(true); } void ELineEdit::dragEnterEvent(QDragEnterEvent *e) { if (e->mimeData()->hasText()) e->accept(); else e->ignore(); } void ELineEdit::dropEvent(QDropEvent *e) { QString str = e->mimeData()->text(); if(!str.isEmpty()) { Jid jid(str); if(!jid.isValid()) setText(str); else { EventDlg *e = (EventDlg *)parent(); QString name = e->jidToString(jid); bool hasComma = false, hasText = false; int len = text().length(); while ( --len >= 0 ) { QChar c = text().at( len ); if ( c == ',' ) { hasComma = true; break; } else if ( !c.isSpace() ) { hasText = true; break; } } if ( hasComma || !hasText ) setText(text() + ' ' + name); else setText(text() + ", " + name); } setCursorPosition(text().length()); repaint(); } } void ELineEdit::keyPressEvent(QKeyEvent *e) { QLineEdit::keyPressEvent(e); if(e->text().length() == 1 && e->text()[0].isLetterOrNumber()) tryComplete(); } #ifdef __GNUC__ #warning "eventdlg.cpp: Disabled right click on JID" #endif //Q3PopupMenu *ELineEdit::createPopupMenu() //{ // EventDlg *e = (EventDlg *)parent(); // int xoff = mapFromGlobal(QCursor::pos()).x(); // int x = characterAt(d->hscroll + xoff, 0); // QString str = text(); // int p1, p2; // QString j = findJid(str, x, &p1, &p2); // if(j.isEmpty()) // return QLineEdit::createPopupMenu(); // // UserResourceList list = e->getResources(j); // // setCursorPosition(p1); // setSelection(p1, p2-p1); // // url = list; // url.sort(); // // int n = 100; // Q3PopupMenu *rm = new Q3PopupMenu(this); //= new QPopupMenu(pm); // connect(rm, SIGNAL(activated(int)), SLOT(resourceMenuActivated(int))); // // rm->insertItem(tr("Recipient Default"), n++); // // if(!list.isEmpty()) { // rm->addSeparator(); // // for(UserResourceList::ConstIterator it = url.begin(); it != url.end(); ++it) { // const UserResource &r = *it; // QString name; // if(r.name().isEmpty()) // name = QObject::tr("[blank]"); // else // name = r.name(); // // rm->insertItem(PsiIconset::instance()->status(r.status()), name, n++); // } // } // // //pm->insertItem("Change Resource", rm, -1, 0); // //pm->insertSeparator(1); // // return rm; //} void ELineEdit::resourceMenuActivated(int x) { if(x < 100) return; QString name; if(x == 100) name = ""; else { int n = 101; for(UserResourceList::ConstIterator it = url.begin(); it != url.end(); ++it) { if(n == x) { name = (*it).name(); break; } ++n; } } url.clear(); changeResource(name); } //---------------------------------------------------------------------------- // AttachView //---------------------------------------------------------------------------- class AttachViewItem : public QListWidgetItem { public: AttachViewItem(const QString &_url, const QString &_desc, AttachView *par) :QListWidgetItem(par) { type = 0; url = _url; desc = _desc; setIcon(IconsetFactory::icon("psi/www").icon()); setText(url + " (" + desc + ')'); // setMultiLinesEnabled(true); } AttachViewItem(const QString &_gc, const QString& from, const QString& reason, const QString& _password, AttachView *par) :QListWidgetItem(par) { type = 1; gc = _gc; password = _password; setIcon(IconsetFactory::icon("psi/groupChat").icon()); QString text; if (!from.isEmpty()) text = QObject::tr("Invitation to %1 from %2").arg(gc).arg(from); else text = QObject::tr("Invitation to %1").arg(gc); if (!reason.isEmpty()) { text += QString(" (%1)").arg(reason); } setText(text); // setMultiLinesEnabled(true); } int rtti() const { return 9100; } QString url, desc; QString gc, password; int type; }; AttachView::AttachView(QWidget* parent) : QListWidget(parent) { v_readOnly = false; // addColumn(tr("Attachments")); // setResizeMode(QListWidget::AllColumns); connect(this, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(qlv_doubleClicked(QListWidgetItem *))); }; AttachView::~AttachView() { } void AttachView::setReadOnly(bool b) { v_readOnly = b; } void AttachView::urlAdd(const QString &url, const QString &desc) { new AttachViewItem(url, desc, this); childCountChanged(); } void AttachView::gcAdd(const QString &gc, const QString& from, const QString& reason, const QString& password) { new AttachViewItem(gc, from, reason, password, this); childCountChanged(); } void AttachView::contextMenuEvent(QContextMenuEvent* e) { AttachViewItem* i = !selectedItems().isEmpty() ? static_cast(selectedItems().first()) : 0; if(!i) return; QAction* goToUrlAction = 0; QAction* copyLocationAction = 0; QAction* joinGroupChatAction = 0; QAction* removeAction = 0; QMenu pm(this); if(i->type == 0) { goToUrlAction = pm.addAction(tr("Go to &URL...")); copyLocationAction = pm.addAction(tr("Copy location")); } else { joinGroupChatAction = pm.addAction(tr("Join &Groupchat...")); } pm.addSeparator(); removeAction = pm.addAction(tr("Remove")); if(v_readOnly) { removeAction->setEnabled(false); } QAction* n = pm.exec(e->globalPos()); if(!n) return; if(n == goToUrlAction) { goURL(i->url); } else if(n == joinGroupChatAction) { actionGCJoin(i->gc, i->password); } else if(n == copyLocationAction) { QApplication::clipboard()->setText(i->url, QClipboard::Clipboard); if(QApplication::clipboard()->supportsSelection()) QApplication::clipboard()->setText(i->url, QClipboard::Selection); } else if(n == removeAction) { takeItem(row(i)); delete i; childCountChanged(); } } void AttachView::qlv_doubleClicked(QListWidgetItem *lvi) { AttachViewItem *i = (AttachViewItem *)lvi; if(!i) return; if(i->type == 0) goURL(i->url); else actionGCJoin(i->gc, i->password); } void AttachView::goURL(const QString &_url) { if(_url.isEmpty()) return; QString url = _url; if(url.indexOf("://") == -1) url.insert(0, "http://"); DesktopUtil::openUrl(url); } UrlList AttachView::urlList() const { UrlList list; for (int index = 0; index < count(); ++index) { AttachViewItem* i = static_cast(item(index)); list += Url(i->url, i->desc); } return list; } void AttachView::addUrlList(const UrlList &list) { for(QList::ConstIterator it = list.begin(); it != list.end(); ++it) { const Url &u = *it; urlAdd(u.url(), u.desc()); } } //---------------------------------------------------------------------------- // AddUrlDlg //---------------------------------------------------------------------------- AddUrlDlg::AddUrlDlg(QWidget *parent) :QDialog(parent) { if ( PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool() ) setAttribute(Qt::WA_MacMetalStyle); setupUi(this); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/www").icon()); #endif setModal(true); connect(pb_close, SIGNAL(clicked()), SLOT(reject())); connect(pb_ok, SIGNAL(clicked()), SLOT(accept())); } AddUrlDlg::~AddUrlDlg() { } //---------------------------------------------------------------------------- // EventDlg - a window to read and write events //---------------------------------------------------------------------------- class EventDlg::Private : public QObject { Q_OBJECT public: Private(EventDlg *d) { dlg = d; nextAnim_ = 0; } ~Private() { setNextAnim(0); } void setNextAnim(PsiIcon *anim) { if (nextAnim_) { delete nextAnim_; nextAnim_ = 0; } if (anim) nextAnim_ = new AlertIcon(anim); } PsiIcon *nextAnim() const { return nextAnim_; } EventDlg *dlg; PsiCon *psi; PsiAccount *pa; bool composing; QLabel *lb_identity; AccountsComboBox *cb_ident; QComboBox *cb_type; AccountLabel *lb_ident; QLabel *lb_time; IconLabel *lb_status; ELineEdit *le_to; QLineEdit *le_from, *le_subj; QLabel *lb_count; IconToolButton *tb_url, *tb_info, *tb_history, *tb_pgp, *tb_icon; IconLabel *lb_pgp; bool enc; int transid; IconButton *pb_next; IconButton *pb_close, *pb_quote, *pb_deny, *pb_send, *pb_reply, *pb_chat, *pb_auth, *pb_http_confirm, *pb_http_deny; IconButton *pb_form_submit, *pb_form_cancel; ChatView *mle; AttachView *attachView; QTimer *whois; QString lastWhois; Jid jid, realJid; QString thread; QStringList completionList; PsiIcon *anim; int nextAmount; QWidget *w_http_id; QLineEdit *le_http_id; PsiHttpAuthRequest httpAuthRequest; QWidget *xdata_form; XDataWidget* xdata; QLabel* xdata_instruction; RosterExchangeItems rosterExchangeItems; bool urlOnShow; Message m; QStringList sendLeft; private: PsiIcon *nextAnim_; private slots: void ensureEditPosition() { QTextCursor cursor = mle->textCursor(); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.clearSelection(); mle->setTextCursor(cursor); } public slots: void addEmoticon(const PsiIcon *icon) { addEmoticon(icon->defaultText()); } void addEmoticon(QString text) { if ( !dlg->isActiveWindow() ) return; PsiRichText::addEmoticon(mle, text); } void updateCounter() { lb_count->setNum(mle->getPlainText().length()); } }; EventDlg::EventDlg(const QString &to, PsiCon *psi, PsiAccount *pa) : AdvancedWidget(0) { setAttribute(Qt::WA_DeleteOnClose); if ( PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool() ) setAttribute(Qt::WA_MacMetalStyle); d = new Private(this); d->composing = true; d->psi = psi; d->pa = 0; d->psi->dialogRegister(this); d->anim = 0; d->nextAmount = 0; d->urlOnShow = false; setAccount(pa); d->whois = new QTimer; connect(d->whois, SIGNAL(timeout()), SLOT(doWhois())); init(); d->cb_ident->setAccount(pa); d->pb_send->show(); d->le_to->setText(expandAddresses(to, false)); d->le_to->setCursorPosition(0); if(PsiOptions::instance()->getOption("options.ui.message.auto-grab-urls-from-clipboard").toBool()) { // url in clipboard? QClipboard *cb = QApplication::clipboard(); QString text = cb->text(QClipboard::Clipboard); if(text.isEmpty() && cb->supportsSelection()) { text = cb->text(QClipboard::Selection); } if(!text.isEmpty()) { if(text.left(7) == "http://") { d->attachView->urlAdd(text, ""); cb->clear(QClipboard::Selection); cb->clear(QClipboard::Clipboard); } } } updateIdentity(pa); X11WM_CLASS("event"); if(d->le_to->text().isEmpty()) d->le_to->setFocus(); else d->mle->setFocus(); if(d->tb_pgp) { UserListItem *u = d->pa->findFirstRelevant(d->jid); if(u && u->isSecure(d->jid.resource())) d->tb_pgp->setChecked(true); } } EventDlg::EventDlg(const Jid &j, PsiAccount *pa, bool unique) : AdvancedWidget(0) { setAttribute(Qt::WA_DeleteOnClose); d = new Private(this); d->composing = false; d->psi = pa->psi(); d->pa = pa; d->jid = j; d->realJid = j; if(unique) d->pa->dialogRegister(this, j); else d->pa->dialogRegister(this); d->anim = 0; d->nextAmount = 0; d->urlOnShow = false; init(); d->le_from->setText(expandAddresses(d->jid.full(), false)); d->le_from->setCursorPosition(0); doWhois(); d->pb_next->show(); d->pb_close->setFocus(); X11WM_CLASS("event"); setTime(QDateTime::currentDateTime(), true); } EventDlg::~EventDlg() { if(d->composing) { delete d->whois; d->psi->dialogUnregister(this); } else { d->pa->dialogUnregister(this); } delete d; } void EventDlg::init() { QVBoxLayout *vb1 = new QVBoxLayout(this); vb1->setMargin(4); vb1->setSpacing(4); // first row QHBoxLayout *hb1 = new QHBoxLayout; hb1->setSpacing(4); vb1->addLayout(hb1); d->lb_identity = new QLabel(tr("Identity:"), this); hb1->addWidget(d->lb_identity); d->enc = false; d->transid = -1; if(d->composing) { d->lb_ident = 0; d->cb_ident = d->psi->accountsComboBox(this); connect(d->cb_ident, SIGNAL(activated(PsiAccount *)), SLOT(updateIdentity(PsiAccount *))); hb1->addWidget(d->cb_ident); } else { d->cb_ident = 0; d->lb_ident = new AccountLabel(this); d->lb_ident->setAccount(d->pa); d->lb_ident->setSizePolicy(QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed )); hb1->addWidget(d->lb_ident); } connect(d->psi, SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility())); updateIdentityVisibility(); // second row QHBoxLayout *hb2 = new QHBoxLayout; hb2->setSpacing(4); vb1->addLayout(hb2); d->lb_status = new IconLabel(this); PsiToolTip::install(d->lb_status); d->lb_status->setPsiIcon(IconsetFactory::iconPtr("status/noauth")); QLabel *l; if(d->composing) { l = new QLabel(tr("To:"), this); hb2->addWidget(l); hb2->addWidget(d->lb_status); d->le_to = new ELineEdit(this); connect(d->le_to, SIGNAL(textChanged(const QString &)), SLOT(to_textChanged(const QString &))); connect(d->le_to, SIGNAL(changeResource(const QString &)), SLOT(to_changeResource(const QString &))); connect(d->le_to, SIGNAL(tryComplete()), SLOT(to_tryComplete())); hb2->addWidget(d->le_to); } else { l = new QLabel(tr("From:"), this); hb2->addWidget(l); hb2->addWidget(d->lb_status); d->le_from = new QLineEdit(this); d->le_from->setReadOnly(true); hb2->addWidget(d->le_from); } if(d->composing) { l = new QLabel(tr("Type:"), this); hb2->addWidget(l); d->cb_type = new QComboBox(this); d->cb_type->addItem(tr("Normal")); d->cb_type->addItem(tr("Chat")); hb2->addWidget(d->cb_type); } else { l = new QLabel(tr("Time:"), this); hb2->addWidget(l); d->lb_time = new QLabel(this); d->lb_time->setFrameStyle( QFrame::Panel | QFrame::Sunken ); hb2->addWidget(d->lb_time); } // icon select //connect(d->psi->iconSelectPopup(), SIGNAL(iconSelected(const PsiIcon *)), d, SLOT(addEmoticon(const PsiIcon *))); connect(d->psi->iconSelectPopup(), SIGNAL(textSelected(QString)), d, SLOT(addEmoticon(QString))); d->tb_icon = new IconToolButton(this); d->tb_icon->setPsiIcon(IconsetFactory::iconPtr("psi/smile")); d->tb_icon->setMenu(d->psi->iconSelectPopup()); d->tb_icon->setPopupMode(QToolButton::InstantPopup); // d->tb_icon->setPopupDelay(1); d->tb_icon->setToolTip(tr("Select icon")); if ( !d->composing ) d->tb_icon->setEnabled(false); // message length counter d->le_subj = new QLineEdit(this); d->lb_count = new QLabel(this); d->lb_count->setToolTip(tr("Message length")); d->lb_count->setFixedWidth(40); d->lb_count->setFrameStyle(QFrame::Panel | QFrame::Sunken); d->lb_count->setAlignment(Qt::AlignRight | Qt::AlignVCenter); d->lb_count->setNum(0); if(d->composing) { d->tb_pgp = new IconToolButton(this); d->tb_pgp->setCheckable(true); d->tb_pgp->setToolTip(tr("Toggle encryption")); d->lb_pgp = 0; } else { d->lb_pgp = new IconLabel(this); d->lb_pgp->setPsiIcon(IconsetFactory::iconPtr("psi/cryptoNo")); d->tb_pgp = 0; } d->tb_url = new IconToolButton(this); connect(d->tb_url, SIGNAL(clicked()), SLOT(addUrl())); d->tb_url->setToolTip(tr("Add URL")); d->tb_info = new IconToolButton(this); connect(d->tb_info, SIGNAL(clicked()), SLOT(doInfo())); d->tb_info->setToolTip(tr("User info")); d->tb_history = new IconToolButton(this); connect(d->tb_history, SIGNAL(clicked()), SLOT(doHistory())); d->tb_history->setToolTip(tr("Message history")); QList toolButtons; toolButtons << d->tb_url << d->tb_info << d->tb_history; if (PsiOptions::instance()->getOption("options.pgp.enable").toBool()) toolButtons << d->tb_pgp; toolButtons << d->tb_icon; foreach (IconToolButton *toolButton, toolButtons) if (toolButton) toolButton->setFocusPolicy(Qt::NoFocus); QHBoxLayout *hb3 = new QHBoxLayout; hb3->setSpacing(4); vb1->addLayout(hb3); // if(d->composing /* && config->showsubject */) { if(PsiOptions::instance()->getOption("options.ui.message.show-subjects").toBool()) { // third row l = new QLabel(tr("Subject:"), this); hb3->addWidget(l); hb3->addWidget(d->le_subj); hb3->addWidget(d->lb_count); hb3->addWidget(d->tb_icon); hb3->addWidget(d->tb_url); hb3->addWidget(d->tb_info); hb3->addWidget(d->tb_history); if(!d->composing) { d->le_subj->setReadOnly(true); d->tb_url->setEnabled(false); hb3->addWidget(d->lb_pgp); } else hb3->addWidget(d->tb_pgp); } else { d->le_subj->hide(); hb2->addWidget(d->lb_count); hb2->addWidget(d->tb_icon); hb2->addWidget(d->tb_url); hb2->addWidget(d->tb_info); hb2->addWidget(d->tb_history); if(d->composing) hb2->addWidget(d->tb_pgp); else hb2->addWidget(d->lb_pgp); } // text area d->mle = new ChatView(this); d->mle->setDialog(this); d->mle->setReadOnly(false); d->mle->setUndoRedoEnabled(true); d->mle->setMinimumHeight(50); vb1->addWidget(d->mle); connect(d->mle, SIGNAL(textChanged()), d, SLOT(updateCounter())); if (d->composing) { d->mle->setAcceptRichText(false); } else { d->mle->setReadOnly(true); d->mle->setUndoRedoEnabled(false); } // attachment view d->attachView = new AttachView(this); d->attachView->setFixedHeight(80); d->attachView->hide(); connect(d->attachView, SIGNAL(childCountChanged()), SLOT(showHideAttachView())); connect(d->attachView, SIGNAL(actionGCJoin(const QString &, const QString&)), SLOT(actionGCJoin(const QString &, const QString&))); vb1->addWidget(d->attachView); if(!d->composing) d->attachView->setReadOnly(true); else QTimer::singleShot(0, d, SLOT(ensureEditPosition())); // http auth transaction id d->w_http_id = new QWidget(this); QHBoxLayout *hb_http_id = new QHBoxLayout(d->w_http_id); hb_http_id->setMargin(0); hb_http_id->setSpacing(4); d->le_http_id = new QLineEdit(d->w_http_id); l = new QLabel(tr("Transaction &identifier:"), d->w_http_id); l->setBuddy(d->le_http_id); hb_http_id->addWidget(l); hb_http_id->addWidget(d->le_http_id); vb1->addWidget(d->w_http_id); d->w_http_id->hide(); // data form d->xdata = new XDataWidget(this); d->xdata_form = new QWidget(this); QVBoxLayout *vb_xdata = new QVBoxLayout(d->xdata_form); d->xdata_instruction = new QLabel(d->xdata_form); vb_xdata->addWidget(d->xdata_instruction); vb_xdata->addWidget(d->xdata); vb1->addWidget(d->xdata_form); d->xdata_form->hide(); // bottom row QHBoxLayout *hb4 = new QHBoxLayout; vb1->addLayout(hb4); d->pb_close = new IconButton(this); d->pb_close->setText(tr("&Close")); connect(d->pb_close, SIGNAL(clicked()), SLOT(close())); d->pb_close->setMinimumWidth(80); hb4->addWidget(d->pb_close); hb4->addStretch(1); d->pb_next = new IconButton(this); connect(d->pb_next, SIGNAL(clicked()), SLOT(doReadNext())); d->pb_next->setText(tr("&Next")); d->pb_next->hide(); d->pb_next->setMinimumWidth(96); d->pb_next->setEnabled(false); hb4->addWidget(d->pb_next); d->pb_quote = new IconButton(this); d->pb_quote->setText(tr("&Quote")); connect(d->pb_quote, SIGNAL(clicked()), SLOT(doQuote())); d->pb_quote->hide(); d->pb_quote->setMinimumWidth(96); hb4->addWidget(d->pb_quote); d->pb_deny = new IconButton(this); d->pb_deny->setText(tr("&Deny")); connect(d->pb_deny, SIGNAL(clicked()), SLOT(doDeny())); d->pb_deny->hide(); d->pb_deny->setMinimumWidth(96); hb4->addWidget(d->pb_deny); d->pb_auth = new IconButton(this); d->pb_auth->setText(tr("&Add/Auth")); connect(d->pb_auth, SIGNAL(clicked()), SLOT(doAuth())); d->pb_auth->setPsiIcon(IconsetFactory::iconPtr("psi/addContact")); d->pb_auth->hide(); d->pb_auth->setMinimumWidth(96); hb4->addWidget(d->pb_auth); d->pb_send = new IconButton(this); d->pb_send->setText(tr("&Send")); connect(d->pb_send, SIGNAL(clicked()), SLOT(doSend())); d->pb_send->hide(); d->pb_send->setMinimumWidth(96); hb4->addWidget(d->pb_send); d->pb_chat = new IconButton(this); d->pb_chat->setText(tr("&Chat")); connect(d->pb_chat, SIGNAL(clicked()), SLOT(doChat())); d->pb_chat->hide(); d->pb_chat->setMinimumWidth(96); hb4->addWidget(d->pb_chat); d->pb_reply = new IconButton(this); d->pb_reply->setText(tr("&Reply")); connect(d->pb_reply, SIGNAL(clicked()), SLOT(doReply())); d->pb_reply->hide(); d->pb_reply->setMinimumWidth(96); hb4->addWidget(d->pb_reply); d->pb_http_confirm = new IconButton(this); d->pb_http_confirm->setText(tr("C&onfirm")); connect(d->pb_http_confirm, SIGNAL(clicked()), SLOT(doHttpConfirm())); d->pb_http_confirm->hide(); d->pb_http_confirm->setMinimumWidth(96); hb4->addWidget(d->pb_http_confirm); d->pb_http_deny = new IconButton(this); d->pb_http_deny->setText(tr("&Deny")); connect(d->pb_http_deny, SIGNAL(clicked()), SLOT(doHttpDeny())); d->pb_http_deny->hide(); d->pb_http_deny->setMinimumWidth(96); hb4->addWidget(d->pb_http_deny); // data form submit button d->pb_form_submit = new IconButton(this); d->pb_form_submit->setText(tr("&Submit")); connect(d->pb_form_submit, SIGNAL(clicked()), SLOT(doFormSubmit())); d->pb_form_submit->hide(); d->pb_form_submit->setMinimumWidth(96); hb4->addWidget(d->pb_form_submit); // data form cancel button d->pb_form_cancel = new IconButton(this); d->pb_form_cancel->setText(tr("&Cancel")); connect(d->pb_form_cancel, SIGNAL(clicked()), SLOT(doFormCancel())); d->pb_form_cancel->hide(); d->pb_form_cancel->setMinimumWidth(96); hb4->addWidget(d->pb_form_cancel); if (d->composing) setTabOrder(d->le_to, d->le_subj); else setTabOrder(d->le_from, d->le_subj); setTabOrder(d->le_subj, d->mle); updatePGP(); connect(d->pa, SIGNAL(pgpKeyChanged()), SLOT(updatePGP())); connect(d->pa, SIGNAL(encryptedMessageSent(int, bool, int, const QString &)), SLOT(encryptedMessageSent(int, bool, int, const QString &))); if (PsiOptions::instance()->getOption("options.ui.message.size").toSize().isValid()) { resize(PsiOptions::instance()->getOption("options.ui.message.size").toSize()); } else { resize(defaultSize()); } optionsUpdate(); //ShortcutManager::connect("common.close", this, SLOT(close())); ShortcutManager::connect("common.user-info", this, SLOT(doInfo())); ShortcutManager::connect("common.history", this, SLOT(doHistory())); //ShortcutManager::connect("message.send", this, SLOT(doSend())); } void EventDlg::setAccount(PsiAccount *pa) { if(d->pa) disconnect(d->pa, SIGNAL(updatedActivity()), this, SLOT(accountUpdatedActivity())); d->pa = pa; connect(d->pa, SIGNAL(updatedActivity()), this, SLOT(accountUpdatedActivity())); } void EventDlg::updateIdentity(PsiAccount *pa) { if(!pa) { close(); return; } setAccount(pa); buildCompletionList(); doWhois(true); } void EventDlg::updateIdentityVisibility() { bool visible = d->psi->contactList()->enabledAccounts().count() > 1; if (d->cb_ident) d->cb_ident->setVisible(visible); if (d->lb_ident) d->lb_ident->setVisible(visible); d->lb_identity->setVisible(visible); } void EventDlg::accountUpdatedActivity() { // TODO: act on account activity change } QString EventDlg::text() const { return d->mle->getPlainText(); } void EventDlg::setHtml(const QString &s) { d->mle->clear(); d->mle->appendText(s); } void EventDlg::setSubject(const QString &s) { d->le_subj->setText(s); } void EventDlg::setThread(const QString &t) { d->thread = t; } void EventDlg::setUrlOnShow() { d->urlOnShow = true; } PsiAccount *EventDlg::psiAccount() { return d->pa; } QStringList EventDlg::stringToList(const QString &s, bool enc) const { QStringList list; int x1, x2; x1 = 0; x2 = 0; while(1) { // scan along for a comma bool found = false; for(int n = x1; n < (int)s.length(); ++n) { if(s.at(n) == ',') { found = true; x2 = n; break; } } if(!found) x2 = s.length(); QString c = s.mid(x1, (x2-x1)); QString j; if(enc) j = findJidInString(c); else j = c; if(j.isEmpty()) j = c; j = j.trimmed(); //printf("j=[%s]\n", j.latin1()); if(!j.isEmpty()) list += j; if(!found) break; x1 = x2+1; } return list; } QString EventDlg::findJidInString(const QString &s) const { int a = s.indexOf('<'); if(a != -1) { ++a; int b = s.indexOf('>', a); if(b != -1) return JIDUtil::decode822(s.mid(a, b-a)); } return ""; } QString EventDlg::expandAddresses(const QString &in, bool enc) const { //printf("in: [%s]\n", in.latin1()); QString str; QStringList list = stringToList(in, enc); bool first = true; for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { if(!first) str += ", "; first = false; Jid j(*it); QList ul = d->pa->findRelevant(j); if(ul.isEmpty()) { str += j.full(); continue; } UserListItem *u = ul.first(); Jid jid; if(j.resource().isEmpty()) jid = u->jid().full(); else jid = u->jid().withResource(j.resource()); QString name; if(!u->name().isEmpty()) name += u->name() + QString(" <%1>").arg(JIDUtil::encode822(jid.full())); else name = JIDUtil::encode822(jid.full()); str += name; } //printf("expanding: [%s]\n", str.latin1()); return str; } void EventDlg::to_textChanged(const QString &) { d->whois->start(250); } void EventDlg::to_changeResource(const QString &r) { QString str = d->le_to->text(); int start = d->le_to->selectionStart(); // int len = d->le_to->selectedText().length(); if(start == -1) { //printf("bad selection\n"); return; } //printf("selection: [%d,%d]\n", start, len); int p1, p2; QString s = findJid(str, start, &p1, &p2); QString j = findJidInString(s); if(j.isEmpty()) j = s; Jid jid(j); if(!jid.isValid()) { //printf("invalid jid\n"); return; } //printf("s=[%s], j=[%s], p: [%d,%d]\n", s.latin1(), j.latin1(), p1, p2); QString js = jidToString(jid, r); //printf("js=[%s]\n", js.latin1()); /*str.remove(start, len); str.insert(start, js); d->le_to->deselect(); d->le_to->setCursorPosition(0); d->le_to->setText(str); //d->le_to->setCursorPosition(start + js.length());*/ d->le_to->insert(js); } void EventDlg::to_tryComplete() { if(!PsiOptions::instance()->getOption("options.ui.message.use-jid-auto-completion").toBool()) return; QString str = d->le_to->text(); int x = d->le_to->cursorPosition(); int p1, p2; QString s = findJid(str, x, &p1, &p2); if(s.length() < 1 || x != p2) return; for(QStringList::ConstIterator it = d->completionList.begin(); it != d->completionList.end(); ++it) { QString name = *it; if(s.length() > name.length()) continue; bool ok = true; int n; for(n = 0; n < (int)s.length(); ++n) { if(s.at(n).toLower() != name.at(n).toLower()) { ok = false; break; } } name = name.mid(n); if(ok) { d->le_to->insert(name); d->le_to->setCursorPosition(x); d->le_to->setSelection(x, name.length()); break; } } } void EventDlg::buildCompletionList() { d->completionList.clear(); d->completionList += d->pa->jid().full(); foreach(UserListItem* u, *d->pa->userList()) { QString j = u->jid().full(); if(!u->name().isEmpty()) d->completionList += u->name() + " <"+j+'>'; d->completionList += j; } } QString EventDlg::jidToString(const Jid &jid, const QString &r) const { QString name; QList ul = d->pa->findRelevant(jid); if(!ul.isEmpty()) { UserListItem *u = ul.first(); QString j; if(r.isEmpty()) j = u->jid().full(); else j = Jid(u->jid().bare()).withResource(r).full(); if(!u->name().isEmpty()) name = u->name() + QString(" <%1>").arg(JIDUtil::encode822(j)); else name = JIDUtil::encode822(j); } else name = JIDUtil::encode822(jid.full()); return name; } void EventDlg::doWhois(bool force) { QString str; if(d->composing) { str = d->le_to->text(); if(str == d->lastWhois && !force) return; } else { str = d->le_from->text(); } //printf("whois: [%s]\n", str.latin1()); d->lastWhois = str; QStringList list = stringToList(str); bool found = false; if(list.count() == 1) { Jid j(list[0]); d->jid = j; QList ul = d->pa->findRelevant(j); if(!ul.isEmpty()) { d->tb_info->setEnabled(true); d->tb_history->setEnabled(true); found = true; } updateContact(d->jid); } if(!found) { d->jid = ""; d->lb_status->setPsiIcon(IconsetFactory::iconPtr("status/noauth")); d->tb_info->setEnabled(false); d->tb_history->setEnabled(false); setWindowTitle(tr("Send Message")); d->lb_status->setToolTip(QString()); } } UserResourceList EventDlg::getResources(const QString &s) const { UserResourceList list; QString j = findJidInString(s); if(j.isEmpty()) j = s; Jid jid(j); if(!jid.isValid()) return list; QList ul = d->pa->findRelevant(jid); if(!ul.isEmpty()) { UserListItem *u = ul.first(); if(u->isAvailable()) return u->userResourceList(); } return list; } void EventDlg::optionsUpdate() { // update the font QFont f; f.fromString(PsiOptions::instance()->getOption("options.ui.look.font.message").toString()); d->mle->setFont(f); // update status icon doWhois(true); if ( PsiOptions::instance()->getOption("options.ui.message.show-character-count").toBool() && d->composing ) d->lb_count->show(); else d->lb_count->hide(); if ( PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool() ) d->tb_icon->show(); else d->tb_icon->hide(); // tool buttons: not required d->tb_url->setPsiIcon(IconsetFactory::iconPtr("psi/www")); d->tb_info->setPsiIcon(IconsetFactory::iconPtr("psi/vCard")); d->tb_history->setPsiIcon(IconsetFactory::iconPtr("psi/history")); if(d->tb_pgp) { QIcon i; i.addPixmap(IconsetFactory::icon("psi/cryptoNo").impix(), QIcon::Normal, QIcon::Off); i.addPixmap(IconsetFactory::icon("psi/cryptoYes").impix(), QIcon::Normal, QIcon::On); d->tb_pgp->setPsiIcon(0); d->tb_pgp->setIcon(i); } if(d->lb_pgp) d->lb_pgp->setPsiIcon(IconsetFactory::iconPtr(d->enc ? "psi/cryptoYes" : "psi/cryptoNo")); // update the readnext icon if(d->nextAmount > 0) d->pb_next->forceSetPsiIcon(d->nextAnim()); // update the widget icon #ifndef Q_WS_MAC if(d->composing) { setWindowIcon(IconsetFactory::icon("psi/sendMessage").icon()); } else { if(d->anim) setWindowIcon(d->anim->icon()); } #endif } QSize EventDlg::defaultSize() { return QSize(420, 280); } void EventDlg::showEvent(QShowEvent *e) { QWidget::showEvent(e); if(d->urlOnShow) { d->urlOnShow = false; QTimer::singleShot(1, this, SLOT(addUrl())); } } void EventDlg::resizeEvent(QResizeEvent *e) { if(PsiOptions::instance()->getOption("options.ui.remember-window-sizes").toBool()) PsiOptions::instance()->getOption("options.ui.message.size").toSize() = e->size(); } void EventDlg::keyPressEvent(QKeyEvent *e) { // FIXMEKEY QKeySequence key = e->key() + ( e->modifiers() & ~Qt::KeypadModifier); if(ShortcutManager::instance()->shortcuts("common.close").contains(key)) close(); else if(ShortcutManager::instance()->shortcuts("message.send").contains(key)) doSend(); else e->ignore(); } void EventDlg::closeEvent(QCloseEvent *e) { // really lame way of checking if we are encrypting if(!d->mle->isEnabled()) return; e->accept(); } void EventDlg::doSend() { if(!d->composing) return; if(!d->pb_send->isEnabled()) return; if(!d->pa->checkConnected(this)) return; if(d->mle->getPlainText().isEmpty() && d->attachView->count() == 0) { QMessageBox::information(this, tr("Warning"), tr("Please type in a message first.")); return; } QStringList list = stringToList(d->le_to->text()); if(list.isEmpty()) { QMessageBox::warning(this, tr("Warning"), tr("No recipients have been specified!")); return; } Message m; if(d->cb_type->currentIndex() == 0) m.setType(""); else m.setType("chat"); m.setBody(d->mle->getPlainText()); m.setSubject(d->le_subj->text()); m.setUrlList(d->attachView->urlList()); m.setTimeStamp(QDateTime::currentDateTime()); m.setThread(d->thread); if(d->tb_pgp->isChecked()) m.setWasEncrypted(true); d->m = m; d->enc = false; if(d->tb_pgp->isChecked()) { d->le_to->setEnabled(false); d->mle->setEnabled(false); d->enc = true; d->sendLeft = list; trySendEncryptedNext(); } else { if (list.count() > 1 && !d->pa->serverInfoManager()->multicastService().isEmpty() && PsiOptions::instance()->getOption("options.enable-multicast").toBool()) { m.setTo(d->pa->serverInfoManager()->multicastService()); foreach(QString recipient, list) { m.addAddress(Address(XMPP::Address::To, Jid(recipient))); } d->pa->dj_sendMessage(m); } else { for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { m.setTo(Jid(*it)); d->pa->dj_sendMessage(m); } } doneSend(); } } void EventDlg::doneSend() { close(); } void EventDlg::doReadNext() { aReadNext(d->realJid); } void EventDlg::doChat() { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aChat(j); } void EventDlg::doReply() { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aReply(j, "", d->le_subj->text(), d->thread); } void EventDlg::doQuote() { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); QString body = TextUtil::rich2plain(d->mle->getHtml()); aReply(j, body, d->le_subj->text(), d->thread); } void EventDlg::doDeny() { if(!d->pa->checkConnected(this)) return; if (d->rosterExchangeItems.isEmpty()) { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aDeny(j); } else { d->rosterExchangeItems.clear(); } close(); } void EventDlg::doAuth() { if(!d->pa->checkConnected(this)) return; if (d->rosterExchangeItems.isEmpty()) { QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aAuth(j); } else { aRosterExchange(d->rosterExchangeItems); d->rosterExchangeItems.clear(); } d->pb_auth->setEnabled(false); closeAfterReply(); } /*! Executed when user wants to confirm a HTTP request. */ void EventDlg::doHttpConfirm() { if(!d->pa->checkConnected(this)) return; if(!d->httpAuthRequest.hasId()) { const QString id = d->le_http_id->text(); if(id.isEmpty()) { QMessageBox::information(this, tr("Warning"), tr("Please type in a transaction identifier first.")); d->le_http_id->setFocus(); return; } else { d->httpAuthRequest.setId(id); } } aHttpConfirm(d->httpAuthRequest); d->le_http_id->setEnabled(false); d->pb_http_confirm->setEnabled(false); d->pb_http_deny->setEnabled(false); closeAfterReply(); } /*! Executed when user wants to deny a HTTP request. */ void EventDlg::doHttpDeny() { if(!d->pa->checkConnected(this)) return; QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); aHttpDeny(d->httpAuthRequest); d->le_http_id->setEnabled(false); d->pb_http_confirm->setEnabled(false); d->pb_http_deny->setEnabled(false); closeAfterReply(); } /*! Executed when user wants to submit a completed form */ void EventDlg::doFormSubmit() { //get original sender QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); //populate the data fields XData data; data.setFields(d->xdata->fields()); //ensure that the user completed all required fields if(!data.isValid()) { QMessageBox::information(this, tr("Warning"), tr("Please complete all required fields (marked with a '*').")); d->xdata_form->setFocus(); return; } data.setType(XData::Data_Submit); aFormSubmit(data, d->thread, j); d->pb_form_submit->setEnabled(false); d->pb_form_cancel->setEnabled(false); closeAfterReply(); } /*! Executed when user wants to cancel a form */ void EventDlg::doFormCancel() { //get original sender QStringList list = stringToList(d->le_from->text()); if(list.isEmpty()) return; Jid j(list[0]); XData data; data.setType(XData::Data_Cancel); aFormCancel(data, d->thread, j); d->pb_form_submit->setEnabled(false); d->pb_form_cancel->setEnabled(false); closeAfterReply(); } void EventDlg::doHistory() { d->pa->actionHistory(d->jid.withResource("")); } void EventDlg::doInfo() { d->pa->actionInfo(d->jid); } void EventDlg::closeAfterReply() { if(d->nextAmount == 0) close(); } void EventDlg::addUrl() { AddUrlDlg *w = new AddUrlDlg(this); int n = w->exec(); if(n != QDialog::Accepted) { delete w; return; } QString url = w->le_url->text(); QString desc = w->le_desc->text(); delete w; d->attachView->urlAdd(url, desc); } void EventDlg::showHideAttachView() { if(d->attachView->count()) { if(d->attachView->isHidden()) d->attachView->show(); } else { if(!d->attachView->isHidden()) d->attachView->hide(); } } void EventDlg::updateContact(const Jid &jid) { if(d->jid.compare(jid, false)) { QString rname = d->jid.resource(); QList ul = d->pa->findRelevant(d->jid); UserListItem *u = 0; int status = -1; if(!ul.isEmpty()) { u = ul.first(); if(rname.isEmpty()) { // use priority if(!u->isAvailable()) status = STATUS_OFFLINE; else status = makeSTATUS((*u->userResourceList().priority()).status()); } else { // use specific UserResourceList::ConstIterator rit = u->userResourceList().find(rname); if(rit != u->userResourceList().end()) status = makeSTATUS((*rit).status()); else status = STATUS_OFFLINE; } } if(status == -1 || !u) d->lb_status->setPsiIcon(IconsetFactory::iconPtr("status/noauth")); else d->lb_status->setPsiIcon(PsiIconset::instance()->statusPtr(jid, status)); if(u) d->lb_status->setToolTip(u->makeTip(true, false)); else d->lb_status->setToolTip(QString()); if(u) setWindowTitle(JIDUtil::nickOrJid(u->name(), u->jid().full())); } } void EventDlg::setTime(const QDateTime &t, bool late) { QString str; //str.sprintf("%02d/%02d %02d:%02d:%02d", t.date().month(), t.date().day(), t.time().hour(), t.time().minute(), t.time().second()); str = QString("") + t.toString(Qt::LocalDate) + ""; if(late) str = QString("") + str + ""; d->lb_time->setText(str); } void EventDlg::updateEvent(PsiEvent *e) { // Default buttons setup d->pb_next->show(); d->pb_chat->show(); d->pb_reply->show(); d->pb_quote->show(); d->pb_close->show(); d->mle->show(); d->pb_auth->hide(); d->pb_deny->hide(); d->pb_form_submit->hide(); d->pb_form_cancel->hide(); d->pb_http_confirm->hide(); d->pb_http_deny->hide(); d->xdata_form->hide(); PsiIcon *oldanim = d->anim; d->anim = PsiIconset::instance()->event2icon(e); if(d->anim != oldanim) setWindowIcon(d->anim->icon()); d->le_from->setText(expandAddresses(e->from().full(), false)); d->le_from->setCursorPosition(0); d->le_from->setToolTip(e->from().full()); setTime(e->timeStamp(), e->late()); d->enc = false; bool showHttpId = false; if (e->type() == PsiEvent::HttpAuth) { HttpAuthEvent *hae = (HttpAuthEvent *)e; const HttpAuthRequest &confirm = hae->request(); QString body(tr( "Someone (maybe you) has requested access to the following resource:\n" "URL: %1\n" "Method: %2\n").arg(confirm.url()).arg(confirm.method())); if (!confirm.hasId()) { body += tr("\n" "If you wish to confirm this request, please provide transaction identifier and press Confirm button. Otherwise press Deny button."); showHttpId = true; } else { body += tr("Transaction identifier: %1\n" "\n" "If you wish to confirm this request, please press Confirm button. " "Otherwise press Deny button.").arg(confirm.id()); } Message m(hae->message()); m.setBody(body); hae->setMessage(m); d->httpAuthRequest = hae->request(); } if (showHttpId) { d->le_http_id->clear(); d->le_http_id->setEnabled(true); d->w_http_id->show(); d->le_http_id->setFocus(); } else { d->w_http_id->hide(); } if(e->type() == PsiEvent::Message || e->type() == PsiEvent::HttpAuth) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); d->enc = m.wasEncrypted(); // HTTP auth request buttons if ( e->type() == PsiEvent::HttpAuth ) { d->pb_chat->hide(); d->pb_reply->hide(); d->pb_quote->hide(); d->pb_http_confirm->setEnabled(true); d->pb_http_confirm->show(); d->pb_http_deny->setEnabled(true); d->pb_http_deny->show(); } bool xhtml = m.containsHTML() && PsiOptions::instance()->getOption("options.html.chat.render").toBool() && !m.html().text().isEmpty(); QString txt = xhtml ? m.html().toString("div") : TextUtil::plain2rich(m.body()); // show subject line if the incoming message has one if(!m.subject().isEmpty() && !PsiOptions::instance()->getOption("options.ui.message.show-subjects").toBool()) txt = "

" + tr("Subject:") + " " + TextUtil::plain2rich(m.subject()) + "

" + (xhtml? "" : "
") + txt; if (!xhtml) { if(PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool()) txt = TextUtil::emoticonify(txt); if( PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool() ) txt = TextUtil::legacyFormat(txt); txt = TextUtil::linkify(txt); } if ( e->type() == PsiEvent::HttpAuth ) txt = "[HTTP Request Confirmation]
" + txt; setHtml("" + txt + ""); d->le_subj->setText(m.subject()); d->le_subj->setCursorPosition(0); d->thread = m.thread(); // Form buttons if (!m.getForm().fields().empty()) { d->pb_chat->hide(); d->pb_reply->hide(); d->pb_quote->hide(); d->pb_close->hide(); d->mle->hide(); //show/enable controls we want d->pb_form_submit->show(); d->pb_form_cancel->show(); d->pb_form_submit->setEnabled(true); d->pb_form_cancel->setEnabled(true); //set title if specified const XData& form = m.getForm(); if ( !form.title().isEmpty() ) setWindowTitle( form.title() ); //show data form d->xdata->setFields( form.fields() ); d->xdata_form->show(); //set instructions QString str = TextUtil::plain2rich( form.instructions() ); d->xdata_instruction->setText(str); } d->attachView->clear(); d->attachView->addUrlList(m.urlList()); if(!m.mucInvites().isEmpty()) { MUCInvite i = m.mucInvites().first(); d->attachView->gcAdd(m.from().full(),i.from().bare(),i.reason(),m.mucPassword()); } else if(!m.invite().isEmpty()) d->attachView->gcAdd(m.invite()); showHideAttachView(); } else if(e->type() == PsiEvent::Auth) { AuthEvent *ae = (AuthEvent *)e; QString type = ae->authType(); d->le_subj->setText(""); if(type == "subscribe") { QString body(tr("[System Message]
This user wants to subscribe to your presence. Click the button labelled \"Add/Auth\" to authorize the subscription. This will also add the person to your contact list if it is not already there.")); setHtml("" + body + ""); d->pb_chat->show(); d->pb_reply->hide(); d->pb_quote->hide(); d->pb_auth->setEnabled(true); d->pb_auth->show(); d->pb_deny->show(); d->pb_http_confirm->hide(); d->pb_http_deny->hide(); } else if(type == "subscribed") { QString body(tr("[System Message]
You are now authorized.")); setHtml("" + body + ""); d->pb_auth->hide(); d->pb_deny->hide(); d->pb_chat->show(); d->pb_reply->show(); d->pb_quote->show(); d->pb_http_confirm->hide(); d->pb_http_deny->hide(); } else if(type == "unsubscribed") { QString body(tr("[System Message]
Your authorization has been removed!")); setHtml("" + body + ""); d->pb_auth->hide(); d->pb_deny->hide(); d->pb_chat->show(); d->pb_reply->show(); d->pb_quote->show(); d->pb_http_confirm->hide(); d->pb_http_deny->hide(); } } else if (e->type() == PsiEvent::RosterExchange) { RosterExchangeEvent *re = (RosterExchangeEvent *)e; int additions = 0, deletions = 0, modifications = 0; foreach(RosterExchangeItem item, re->rosterExchangeItems()) { switch(item.action()) { case RosterExchangeItem::Add: additions++; break; case RosterExchangeItem::Delete: deletions++; break; case RosterExchangeItem::Modify: modifications++; break; } } QString action; if (additions > 0) { if (additions > 1) action += QString(tr("%1 additions")).arg(additions); else action += QString(tr("1 addition")); if (deletions > 0 || modifications > 0) action += ", "; } if (deletions > 0) { if (deletions > 1) action += QString(tr("%1 deletions")).arg(deletions); else action += QString(tr("1 deletion")); if (modifications > 0) action += ", "; } if (modifications > 0) { if (modifications > 1) action += QString(tr("%1 modifications")).arg(modifications); else action += QString(tr("1 modification")); } d->le_subj->setText(""); QString body = QString(tr("[System Message]
This user wants to modify your roster (%1). Click the button labelled \"Add/Auth\" to authorize the modification.")).arg(action); setHtml("" + body + ""); d->rosterExchangeItems = re->rosterExchangeItems(); d->pb_chat->show(); d->pb_reply->hide(); d->pb_quote->hide(); d->pb_auth->setEnabled(true); d->pb_auth->show(); d->pb_deny->show(); } d->mle->scrollToTop(); if(d->lb_pgp) d->lb_pgp->setPsiIcon( IconsetFactory::iconPtr(d->enc ? "psi/cryptoYes" : "psi/cryptoNo") ); if(!d->le_subj->text().isEmpty()) d->le_subj->setToolTip(d->le_subj->text()); else d->le_subj->setToolTip(QString()); doWhois(); } void EventDlg::updateReadNext(PsiIcon *nextAnim, int nextAmount) { int oldAmount = d->nextAmount; d->setNextAnim(nextAnim); d->nextAmount = nextAmount; if(nextAmount == 0) { d->setNextAnim(0); d->pb_next->forceSetPsiIcon(0); d->pb_next->setEnabled(false); d->pb_next->setText(tr("&Next")); if(d->pb_reply->isVisibleTo(this) && d->pb_reply->isEnabled()) d->pb_reply->setFocus(); else if(d->pb_auth->isVisibleTo(this)) d->pb_auth->setFocus(); else if(d->w_http_id->isVisibleTo(this)) d->le_http_id->setFocus(); else if(d->pb_http_deny->isVisibleTo(this)) d->pb_http_deny->setFocus(); } else { d->pb_next->setEnabled(true); QString str(tr("&Next")); str += QString(" - %1").arg(nextAmount); d->pb_next->setText(str); d->pb_next->forceSetPsiIcon(d->nextAnim()); if(d->nextAmount > oldAmount) d->pb_next->setFocus(); } } void EventDlg::actionGCJoin(const QString &gc, const QString&) { Jid j(gc); d->pa->actionJoin(j.withResource("")); } void EventDlg::updatePGP() { if(d->tb_pgp) { d->tb_pgp->setEnabled(d->pa->hasPGP()); if(!d->pa->hasPGP()) { d->tb_pgp->setChecked(false); } } } void EventDlg::trySendEncryptedNext() { if(d->sendLeft.isEmpty()) return; Message m = d->m; m.setTo(Jid(d->sendLeft.first())); d->transid = d->pa->sendMessageEncrypted(m); if(d->transid == -1) { d->le_to->setEnabled(true); d->mle->setEnabled(true); d->mle->setFocus(); return; } } void EventDlg::encryptedMessageSent(int x, bool b, int e, const QString &dtext) { if(d->transid == -1) return; if(d->transid != x) return; d->transid = -1; if(b) { // remove the item Jid j(d->sendLeft.takeFirst()); //d->pa->toggleSecurity(j, d->enc); if(d->sendLeft.isEmpty()) { d->le_to->setEnabled(true); d->mle->setEnabled(true); doneSend(); } else { trySendEncryptedNext(); return; } } else { PGPUtil::showDiagnosticText(static_cast(e), dtext); } d->le_to->setEnabled(true); d->mle->setEnabled(true); d->mle->setFocus(); } #include "eventdlg.moc" psi-0.14/src/src.pri0000644000175000017500000002514711305557613012444 0ustar janjanQT += xml network qt3support # modules include($$PWD/protocol/protocol.pri) include($$PWD/irisprotocol/irisprotocol.pri) include($$PWD/privacy/privacy.pri) include($$PWD/capabilities/capabilities.pri) include($$PWD/utilities/utilities.pri) include($$PWD/tabs/tabs.pri) include($$PWD/Certificates/Certificates.pri) # tools # include($$PWD/tools/trayicon/trayicon.pri) include($$PWD/tools/iconset/iconset.pri) include($$PWD/libpsi/tools/idle/idle.pri) include($$PWD/libpsi/tools/systemwatch/systemwatch.pri) include($$PWD/libpsi/tools/zip/zip.pri) include($$PWD/tools/optionstree/optionstree.pri) include($$PWD/libpsi/tools/globalshortcut/globalshortcut.pri) include($$PWD/tools/advwidget/advwidget.pri) include($$PWD/libpsi/tools/spellchecker/spellchecker.pri) include($$PWD/libpsi/dialogs/grepshortcutkeydialog.pri) include($$PWD/libpsi/tools/atomicxmlfile/atomicxmlfile.pri) include($$PWD/libpsi/tools/simplecli/simplecli.pri) # psimedia include($$PWD/psimedia/psimedia.pri) # audio/video calls include($$PWD/avcall/avcall.pri) # Growl mac { contains(DEFINES, HAVE_GROWL) { include($$PWD/libpsi/tools/growlnotifier/growlnotifier.pri) } } # Mac dock mac { include($$PWD/libpsi/tools/mac_dock/mac_dock.pri) } # Tune pep { DEFINES += USE_PEP CONFIG += tc_psifile mac { CONFIG += tc_itunes } windows { CONFIG += tc_winamp } } include($$PWD/tools/tunecontroller/tunecontroller.pri) # Crash use_crash { DEFINES += USE_CRASH include($$PWD/tools/crash/crash.pri) } # AutoUpdater include($$PWD/AutoUpdater/AutoUpdater.pri) # qca qca-static { # QCA DEFINES += QCA_STATIC include($$PWD/../third-party/qca/qca.pri) # QCA-OpenSSL contains(DEFINES, HAVE_OPENSSL) { include($$PWD/../third-party/qca/qca-ossl.pri) } # QCA-SASL contains(DEFINES, HAVE_CYRUSSASL) { include($$PWD/../third-party/qca/qca-cyrus-sasl.pri) } # QCA-GnuPG include($$PWD/../third-party/qca/qca-gnupg.pri) } else { CONFIG += crypto } # Widgets include($$PWD/widgets/widgets.pri) # Google FT google_ft { DEFINES += GOOGLE_FT HEADERS += $$PWD/googleftmanager.h SOURCES += $$PWD/googleftmanager.cpp include(../third-party/libjingle.new/libjingle.pri) } # Jingle jingle { HEADERS += $$PWD/jinglevoicecaller.h SOURCES += $$PWD/jinglevoicecaller.cpp DEFINES += HAVE_JINGLE POSIX JINGLE_CPP = $$PWD/../third-party/libjingle LIBS += -L$$JINGLE_CPP -ljingle_psi INCLUDEPATH += $$JINGLE_CPP contains(DEFINES, HAVE_PORTAUDIO) { LIBS += -framework CoreAudio -framework AudioToolbox } } # include Iris XMPP library include($$PWD/../iris/iris.pri) # Header files HEADERS += \ $$PWD/varlist.h \ $$PWD/jidutil.h \ $$PWD/showtextdlg.h \ $$PWD/profiles.h \ $$PWD/activeprofiles.h \ $$PWD/profiledlg.h \ $$PWD/aboutdlg.h \ $$PWD/desktoputil.h \ $$PWD/fileutil.h \ $$PWD/textutil.h \ $$PWD/pixmaputil.h \ $$PWD/psiaccount.h \ $$PWD/psicon.h \ $$PWD/accountscombobox.h \ $$PWD/psievent.h \ $$PWD/xmlconsole.h \ $$PWD/contactview.h \ $$PWD/psiiconset.h \ $$PWD/applicationinfo.h \ $$PWD/pgpkeydlg.h \ $$PWD/pgputil.h \ $$PWD/pgptransaction.h \ $$PWD/userlist.h \ $$PWD/mainwin.h \ $$PWD/mainwin_p.h \ $$PWD/psitrayicon.h \ $$PWD/rtparse.h \ $$PWD/systeminfo.h \ $$PWD/common.h \ $$PWD/proxy.h \ $$PWD/miniclient.h \ $$PWD/accountmanagedlg.h \ $$PWD/accountadddlg.h \ $$PWD/accountregdlg.h \ $$PWD/accountmodifydlg.h \ $$PWD/changepwdlg.h \ $$PWD/msgmle.h \ $$PWD/statusdlg.h \ $$PWD/statuscombobox.h \ $$PWD/eventdlg.h \ $$PWD/chatdlg.h \ $$PWD/psichatdlg.h \ $$PWD/chatsplitter.h \ $$PWD/chateditproxy.h \ $$PWD/adduserdlg.h \ $$PWD/groupchatdlg.h \ $$PWD/minicmd.h \ $$PWD/mcmdmanager.h \ $$PWD/gcuserview.h \ $$PWD/infodlg.h \ $$PWD/translationmanager.h \ $$PWD/eventdb.h \ $$PWD/historydlg.h \ $$PWD/tipdlg.h \ $$PWD/searchdlg.h \ $$PWD/registrationdlg.h \ $$PWD/psitoolbar.h \ $$PWD/passphrasedlg.h \ $$PWD/vcardfactory.h \ $$PWD/tasklist.h \ $$PWD/discodlg.h \ $$PWD/alerticon.h \ $$PWD/alertable.h \ $$PWD/psipopup.h \ $$PWD/psiapplication.h \ $$PWD/filetransdlg.h \ $$PWD/avatars.h \ $$PWD/actionlist.h \ $$PWD/serverinfomanager.h \ $$PWD/psiactionlist.h \ $$PWD/xdata_widget.h \ $$PWD/statuspreset.h \ $$PWD/lastactivitytask.h \ $$PWD/mucmanager.h \ $$PWD/mucjoindlg.h \ $$PWD/mucconfigdlg.h \ $$PWD/mucaffiliationsmodel.h \ $$PWD/mucaffiliationsproxymodel.h \ $$PWD/mucaffiliationsview.h \ $$PWD/mucreasonseditor.h \ $$PWD/rosteritemexchangetask.h \ $$PWD/mood.h \ $$PWD/moodcatalog.h \ $$PWD/mooddlg.h \ $$PWD/geolocation.h \ $$PWD/physicallocation.h \ $$PWD/urlbookmark.h \ $$PWD/conferencebookmark.h \ $$PWD/bookmarkmanager.h \ $$PWD/pepmanager.h \ $$PWD/pubsubsubscription.h \ $$PWD/rc.h \ $$PWD/psihttpauthrequest.h \ $$PWD/httpauthmanager.h \ $$PWD/ahcommand.h \ $$PWD/pongserver.h \ $$PWD/ahcommandserver.h \ $$PWD/ahcommanddlg.h \ $$PWD/ahcformdlg.h \ $$PWD/ahcexecutetask.h \ $$PWD/ahcservermanager.h \ $$PWD/serverlistquerier.h \ $$PWD/psioptionseditor.h \ $$PWD/psioptions.h \ $$PWD/voicecaller.h \ $$PWD/voicecalldlg.h \ $$PWD/resourcemenu.h \ $$PWD/shortcutmanager.h \ $$PWD/psicontactlist.h \ $$PWD/accountlabel.h \ $$PWD/psiactions.h \ $$PWD/bookmarkmanagedlg.h \ $$PWD/vcardphotodlg.h \ $$PWD/psicli.h HEADERS += tabcompletion.h SOURCES += tabcompletion.cpp HEADERS += mcmdcompletion.h SOURCES += mcmdcompletion.cpp # Source files SOURCES += \ $$PWD/varlist.cpp \ $$PWD/jidutil.cpp \ $$PWD/showtextdlg.cpp \ $$PWD/psi_profiles.cpp \ $$PWD/activeprofiles.cpp \ $$PWD/profiledlg.cpp \ $$PWD/aboutdlg.cpp \ $$PWD/desktoputil.cpp \ $$PWD/fileutil.cpp \ $$PWD/textutil.cpp \ $$PWD/pixmaputil.cpp \ $$PWD/accountscombobox.cpp \ $$PWD/psievent.cpp \ $$PWD/xmlconsole.cpp \ $$PWD/contactview.cpp \ $$PWD/psiiconset.cpp \ $$PWD/applicationinfo.cpp \ $$PWD/pgpkeydlg.cpp \ $$PWD/pgputil.cpp \ $$PWD/pgptransaction.cpp \ $$PWD/serverinfomanager.cpp \ $$PWD/userlist.cpp \ $$PWD/mainwin.cpp \ $$PWD/mainwin_p.cpp \ $$PWD/psitrayicon.cpp \ $$PWD/rtparse.cpp \ $$PWD/systeminfo.cpp \ $$PWD/common.cpp \ $$PWD/proxy.cpp \ $$PWD/miniclient.cpp \ $$PWD/accountmanagedlg.cpp \ $$PWD/accountadddlg.cpp \ $$PWD/accountregdlg.cpp \ $$PWD/accountmodifydlg.cpp \ $$PWD/changepwdlg.cpp \ $$PWD/msgmle.cpp \ $$PWD/statusdlg.cpp \ $$PWD/statuscombobox.cpp \ $$PWD/eventdlg.cpp \ $$PWD/chatdlg.cpp \ $$PWD/psichatdlg.cpp \ $$PWD/chatsplitter.cpp \ $$PWD/chateditproxy.cpp \ $$PWD/tipdlg.cpp \ $$PWD/adduserdlg.cpp \ $$PWD/groupchatdlg.cpp \ $$PWD/mcmdmanager.cpp \ $$PWD/mcmdsimplesite.cpp \ $$PWD/gcuserview.cpp \ $$PWD/infodlg.cpp \ $$PWD/translationmanager.cpp \ $$PWD/eventdb.cpp \ $$PWD/historydlg.cpp \ $$PWD/searchdlg.cpp \ $$PWD/registrationdlg.cpp \ $$PWD/psitoolbar.cpp \ $$PWD/passphrasedlg.cpp \ $$PWD/vcardfactory.cpp \ $$PWD/discodlg.cpp \ $$PWD/alerticon.cpp \ $$PWD/alertable.cpp \ $$PWD/psipopup.cpp \ $$PWD/psiapplication.cpp \ $$PWD/filetransdlg.cpp \ $$PWD/avatars.cpp \ $$PWD/actionlist.cpp \ $$PWD/psiactionlist.cpp \ $$PWD/xdata_widget.cpp \ $$PWD/lastactivitytask.cpp \ $$PWD/statuspreset.cpp \ $$PWD/mucmanager.cpp \ $$PWD/mucjoindlg.cpp \ $$PWD/mucconfigdlg.cpp \ $$PWD/mucaffiliationsmodel.cpp \ $$PWD/mucaffiliationsproxymodel.cpp \ $$PWD/mucaffiliationsview.cpp \ $$PWD/mucreasonseditor.cpp \ $$PWD/rosteritemexchangetask.cpp \ $$PWD/mood.cpp \ $$PWD/moodcatalog.cpp \ $$PWD/mooddlg.cpp \ $$PWD/geolocation.cpp \ $$PWD/physicallocation.cpp \ $$PWD/urlbookmark.cpp \ $$PWD/conferencebookmark.cpp \ $$PWD/bookmarkmanager.cpp \ $$PWD/pepmanager.cpp \ $$PWD/pubsubsubscription.cpp \ $$PWD/rc.cpp \ $$PWD/httpauthmanager.cpp \ $$PWD/ahcommand.cpp \ $$PWD/pongserver.cpp \ $$PWD/ahcommandserver.cpp \ $$PWD/ahcommanddlg.cpp \ $$PWD/ahcformdlg.cpp \ $$PWD/ahcexecutetask.cpp \ $$PWD/ahcservermanager.cpp \ $$PWD/serverlistquerier.cpp \ $$PWD/psioptions.cpp \ $$PWD/psioptionseditor.cpp \ $$PWD/voicecalldlg.cpp \ $$PWD/resourcemenu.cpp \ $$PWD/shortcutmanager.cpp \ $$PWD/psicontactlist.cpp \ $$PWD/psicon.cpp \ $$PWD/psiaccount.cpp \ $$PWD/accountlabel.cpp \ $$PWD/bookmarkmanagedlg.cpp \ $$PWD/vcardphotodlg.cpp whiteboarding { # Whiteboarding support. Still experimental. DEFINES += WHITEBOARDING QT += svg HEADERS += \ $$PWD/sxe/sxemanager.h \ $$PWD/sxe/sxesession.h \ $$PWD/sxe/sxeedit.h \ $$PWD/sxe/sxenewedit.h \ $$PWD/sxe/sxeremoveedit.h \ $$PWD/sxe/sxerecordedit.h \ $$PWD/sxe/sxerecord.h \ $$PWD/whiteboarding/wbmanager.h \ $$PWD/whiteboarding/wbdlg.h \ $$PWD/whiteboarding/wbwidget.h \ $$PWD/whiteboarding/wbscene.h \ $$PWD/whiteboarding/wbitem.h \ $$PWD/whiteboarding/wbnewitem.h \ $$PWD/whiteboarding/wbnewpath.h \ $$PWD/whiteboarding/wbnewimage.h SOURCES += \ $$PWD/sxe/sxemanager.cpp \ $$PWD/sxe/sxesession.cpp \ $$PWD/sxe/sxeedit.cpp \ $$PWD/sxe/sxenewedit.cpp \ $$PWD/sxe/sxeremoveedit.cpp \ $$PWD/sxe/sxerecordedit.cpp \ $$PWD/sxe/sxerecord.cpp \ $$PWD/whiteboarding/wbmanager.cpp \ $$PWD/whiteboarding/wbdlg.cpp \ $$PWD/whiteboarding/wbwidget.cpp \ $$PWD/whiteboarding/wbscene.cpp \ $$PWD/whiteboarding/wbitem.cpp \ $$PWD/whiteboarding/wbnewitem.cpp \ $$PWD/whiteboarding/wbnewpath.cpp \ $$PWD/whiteboarding/wbnewimage.cpp } mac { contains( DEFINES, HAVE_GROWL ) { HEADERS += $$PWD/psigrowlnotifier.h SOURCES += $$PWD/psigrowlnotifier.cpp } include($$PWD/CocoaUtilities/CocoaUtilities.pri) } # Qt Designer interfaces INTERFACES += \ $$PWD/profileopen.ui \ $$PWD/profilemanage.ui \ $$PWD/profilenew.ui \ $$PWD/proxy.ui \ $$PWD/pgpkey.ui \ $$PWD/accountmanage.ui \ $$PWD/accountadd.ui \ $$PWD/accountreg.ui \ $$PWD/accountremove.ui \ $$PWD/accountmodify.ui \ $$PWD/changepw.ui \ $$PWD/addurl.ui \ $$PWD/adduser.ui \ $$PWD/mucjoin.ui \ $$PWD/info.ui \ $$PWD/search.ui \ $$PWD/about.ui \ $$PWD/optioneditor.ui \ $$PWD/passphrase.ui \ $$PWD/mucconfig.ui \ $$PWD/mucreasonseditor.ui \ $$PWD/xmlconsole.ui \ $$PWD/disco.ui \ $$PWD/tip.ui \ $$PWD/filetrans.ui \ $$PWD/mood.ui \ $$PWD/voicecall.ui \ $$PWD/chatdlg.ui \ $$PWD/groupchatdlg.ui \ $$PWD/bookmarkmanage.ui \ $$PWD/ahcommanddlg.ui \ $$PWD/ahcformdlg.ui # options dialog include($$PWD/options/options.pri) # Plugins psi_plugins { DEFINES += PSI_PLUGINS HEADERS += \ $$PWD/pluginmanager.h \ $$PWD/pluginhost.h SOURCES += \ $$PWD/pluginmanager.cpp \ $$PWD/pluginhost.cpp include($$PWD/plugins/plugins.pri) } dbus { HEADERS += $$PWD/dbus.h SOURCES += $$PWD/dbus.cpp SOURCES += $$PWD/activeprofiles_dbus.cpp DEFINES += USE_DBUS CONFIG += qdbus } win32:!dbus { SOURCES += $$PWD/activeprofiles_win.cpp LIBS += -lUser32 } unix:!dbus { SOURCES += $$PWD/activeprofiles_stub.cpp } mac { QMAKE_LFLAGS += -framework Carbon -framework IOKit -framework AppKit } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD psi-0.14/src/bookmarkmanager.cpp0000644000175000017500000001245411305557613015002 0ustar janjan/* * bookmarkmanager.cpp * Copyright (C) 2006-2008 Remko Troncon, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bookmarkmanager.h" #include "xmpp_task.h" #include "xmpp_client.h" #include "xmpp_xmlcommon.h" #include "psiaccount.h" // ----------------------------------------------------------------------------- class BookmarkTask : public Task { public: BookmarkTask(Task* parent) : Task(parent) { } void set(const QList& urls, const QList& conferences) { iq_ = createIQ(doc(), "set", "", id()); QDomElement prvt = doc()->createElement("query"); prvt.setAttribute("xmlns", "jabber:iq:private"); iq_.appendChild(prvt); QDomElement storage = doc()->createElement("storage"); storage.setAttribute("xmlns", "storage:bookmarks"); prvt.appendChild(storage); foreach(URLBookmark u, urls) storage.appendChild(u.toXml(*doc())); foreach(ConferenceBookmark c, conferences) storage.appendChild(c.toXml(*doc())); } void get() { iq_ = createIQ(doc(), "get", "", id()); QDomElement prvt = doc()->createElement("query"); prvt.setAttribute("xmlns", "jabber:iq:private"); iq_.appendChild(prvt); QDomElement bookmarks = doc()->createElement("storage"); bookmarks.setAttribute("xmlns", "storage:bookmarks"); prvt.appendChild(bookmarks); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (!e.isNull() && e.tagName() == "storage" && e.attribute("xmlns") == "storage:bookmarks") { for (QDomNode m = e.firstChild(); !m.isNull(); m = m.nextSibling()) { QDomElement f = m.toElement(); if (f.isNull()) continue; if (f.tagName() == "url") { URLBookmark u(f); if (!u.isNull()) urls_ += u; } else if (f.tagName() == "conference") { ConferenceBookmark c(f); if (!c.isNull()) conferences_ += c; } } } } setSuccess(); } else { setError(x); } return true; } const QList& urls() const { return urls_; } const QList& conferences() const { return conferences_; } private: QDomElement iq_; QList urls_; QList conferences_; }; // ----------------------------------------------------------------------------- BookmarkManager::BookmarkManager(PsiAccount* account) : account_(account) , accountAvailable_(false) , isAvailable_(false) { connect(account_, SIGNAL(updatedActivity()), SLOT(accountStateChanged())); } bool BookmarkManager::isAvailable() const { return isAvailable_; } void BookmarkManager::setIsAvailable(bool available) { if (available != isAvailable_) { isAvailable_ = available; emit availabilityChanged(); } } QList BookmarkManager::urls() const { return urls_; } QList BookmarkManager::conferences() const { return conferences_; } void BookmarkManager::accountStateChanged() { if (!account_->isAvailable()) { setIsAvailable(false); } if (account_->isAvailable() && !accountAvailable_) { getBookmarks(); } accountAvailable_ = account_->isAvailable(); } void BookmarkManager::getBookmarks() { BookmarkTask* t = new BookmarkTask(account_->client()->rootTask()); connect(t,SIGNAL(finished()),SLOT(getBookmarks_finished())); t->get(); t->go(true); } void BookmarkManager::setBookmarks(const QList& urls, const QList& conferences) { urls_ = urls; conferences_ = conferences; BookmarkTask* t = new BookmarkTask(account_->client()->rootTask()); connect(t,SIGNAL(finished()),SLOT(setBookmarks_finished())); t->set(urls,conferences); t->go(true); } void BookmarkManager::setBookmarks(const QList& urls) { setBookmarks(urls, conferences()); } void BookmarkManager::setBookmarks(const QList& conferences) { setBookmarks(urls(), conferences); } void BookmarkManager::getBookmarks_finished() { BookmarkTask* t = static_cast(sender()); if (t->success()) { bool urlsWereChanged = urls_ != t->urls(); bool conferencesWereChanged = conferences_ != t->conferences(); urls_ = t->urls(); conferences_ = t->conferences(); if (urlsWereChanged) emit urlsChanged(urls_); if (conferencesWereChanged) emit conferencesChanged(conferences_); setIsAvailable(true); } else { setIsAvailable(false); } } void BookmarkManager::setBookmarks_finished() { BookmarkTask* t = static_cast(sender()); Q_UNUSED(t); } psi-0.14/src/dbus.cpp0000644000175000017500000000272211305557613012574 0ustar janjan #include #include #include #include #include #include "common.h" #include "dbus.h" #include "psicontactlist.h" #include "psiaccount.h" #include "activeprofiles.h" #define PSIDBUSIFACE "org.psi_im.Psi" class PsiConAdapter : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.psi_im.Psi.Main") // Q_CLASSINFO("D-Bus Introspection", ...) public: PsiConAdapter(PsiCon *psicon_); ~PsiConAdapter(); public Q_SLOTS: void openURI(QString uri); void setStatus(QString status, QString message); void raise(); void sleep(); void wake(); /*Q_SIGNALS: void psi_pong(); */ private: PsiCon *psicon; }; PsiConAdapter::PsiConAdapter(PsiCon *psicon_) : QDBusAbstractAdaptor(psicon_) { psicon = psicon_; } PsiConAdapter::~PsiConAdapter() {} void PsiConAdapter::openURI(QString uri) { emit ActiveProfiles::instance()->openUriRequested(uri); } void PsiConAdapter::setStatus(QString status, QString message) { emit ActiveProfiles::instance()->setStatusRequested(status, message); } // FIXME libguniqueapp uses activate void PsiConAdapter::raise() { emit ActiveProfiles::instance()->raiseRequested(); } void PsiConAdapter::sleep() { psicon->doSleep(); } void PsiConAdapter::wake() { psicon->doWakeup(); } void addPsiConAdapter(PsiCon *psicon) { new PsiConAdapter(psicon); QDBusConnection::sessionBus().registerObject("/Main", psicon); } #include "dbus.moc" psi-0.14/src/dbus.h0000644000175000017500000000034311305557613012236 0ustar janjan#ifndef PSI_DBUS_H #define PSI_DBUS_H #include "psicon.h" #define PSIDBUSNAME "org.psi-im.Psi" #define PSIDBUSMAINIF "org.psi_im.Psi.Main" bool dbusInit(const QString profile); void addPsiConAdapter(PsiCon *psicon); #endif psi-0.14/src/ahcommand.cpp0000644000175000017500000002272511305557613013573 0ustar janjan/* * ahcommand.cpp - Ad-Hoc Command * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "ahcommand.h" #include "xmpp_xdata.h" #define AHC_NS "http://jabber.org/protocol/commands" #define XMPPSTANZA_NS "urn:ietf:params:xml:ns:xmpp-stanzas" using namespace XMPP; // -------------------------------------------------------------------------- // AHCommand: The class representing an Ad-Hoc command request or reply. // -------------------------------------------------------------------------- AHCommand::AHCommand(const QString& node, const QString& sessionId, Action action) : node_(node), hasData_(false), status_(NoStatus), defaultAction_(NoAction), action_(action), sessionId_(sessionId) { } AHCommand::AHCommand(const QString& node, XData data, const QString& sessionId, Action action) : node_(node), hasData_(true), data_(data), status_(NoStatus), defaultAction_(NoAction), action_(action), sessionId_(sessionId) { } AHCommand::AHCommand(const QDomElement& q) : hasData_(false), defaultAction_(NoAction) { // Parse attributes QString status = q.attribute("status"); setStatus(string2status(status)); node_ = q.attribute("node"); action_ = string2action(q.attribute("action")); sessionId_ = q.attribute("sessionid"); // Parse the body for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (e.isNull()) continue; QString tag = e.tagName(); // A form if (tag == "x" && e.attribute("xmlns") =="jabber:x:data") { data_.fromXml(e); hasData_ = true; } // Actions else if (tag == "actions") { QString execute = e.attribute("execute"); if (!execute.isEmpty()) setDefaultAction(string2action(execute)); for (QDomNode m = e.firstChild(); !m.isNull(); m = m.nextSibling()) { Action a = string2action(m.toElement().tagName()); if (a == Prev || a == Next || a == Complete) actions_ += a; } } } } QDomElement AHCommand::toXml(QDomDocument* doc, bool submit) const { QDomElement command = doc->createElement("command"); command.setAttribute("xmlns", AHC_NS); if (status_ != NoStatus) command.setAttribute("status",status2string(status())); if (hasData()) command.appendChild(data().toXml(doc, submit)); if (action_ != Execute) command.setAttribute("action",action2string(action_)); command.setAttribute("node", node_); if (!sessionId_.isEmpty()) command.setAttribute("sessionid", sessionId_); return command; } AHCommand AHCommand::formReply(const AHCommand& c, const XData& data) { AHCommand r(c.node(), data, c.sessionId()); r.setStatus(AHCommand::Executing); return r; } AHCommand AHCommand::formReply(const AHCommand& c, const XData& data, const QString& sessionId) { AHCommand r(c.node(), data, sessionId); r.setStatus(AHCommand::Executing); return r; } AHCommand AHCommand::canceledReply(const AHCommand& c) { AHCommand r(c.node(), c.sessionId()); r.setStatus(Canceled); return r; } AHCommand AHCommand::completedReply(const AHCommand& c) { AHCommand r(c.node(), c.sessionId()); r.setStatus(Completed); return r; } AHCommand AHCommand::completedReply(const AHCommand& c, const XData& d) { AHCommand r(c.node(), d, c.sessionId()); r.setStatus(Completed); return r; } //AHCommand AHCommand::errorReply(const AHCommand& c, const AHCError& error) //{ // AHCommand r(c.node(), c.sessionId()); // r.setError(error); // return r; //} void AHCommand::setStatus(Status s) { status_ = s; } void AHCommand::setError(const AHCError& e) { error_ = e; } void AHCommand::setDefaultAction(Action a) { defaultAction_ = a; } QString AHCommand::status2string(Status status) { QString s; switch (status) { case Executing : s = "executing"; break; case Completed : s = "completed"; break; case Canceled : s = "canceled"; break; case NoStatus : s = ""; break; } return s; } QString AHCommand::action2string(Action action) { QString s; switch (action) { case Prev : s = "prev"; break; case Next : s = "next"; break; case Cancel : s = "cancel"; break; case Complete : s = "complete"; break; default: break; } return s; } AHCommand::Action AHCommand::string2action(const QString& s) { if (s == "prev") return Prev; else if (s == "next") return Next; else if (s == "complete") return Complete; else if (s == "cancel") return Cancel; else return Execute; } AHCommand::Status AHCommand::string2status(const QString& s) { if (s == "canceled") return Canceled; else if (s == "completed") return Completed; else if (s == "executing") return Executing; else return NoStatus; } // -------------------------------------------------------------------------- // AHCError: The class representing an Ad-Hoc command error // -------------------------------------------------------------------------- AHCError::AHCError(ErrorType t) : type_(t) { } AHCError::AHCError(const QDomElement& e) : type_(None) { QString errorGeneral = "", errorSpecific = ""; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; QString tag = i.tagName(); if ((tag == "bad-request" || tag == "not-allowed" || tag == "forbidden" || tag == "forbidden" || tag == "item-not-found" || tag == "feature-not-implemented") && e.attribute("xmlns") == XMPPSTANZA_NS) { errorGeneral = tag; } else if ((tag == "malformed-action" || tag == "bad-action" || tag == "bad-locale" || tag == "bad-payload" || tag == "bad-sessionid" || tag == "session-expired") && e.attribute("xmlns") == AHC_NS) { errorSpecific = tag; } } type_ = strings2error(errorGeneral, errorSpecific); } QDomElement AHCError::toXml(QDomDocument* doc) const { QDomElement err = doc->createElement("error"); // Error handling if (type_ != None) { QString desc, specificCondition = ""; switch (type_) { case MalformedAction: desc = "bad-request"; specificCondition = "malformed-action"; break; case BadAction: desc = "bad-request"; specificCondition = "bad-action"; break; case BadLocale: desc = "bad-request"; specificCondition = "bad-locale"; break; case BadPayload: desc = "bad-request"; specificCondition = "bad-payload"; break; case BadSessionID: desc = "bad-request"; specificCondition = "bad-sessionid"; break; case SessionExpired: desc = "not-allowed"; specificCondition = "session-expired"; break; case Forbidden: desc = "forbidden"; break; case ItemNotFound: desc = "item-not-found"; break; case FeatureNotImplemented: desc = "feature-not-implemented"; break; case None: break; } // General error condition QDomElement generalElement = doc->createElement(desc); generalElement.setAttribute("xmlns", XMPPSTANZA_NS); err.appendChild(generalElement); // Specific error condition if (!specificCondition.isEmpty()) { QDomElement generalElement = doc->createElement(specificCondition); generalElement.setAttribute("xmlns", AHC_NS); err.appendChild(generalElement); } } return err; } AHCError::ErrorType AHCError::strings2error(const QString& g, const QString& s) { if (s == "malformed-action") return MalformedAction; if (s == "bad-action") return BadAction; if (s == "bad-locale") return BadLocale; if (s == "bad-payload") return BadPayload; if (s == "bad-sessionid") return BadSessionID; if (s == "session-expired") return SessionExpired; if (g == "forbidden") return Forbidden; if (g == "item-not-found") return ItemNotFound; if (g == "feature-not-implemented") return FeatureNotImplemented; return None; } QString AHCError::error2description(const AHCError& e) { QString desc; switch (e.type()) { case MalformedAction: desc = QString("The responding JID does not understand the specified action"); break; case BadAction: desc = QString("The responding JID cannot accept the specified action"); break; case BadLocale: desc = QString("The responding JID cannot accept the specified language/locale"); break; case BadPayload: desc = QString("The responding JID cannot accept the specified payload (eg the data form did not provide one or more required fields)"); break; case BadSessionID: desc = QString("The responding JID cannot accept the specified sessionid"); break; case SessionExpired: desc = QString("The requesting JID specified a sessionid that is no longer active (either because it was completed, canceled, or timed out)"); break; case Forbidden: desc = QString("The requesting JID is not allowed to execute the command"); break; case ItemNotFound: desc = QString("The responding JID cannot find the requested command node"); break; case FeatureNotImplemented: desc = QString("The responding JID does not support Ad-hoc commands"); break; case None: break; } return desc; } psi-0.14/src/psicontactlist.cpp0000644000175000017500000001766611305557613014717 0ustar janjan/* * psicontactlist.cpp - general abstraction of the psi-specific contact list * Copyright (C) 2006 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psicontactlist.h" #include "psiaccount.h" #include "psievent.h" #include "accountadddlg.h" #include "serverinfomanager.h" #include "psicon.h" #include "contactview.h" /** * Constructs new PsiContactList. \param psi will not be PsiContactList's parent though. */ PsiContactList::PsiContactList(PsiCon* psi) : psi_(psi) { } /** * Destroys the PsiContactList along with all PsiAccounts. */ PsiContactList::~PsiContactList() { // PsiAccount calls some signals while being deleted prior to being unlinked, // which in result could cause calls to PsiContactList::accounts() QList toDelete(accounts_); foreach(PsiAccount* account, toDelete) delete account; } /** * Returns pointer to the global Psi Controller. */ PsiCon* PsiContactList::psi() const { return psi_; } /** * Returns list of all accounts if \param enabledOnly is false, * equivalent to enabledAccounts() otherwise. */ const QList& PsiContactList::accounts() const { return accounts_; } /** * Returns list with all enabled accounts. */ const QList& PsiContactList::enabledAccounts() const { return enabledAccounts_; } /** * Returns true, if there are some enabled accounts which are active. */ bool PsiContactList::haveActiveAccounts() const { foreach(PsiAccount* account, enabledAccounts_) if (account->isActive()) return true; return false; } /** * Returns true if enabledAccounts() list is not empty. */ bool PsiContactList::haveEnabledAccounts() const { return !enabledAccounts_.isEmpty(); } /** * At the moment, it returns first enabled account. */ PsiAccount *PsiContactList::defaultAccount() const { if (enabledAccounts_.isEmpty()) { return 0; } return enabledAccounts_.first(); } /** * Creates new PsiAccount based on some initial settings. This is used by AccountAddDlg. */ void PsiContactList::createAccount(const QString& name, const Jid& j, const QString& pass, bool opt_host, const QString& host, int port, bool legacy_ssl_probe, UserAccount::SSLFlag ssl, QString proxyID, const QString &tlsOverrideDomain, const QByteArray &tlsOverrideCert, bool modify) { UserAccount acc; acc.name = name; acc.jid = j.full(); if(!pass.isEmpty()) { acc.opt_pass = true; acc.pass = pass; } acc.opt_host = opt_host; acc.host = host; acc.port = port; acc.ssl = ssl; acc.proxyID = proxyID; acc.legacy_ssl_probe = legacy_ssl_probe; acc.tlsOverrideCert = tlsOverrideCert; acc.tlsOverrideDomain = tlsOverrideDomain; PsiAccount *pa = loadAccount(acc); emit saveAccounts(); // pop up the modify dialog so the user can customize the new account if (modify) pa->modify(); } void PsiContactList::createAccount(const UserAccount& acc) { loadAccount(acc); emit saveAccounts(); } /** * Call this to remove account completely from system. */ void PsiContactList::removeAccount(PsiAccount* account) { emit accountRemoved(account); account->deleteQueueFile(); delete account; emit saveAccounts(); } /** * Obsolete. Call PsiAccount::setEnabled() directly. */ void PsiContactList::setAccountEnabled(PsiAccount* account, bool enabled) { account->setEnabled(enabled); } /** * Counts total number of unread events for all accounts. */ int PsiContactList::queueCount() const { int total = 0; foreach(PsiAccount* account, enabledAccounts_) total += account->eventQueue()->count(); return total; } /** * Finds account with unprocessed event of highest priority, starting with * non-DND accounts. */ PsiAccount* PsiContactList::queueLowestEventId() { PsiAccount *low = 0; // first try to get event from non-dnd account low = tryQueueLowestEventId(false); // if failed, then get the event from dnd account instead if (!low) low = tryQueueLowestEventId(true); return low; } /** * Creates new PsiAccount from \param acc. */ PsiAccount *PsiContactList::loadAccount(const UserAccount& acc) { beginBulkOperation(); PsiAccount *pa = psi_->createAccount(acc); connect(pa, SIGNAL(enabledChanged()), SIGNAL(accountCountChanged())); emit accountAdded(pa); endBulkOperation(); return pa; } /** * Loads accounts from \param list */ void PsiContactList::loadAccounts(const UserAccountList &list) { beginBulkOperation(); foreach(UserAccount account, list) loadAccount(account); endBulkOperation(); } /** * Creates new UserAccountList from all the PsiAccounts ready for saving to disk. */ UserAccountList PsiContactList::getUserAccountList() const { UserAccountList acc; foreach(PsiAccount* account, accounts_) { acc += account->userAccount(); } return acc; } /** * It's called by each and every PsiAccount on its creation. */ void PsiContactList::link(PsiAccount* account) { Q_ASSERT(!accounts_.contains(account)); connect(account, SIGNAL(updatedActivity()), this, SIGNAL(accountActivityChanged())); connect(account->serverInfoManager(),SIGNAL(featuresChanged()), this, SIGNAL(accountFeaturesChanged())); accounts_.append(account); if (account->enabled()) enabledAccounts_.append(account); connect(account, SIGNAL(enabledChanged()), SLOT(accountEnabledChanged())); emit accountCountChanged(); } /** * It's called by each and every PsiAccount on its destruction. */ void PsiContactList::unlink(PsiAccount* account) { Q_ASSERT(accounts_.contains(account)); disconnect(account, SIGNAL(updatedActivity()), this, SIGNAL(accountActivityChanged())); accounts_.removeAll(account); enabledAccounts_.removeAll(account); emit accountCountChanged(); } PsiAccount *PsiContactList::tryQueueLowestEventId(bool includeDND) { PsiAccount *low = 0; int low_id = 0; int low_prior = EventPriorityDontCare; foreach(PsiAccount *account, enabledAccounts_) { int n = account->eventQueue()->nextId(); if ( n == -1 ) continue; if (!includeDND && account->status().type() == XMPP::Status::DND) continue; int p = account->eventQueue()->peekNext()->priority(); if ( !low || (n < low_id && p == low_prior) || p > low_prior ) { low = account; low_id = n; low_prior = p; } } return low; } void PsiContactList::accountEnabledChanged() { PsiAccount* account = (PsiAccount*)sender(); enabledAccounts_.removeAll(account); if (account->enabled()) enabledAccounts_.append(account); } #ifdef NEWCONTACTLIST #error "Don't forget to ditch PsiContactList::beginBulkOperation() and PsiContactList::endBulkOperation()" #endif static int sortColumn = -1; static int operationCount = 0; /** * This function should be called when a big update inside PsiContactList is taking place * to enable optimizations (currently it just turns off the sorting of ContactView). */ void PsiContactList::beginBulkOperation() { operationCount++; if (operationCount == 1) { Q_ASSERT(psi()); Q_ASSERT(psi()->contactView()); sortColumn = psi()->contactView()->sortColumn(); Q_ASSERT(sortColumn != -1); psi()->contactView()->setSorting(-1, true); } } /** * This function should be called when a big update inside PsiContactList is finished * (currently it re-enables the sorting of ContactView). */ void PsiContactList::endBulkOperation() { operationCount--; if (operationCount <= 0) { Q_ASSERT(psi()); Q_ASSERT(psi()->contactView()); Q_ASSERT(sortColumn != -1); psi()->contactView()->setSorting(sortColumn, true); sortColumn = -1; } } psi-0.14/src/searchdlg.cpp0000644000175000017500000002714311305557613013577 0ustar janjan/* * searchdlg.cpp * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include "jidutil.h" #include "psiaccount.h" #include "common.h" #include "xdata_widget.h" #include "xmpp_tasks.h" #include "xmpp_xdata.h" #include "xmpp_xmlcommon.h" #include "textutil.h" #include "searchdlg.h" using namespace XMPP; //---------------------------------------------------------------------------- // JT_XSearch //---------------------------------------------------------------------------- class JT_XSearch : public JT_Search { Q_OBJECT public: JT_XSearch(Task *parent); void setForm(const Form &frm, const XData &_form); bool take(const QDomElement &); QDomElement iq() const; void onGo(); private: QDomElement _iq; }; JT_XSearch::JT_XSearch( Task *parent ) : JT_Search( parent ) { } bool JT_XSearch::take( const QDomElement &x ) { _iq = x; return JT_Search::take( x ); } QDomElement JT_XSearch::iq() const { return _iq; } void JT_XSearch::setForm(const Form &frm, const XData &_form) { JT_Search::set( frm ); _iq = createIQ(doc(), "set", frm.jid().full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:search"); _iq.appendChild(query); XData form( _form ); form.setType( XData::Data_Submit ); query.appendChild( form.toXml( doc() ) ); } void JT_XSearch::onGo() { if ( !_iq.isNull() ) send( _iq ); else JT_Search::onGo(); } //---------------------------------------------------------------------------- // SearchDlg //---------------------------------------------------------------------------- class SearchDlg::Private { public: Private(SearchDlg* _dlg) : dlg(_dlg) {} struct NickAndJid { QString nick; XMPP::Jid jid; }; QList selectedNicksAndJids() const { QList result; int jid; int nick; if (!xdata) { jid = 4; nick = 0; } else { jid = 0; nick = 0; int i = 0; QList::ConstIterator it = xdata_form.report().begin(); for (; it != xdata_form.report().end(); ++it, ++i) { QString name = (*it).name; if (name == "jid") jid = i; if (name == "nickname" || name == "nick" || name == "title") nick = i; } } foreach(QTreeWidgetItem* i, dlg->lv_results->selectedItems()) { NickAndJid nickJid; nickJid.jid = XMPP::Jid(i->text(jid)); nickJid.nick = i->text(nick); result << nickJid; } return result; } SearchDlg* dlg; PsiAccount *pa; Jid jid; Form form; BusyWidget *busy; QPointer jt; QWidget *gr_form; QGridLayout *gr_form_layout; int type; QList lb_field; QList le_field; XDataWidget *xdata; XData xdata_form; }; SearchDlg::SearchDlg(const Jid &jid, PsiAccount *pa) : QDialog(0) { setAttribute(Qt::WA_DeleteOnClose); d = new Private(this); setupUi(this); setModal(false); d->pa = pa; d->jid = jid; d->pa->dialogRegister(this, d->jid); d->jt = 0; d->xdata = 0; setWindowTitle(windowTitle().arg(d->jid.full())); d->busy = busy; d->gr_form = new QWidget(gb_search); d->gr_form_layout = new QGridLayout(d->gr_form); d->gr_form_layout->setSpacing(4); replaceWidget(lb_form, d->gr_form); d->gr_form->hide(); pb_add->setEnabled(false); pb_info->setEnabled(false); pb_stop->setEnabled(false); pb_search->setEnabled(false); connect(lv_results, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged())); connect(lv_results, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(itemActivated(QTreeWidgetItem*, int))); connect(pb_close, SIGNAL(clicked()), SLOT(close())); connect(pb_search, SIGNAL(clicked()), SLOT(doSearchSet())); connect(pb_stop, SIGNAL(clicked()), SLOT(doStop())); connect(pb_add, SIGNAL(clicked()), SLOT(doAdd())); connect(pb_info, SIGNAL(clicked()), SLOT(doInfo())); resize(600,440); doSearchGet(); } SearchDlg::~SearchDlg() { delete d->jt; d->pa->dialogUnregister(this); delete d; } /*void SearchDlg::localUpdate(const JabRosterEntry &e) { int oldstate = localStatus; localStatus = e.localStatus(); if(localStatus == STATUS_OFFLINE) { if(isBusy) { busy->stop(); isBusy = FALSE; } pb_search->setEnabled(FALSE); pb_stop->setEnabled(FALSE); clear(); } else { // coming online? if(oldstate == STATUS_OFFLINE) { pb_search->setEnabled(TRUE); } } }*/ void SearchDlg::addEntry(const QString &jid, const QString &nick, const QString &first, const QString &last, const QString &email) { QTreeWidgetItem* lvi = new QTreeWidgetItem(lv_results); lvi->setText(0, nick); lvi->setText(1, first); lvi->setText(2, last); lvi->setText(3, email); lvi->setText(4, jid); } void SearchDlg::doSearchGet() { lb_instructions->setText(tr("Fetching search form for %1 ...").arg(d->jid.full())); d->busy->start(); d->type = 0; d->jt = new JT_XSearch(d->pa->client()->rootTask()); connect(d->jt, SIGNAL(finished()), SLOT(jt_finished())); d->jt->get(d->jid); d->jt->go(true); } void SearchDlg::doSearchSet() { if(d->busy->isActive()) return; if(!d->pa->checkConnected(this)) return; d->jt = new JT_XSearch(d->pa->client()->rootTask()); if ( !d->xdata ) { Form submitForm = d->form; Q_ASSERT(submitForm.count() == d->le_field.count()); // import the changes back into the form. // the QPtrList of QLineEdits should be in the same order for (int i = 0; i < submitForm.count(); ++i) { submitForm[i].setValue(d->le_field[i]->text()); } d->jt->set(submitForm); } else { XData form; form.setFields( d->xdata->fields() ); d->jt->setForm( d->form, form ); } clear(); pb_search->setEnabled(false); pb_stop->setEnabled(true); d->gr_form->setEnabled(false); d->busy->start(); d->type = 1; connect(d->jt, SIGNAL(finished()), SLOT(jt_finished())); d->jt->go(true); } void SearchDlg::jt_finished() { d->busy->stop(); JT_XSearch *jt = d->jt; d->jt = 0; if(d->type == 1) { d->gr_form->setEnabled(true); pb_search->setEnabled(true); pb_stop->setEnabled(false); } if(jt->success()) { if(d->type == 0) { d->form = jt->form(); bool useXData = false; { QDomNode n = queryTag( jt->iq() ).firstChild(); for( ; !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if( i.attribute( "xmlns" ) == "jabber:x:data" ) { useXData = true; XData form; form.fromXml( i ); //if ( !form.title().isEmpty() ) // setWindowTitle( form.title() ); QString str = TextUtil::plain2rich( form.instructions() ); lb_instructions->setText(str); d->xdata = new XDataWidget( d->gr_form ); d->gr_form_layout->addWidget(d->xdata); // FIXME d->xdata->setFields( form.fields() ); d->xdata->show(); break; } } } if ( !useXData ) { QString str = TextUtil::plain2rich(d->form.instructions()); lb_instructions->setText(str); for(Form::ConstIterator it = d->form.begin(); it != d->form.end(); ++it) { const FormField &f = *it; QLabel *lb = new QLabel(f.fieldName(), d->gr_form); QLineEdit *le = new QLineEdit(d->gr_form); d->gr_form_layout->addWidget(lb); // FIXME d->gr_form_layout->addWidget(le); // FIXME if(f.isSecret()) le->setEchoMode(QLineEdit::Password); le->setText(f.value()); d->lb_field.append(lb); d->le_field.append(le); connect(le, SIGNAL(returnPressed()), this, SLOT(doSearchSet())); } } d->gr_form->show(); pb_search->setEnabled(true); show(); qApp->processEvents(); resize(sizeHint()); } else { lv_results->setUpdatesEnabled(false); if ( !d->xdata ) { const QList &list = jt->results(); if(list.isEmpty()) QMessageBox::information(this, tr("Search Results"), tr("Search returned 0 results.")); else { for(QList::ConstIterator it = list.begin(); it != list.end(); ++it) { const SearchResult &r = *it; addEntry(r.jid().full(), r.nick(), r.first(), r.last(), r.email()); } } } else { XData form; QDomNode n = queryTag( jt->iq() ).firstChild(); for( ; !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if( i.attribute( "xmlns" ) == "jabber:x:data" ) { form.fromXml( i ); break; } } QStringList header_labels; foreach(XData::ReportField report, form.report()) { header_labels << report.label; } lv_results->clear(); lv_results->setColumnCount(0); lv_results->setHeaderLabels(header_labels); foreach(XData::ReportItem ri, form.reportItems()) { int i = 0; QTreeWidgetItem* lvi = new QTreeWidgetItem(lv_results); foreach(XData::ReportField report, form.report()) { lvi->setText(i++, ri[report.name]); } } d->xdata_form = form; } for (int i = 0; i < lv_results->columnCount(); ++i) { lv_results->resizeColumnToContents(i); lv_results->setColumnWidth(i, qMin(lv_results->columnWidth(i), 300)); } lv_results->sortByColumn(0, Qt::AscendingOrder); lv_results->setUpdatesEnabled(true); } } else { if(d->type == 0) { QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve search form.\nReason: %1").arg(jt->statusString())); close(); } else { QMessageBox::critical(this, tr("Error"), tr("Error retrieving search results.\nReason: %1").arg(jt->statusString())); } } } void SearchDlg::clear() { lv_results->clear(); pb_add->setEnabled(false); pb_info->setEnabled(false); } void SearchDlg::doStop() { if(!d->busy->isActive()) return; delete d->jt; d->jt = 0; d->busy->stop(); d->gr_form->setEnabled(true); pb_search->setEnabled(true); pb_stop->setEnabled(false); } void SearchDlg::selectionChanged() { bool enable = !lv_results->selectedItems().isEmpty(); pb_add->setEnabled(enable); pb_info->setEnabled(enable); } void SearchDlg::itemActivated(QTreeWidgetItem* item, int column) { Q_UNUSED(item); Q_UNUSED(column); doInfo(); } void SearchDlg::doAdd() { QList nicksAndJids = d->selectedNicksAndJids(); if (nicksAndJids.isEmpty()) return; foreach(Private::NickAndJid nickJid, nicksAndJids) emit add(nickJid.jid, nickJid.nick, QStringList(), true); if (nicksAndJids.count() > 1) { QMessageBox::information(this, tr("Add User: Success"), tr("Added %n users to your roster.", "", nicksAndJids.count())); } else { QMessageBox::information(this, tr("Add User: Success"), tr("Added %1 to your roster.").arg( JIDUtil::nickOrJid(nicksAndJids.first().nick, nicksAndJids.first().jid.full() ))); } } void SearchDlg::doInfo() { QList nicksAndJids = d->selectedNicksAndJids(); if (nicksAndJids.isEmpty()) return; foreach(Private::NickAndJid nickJid, nicksAndJids) emit aInfo(nickJid.jid); } #include "searchdlg.moc" psi-0.14/src/mucreasonseditor.cpp0000644000175000017500000000167311305557613015231 0ustar janjan#include "mucreasonseditor.h" #include "common.h" #include "psioptions.h" MUCReasonsEditor::MUCReasonsEditor(QWidget* parent) : QDialog(parent) { ui_.setupUi(this); ui_.lstReasons->addItems(PsiOptions::instance()->getOption("options.muc.reasons").toStringList()); } MUCReasonsEditor::~MUCReasonsEditor() { } void MUCReasonsEditor::accept() { QStringList reasons; int cnt=ui_.lstReasons->count(); for (int i=0; iitem(i)->text()); PsiOptions::instance()->setOption("options.muc.reasons", reasons); reason_=ui_.txtReason->text(); QDialog::accept(); } void MUCReasonsEditor::on_btnAdd_clicked() { reason_=ui_.txtReason->text().trimmed(); if (reason_.isEmpty()) return; ui_.lstReasons->addItem(reason_); } void MUCReasonsEditor::on_btnRemove_clicked() { int idx=ui_.lstReasons->currentRow(); if (idx>=0) { QListWidgetItem *item =ui_.lstReasons->takeItem(idx); if (item) delete item; } } psi-0.14/src/avatars.h0000644000175000017500000000556111305557613012751 0ustar janjan/* * avatars.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AVATARS_H #define AVATARS_H #include #include #include #include #include "iconset.h" class PsiAccount; class Avatar; class VCardAvatar; class VCardStaticAvatar; class FileAvatar; class PEPAvatar; namespace XMPP { class Jid; class Resource; class PubSubItem; } using namespace XMPP; //------------------------------------------------------------------------------ class AvatarFactory : public QObject { Q_OBJECT public: AvatarFactory(PsiAccount* pa); QPixmap getAvatar(const Jid& jid); PsiAccount* account() const; void setSelfAvatar(const QString& fileName); void importManualAvatar(const Jid& j, const QString& fileName); void removeManualAvatar(const Jid& j); bool hasManualAvatar(const Jid& j); static QString getManualDir(); static QString getCacheDir(); static int maxAvatarSize(); signals: void avatarChanged(const Jid&); public slots: void updateAvatar(const Jid&); protected slots: void itemPublished(const Jid&, const QString&, const PubSubItem&); void publish_success(const QString&, const PubSubItem&); void resourceAvailable(const Jid&, const Resource&); protected: Avatar* retrieveAvatar(const Jid& jid); private: QByteArray selfAvatarData_; QString selfAvatarHash_; QMap active_avatars_; QMap pep_avatars_; QMap file_avatars_; QMap vcard_avatars_; QMap vcard_static_avatars_; PsiAccount* pa_; Iconset iconset_; }; //------------------------------------------------------------------------------ class Avatar : public QObject { Q_OBJECT public: Avatar(AvatarFactory* factory); virtual ~Avatar(); virtual QPixmap getPixmap() { return pixmap(); } virtual bool isEmpty() { return getPixmap().isNull(); } protected: AvatarFactory* factory() const; virtual const QPixmap& pixmap() const { return pixmap_; } virtual void setImage(const QImage&); virtual void setImage(const QByteArray&); virtual void setImage(const QPixmap&); virtual void resetImage(); private: QPixmap pixmap_; AvatarFactory* factory_; }; #endif psi-0.14/src/irisprotocol/0000755000175000017500000000000011305557613013660 5ustar janjanpsi-0.14/src/irisprotocol/irisprotocol.pri0000644000175000017500000000013311305557613017121 0ustar janjanHEADERS += \ $$PWD/iris_discoinfoquerier.h SOURCES += \ $$PWD/iris_discoinfoquerier.cpp psi-0.14/src/irisprotocol/iris_discoinfoquerier.cpp0000644000175000017500000000143411305557613020766 0ustar janjan#include "irisprotocol/iris_discoinfoquerier.h" #include "xmpp_discoinfotask.h" using namespace XMPP; namespace IrisProtocol { DiscoInfoQuerier::DiscoInfoQuerier(XMPP::Client* client) : client_(client) { } void DiscoInfoQuerier::getDiscoInfo(const XMPP::Jid& jid, const QString& node) { JT_DiscoInfo* disco = new JT_DiscoInfo(client_->rootTask()); connect(disco, SIGNAL(finished()), SLOT(discoFinished())); disco->get(jid, node); disco->go(true); } void DiscoInfoQuerier::discoFinished() { JT_DiscoInfo *disco = (JT_DiscoInfo*)sender(); Q_ASSERT(disco); if (disco->success()) { emit getDiscoInfo_success(disco->jid(), disco->node(), disco->item()); } else { emit getDiscoInfo_error(disco->jid(), disco->node(), disco->statusCode(), disco->statusString()); } } } // namespace psi-0.14/src/irisprotocol/iris_discoinfoquerier.h0000644000175000017500000000103211305557613020425 0ustar janjan#ifndef IRISPROTOCOL_DISCOINFOQUERIER_H #define IRISPROTOCOL_DISCOINFOQUERIER_H #include #include #include "xmpp_client.h" #include "protocol/discoinfoquerier.h" namespace XMPP { class Jid; } namespace IrisProtocol { class DiscoInfoQuerier : public Protocol::DiscoInfoQuerier { Q_OBJECT public: DiscoInfoQuerier(XMPP::Client* client); void getDiscoInfo(const XMPP::Jid& jid, const QString& node); private slots: void discoFinished(); private: QPointer client_; }; } // namespace #endif psi-0.14/src/eventdb.cpp0000644000175000017500000004311011305557613013262 0ustar janjan/* * eventdb.cpp - asynchronous I/O event database * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eventdb.h" #define FAKEDELAY 0 #include #include #include #include #include #include "common.h" #include "applicationinfo.h" #include "psievent.h" #include "jidutil.h" using namespace XMPP; //---------------------------------------------------------------------------- // EDBItem //---------------------------------------------------------------------------- EDBItem::EDBItem(PsiEvent *event, const QString &id, const QString &prevId, const QString &nextId) { e = event; v_id = id; v_prevId = prevId; v_nextId = nextId; } EDBItem::~EDBItem() { delete e; } PsiEvent *EDBItem::event() const { return e; } const QString & EDBItem::id() const { return v_id; } const QString & EDBItem::nextId() const { return v_nextId; } const QString & EDBItem::prevId() const { return v_prevId; } //---------------------------------------------------------------------------- // EDBHandle //---------------------------------------------------------------------------- class EDBHandle::Private { public: Private() {} EDB *edb; EDBResult *r; bool busy; bool writeSuccess; int listeningFor; int lastRequestType; }; EDBHandle::EDBHandle(EDB *edb) :QObject(0) { d = new Private; d->edb = edb; d->r = 0; d->busy = false; d->writeSuccess = false; d->listeningFor = -1; d->lastRequestType = Read; d->edb->reg(this); } EDBHandle::~EDBHandle() { d->edb->unreg(this); delete d->r; delete d; } void EDBHandle::getLatest(const Jid &j, int len) { d->busy = true; d->lastRequestType = Read; d->listeningFor = d->edb->op_getLatest(j, len); } void EDBHandle::getOldest(const Jid &j, int len) { d->busy = true; d->lastRequestType = Read; d->listeningFor = d->edb->op_getOldest(j, len); } void EDBHandle::get(const Jid &j, const QString &id, int direction, int len) { d->busy = true; d->lastRequestType = Read; d->listeningFor = d->edb->op_get(j, id, direction, len); } void EDBHandle::find(const QString &str, const Jid &j, const QString &id, int direction) { d->busy = true; d->lastRequestType = Read; d->listeningFor = d->edb->op_find(str, j, id, direction); } void EDBHandle::append(const Jid &j, PsiEvent *e) { d->busy = true; d->lastRequestType = Write; d->listeningFor = d->edb->op_append(j, e); } void EDBHandle::erase(const Jid &j) { d->busy = true; d->lastRequestType = Erase; d->listeningFor = d->edb->op_erase(j); } bool EDBHandle::busy() const { return d->busy; } const EDBResult *EDBHandle::result() const { return d->r; } bool EDBHandle::writeSuccess() const { return d->writeSuccess; } void EDBHandle::edb_resultReady(EDBResult *r) { d->busy = false; if(r == 0) { delete d->r; d->r = 0; } else { d->r = r; } d->listeningFor = -1; finished(); } void EDBHandle::edb_writeFinished(bool b) { d->busy = false; d->writeSuccess = b; d->listeningFor = -1; finished(); } int EDBHandle::listeningFor() const { return d->listeningFor; } int EDBHandle::lastRequestType() const { return d->lastRequestType; } //---------------------------------------------------------------------------- // EDB //---------------------------------------------------------------------------- class EDB::Private { public: Private() {} QList list; int reqid_base; }; EDB::EDB() { d = new Private; d->reqid_base = 0; } EDB::~EDB() { qDeleteAll(d->list); d->list.clear(); delete d; } int EDB::genUniqueId() const { return d->reqid_base++; } void EDB::reg(EDBHandle *h) { d->list.append(h); } void EDB::unreg(EDBHandle *h) { d->list.removeAll(h); } int EDB::op_getLatest(const Jid &j, int len) { return getLatest(j, len); } int EDB::op_getOldest(const Jid &j, int len) { return getOldest(j, len); } int EDB::op_get(const Jid &jid, const QString &id, int direction, int len) { return get(jid, id, direction, len); } int EDB::op_find(const QString &str, const Jid &j, const QString &id, int direction) { return find(str, j, id, direction); } int EDB::op_append(const Jid &j, PsiEvent *e) { return append(j, e); } int EDB::op_erase(const Jid &j) { return erase(j); } void EDB::resultReady(int req, EDBResult *r) { // deliver foreach(EDBHandle* h, d->list) { if(h->listeningFor() == req) { h->edb_resultReady(r); return; } } delete r; } void EDB::writeFinished(int req, bool b) { // deliver foreach(EDBHandle* h, d->list) { if(h->listeningFor() == req) { h->edb_writeFinished(b); return; } } } //---------------------------------------------------------------------------- // EDBFlatFile //---------------------------------------------------------------------------- struct item_file_req { Jid j; int type; // 0 = latest, 1 = oldest, 2 = random, 3 = write int len; int dir; int id; int eventId; QString findStr; PsiEvent *event; enum Type { Type_getLatest = 0, Type_getOldest, Type_get, Type_append, Type_find, Type_erase }; }; class EDBFlatFile::Private { public: Private() {} QList flist; QList rlist; }; EDBFlatFile::EDBFlatFile() :EDB() { d = new Private; } EDBFlatFile::~EDBFlatFile() { qDeleteAll(d->rlist); qDeleteAll(d->flist); d->flist.clear(); delete d; } int EDBFlatFile::getLatest(const Jid &j, int len) { item_file_req *r = new item_file_req; r->j = j; r->type = item_file_req::Type_getLatest; r->len = len < 1 ? 1: len; r->id = genUniqueId(); d->rlist.append(r); QTimer::singleShot(FAKEDELAY, this, SLOT(performRequests())); return r->id; } int EDBFlatFile::getOldest(const Jid &j, int len) { item_file_req *r = new item_file_req; r->j = j; r->type = item_file_req::Type_getOldest; r->len = len < 1 ? 1: len; r->id = genUniqueId(); d->rlist.append(r); QTimer::singleShot(FAKEDELAY, this, SLOT(performRequests())); return r->id; } int EDBFlatFile::get(const Jid &j, const QString &id, int direction, int len) { item_file_req *r = new item_file_req; r->j = j; r->type = item_file_req::Type_get; r->len = len < 1 ? 1: len; r->dir = direction; r->eventId = id.toInt(); r->id = genUniqueId(); d->rlist.append(r); QTimer::singleShot(FAKEDELAY, this, SLOT(performRequests())); return r->id; } int EDBFlatFile::find(const QString &str, const Jid &j, const QString &id, int direction) { item_file_req *r = new item_file_req; r->j = j; r->type = item_file_req::Type_find; r->len = 1; r->dir = direction; r->findStr = str; r->eventId = id.toInt(); r->id = genUniqueId(); d->rlist.append(r); QTimer::singleShot(FAKEDELAY, this, SLOT(performRequests())); return r->id; } int EDBFlatFile::append(const Jid &j, PsiEvent *e) { item_file_req *r = new item_file_req; r->j = j; r->type = item_file_req::Type_append; r->event = e->copy(); if ( !r->event ) { qWarning("EDBFlatFile::append(): Attempted to append incompatible type."); delete r; return 0; } r->id = genUniqueId(); d->rlist.append(r); QTimer::singleShot(FAKEDELAY, this, SLOT(performRequests())); return r->id; } int EDBFlatFile::erase(const Jid &j) { item_file_req *r = new item_file_req; r->j = j; r->type = item_file_req::Type_erase; r->event = 0; r->id = genUniqueId(); d->rlist.append(r); QTimer::singleShot(FAKEDELAY, this, SLOT(performRequests())); return r->id; } EDBFlatFile::File *EDBFlatFile::findFile(const Jid &j) const { foreach(File* i, d->flist) { if(i->j.compare(j, false)) return i; } return 0; } EDBFlatFile::File *EDBFlatFile::ensureFile(const Jid &j) { File *i = findFile(j); if(!i) { i = new File(Jid(j.bare())); connect(i, SIGNAL(timeout()), SLOT(file_timeout())); d->flist.append(i); } return i; } bool EDBFlatFile::deleteFile(const Jid &j) { File *i = findFile(j); QString fname; if (i) { fname = i->fname; d->flist.removeAll(i); delete i; } else { fname = File::jidToFileName(j); } QFileInfo fi(fname); if(fi.exists()) { QDir dir = fi.dir(); return dir.remove(fi.fileName()); } else return true; } void EDBFlatFile::performRequests() { if(d->rlist.isEmpty()) return; item_file_req *r = d->rlist.takeFirst(); File *f = ensureFile(r->j); int type = r->type; if(type >= item_file_req::Type_getLatest && type <= item_file_req::Type_get) { int id, direction; if(type == item_file_req::Type_getLatest) { direction = Backward; id = f->total()-1; } else if(type == item_file_req::Type_getOldest) { direction = Forward; id = 0; } else if(type == item_file_req::Type_get) { direction = r->dir; id = r->eventId; } else { qWarning("EDBFlatFile::performRequests(): Invalid type."); return; } int len; if(direction == Forward) { if(id + r->len > f->total()) len = f->total() - id; else len = r->len; } else { if((id+1) - r->len < 0) len = id+1; else len = r->len; } EDBResult *result = new EDBResult; result->setAutoDelete(true); for(int n = 0; n < len; ++n) { PsiEvent *e = f->get(id); if(e) { QString prevId, nextId; if(id > 0) prevId = QString::number(id-1); if(id < f->total()-1) nextId = QString::number(id+1); EDBItem *ei = new EDBItem(e, QString::number(id), prevId, nextId); result->append(ei); } if(direction == Forward) ++id; else --id; } resultReady(r->id, result); } else if(type == item_file_req::Type_append) { writeFinished(r->id, f->append(r->event)); delete r->event; } else if(type == item_file_req::Type_find) { int id = r->eventId; EDBResult *result = new EDBResult; result->setAutoDelete(true); while(1) { PsiEvent *e = f->get(id); if(!e) break; QString prevId, nextId; if(id > 0) prevId = QString::number(id-1); if(id < f->total()-1) nextId = QString::number(id+1); if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); if(m.body().indexOf(r->findStr, 0, Qt::CaseInsensitive) != -1) { EDBItem *ei = new EDBItem(e, QString::number(id), prevId, nextId); result->append(ei); break; } } if(r->dir == Forward) ++id; else --id; } resultReady(r->id, result); } else if(type == item_file_req::Type_erase) { writeFinished(r->id, deleteFile(f->j)); } delete r; } void EDBFlatFile::file_timeout() { File *i = (File *)sender(); d->flist.removeAll(i); i->deleteLater(); } //---------------------------------------------------------------------------- // EDBFlatFile::File //---------------------------------------------------------------------------- class EDBFlatFile::File::Private { public: Private() {} QVector index; bool indexed; }; EDBFlatFile::File::File(const Jid &_j) { d = new Private; d->indexed = false; j = _j; valid = false; t = new QTimer(this); connect(t, SIGNAL(timeout()), SLOT(timer_timeout())); //printf("[EDB opening -- %s]\n", j.full().latin1()); fname = jidToFileName(_j); f.setFileName(fname); valid = f.open(QIODevice::ReadWrite); touch(); } EDBFlatFile::File::~File() { if(valid) f.close(); //printf("[EDB closing -- %s]\n", j.full().latin1()); delete d; } QString EDBFlatFile::File::jidToFileName(const XMPP::Jid &j) { return ApplicationInfo::historyDir() + "/" + JIDUtil::encode(j.bare()).toLower() + ".history"; } void EDBFlatFile::File::ensureIndex() { if ( valid && !d->indexed ) { if (f.isSequential()) { qWarning("EDBFlatFile::File::ensureIndex(): Can't index sequential files."); return; } f.reset(); // go to beginning d->index.clear(); //printf(" file: %s\n", fname.latin1()); // build index while(1) { quint64 at = f.pos(); // locate a newline bool found = false; char c; while (f.getChar(&c)) { if (c == '\n') { found = true; break; } } if(!found) break; int oldsize = d->index.size(); d->index.resize(oldsize+1); d->index[oldsize] = at; } d->indexed = true; } else { //printf(" file: can't open\n"); } //printf(" messages: %d\n\n", d->index.size()); } int EDBFlatFile::File::total() const { ((EDBFlatFile::File *)this)->ensureIndex(); return d->index.size(); } void EDBFlatFile::File::touch() { t->start(30000); } void EDBFlatFile::File::timer_timeout() { timeout(); } PsiEvent *EDBFlatFile::File::get(int id) { touch(); if(!valid) return 0; ensureIndex(); if(id < 0 || id > (int)d->index.size()) return 0; f.seek(d->index[id]); QTextStream t; t.setDevice(&f); t.setCodec("UTF-8"); QString line = t.readLine(); return lineToEvent(line); } bool EDBFlatFile::File::append(PsiEvent *e) { touch(); if(!valid) return false; QString line = eventToLine(e); if(line.isEmpty()) return false; f.seek(f.size()); quint64 at = f.pos(); QTextStream t; t.setDevice(&f); t.setCodec("UTF-8"); t << line << endl; f.flush(); if ( d->indexed ) { int oldsize = d->index.size(); d->index.resize(oldsize+1); d->index[oldsize] = at; } return true; } PsiEvent *EDBFlatFile::File::lineToEvent(const QString &line) { // -- read the line -- QString sTime, sType, sOrigin, sFlags, sText, sSubj, sUrl, sUrlDesc; int x1, x2; x1 = line.indexOf('|') + 1; x2 = line.indexOf('|', x1); sTime = line.mid(x1, x2-x1); x1 = x2 + 1; x2 = line.indexOf('|', x1); sType = line.mid(x1, x2-x1); x1 = x2 + 1; x2 = line.indexOf('|', x1); sOrigin = line.mid(x1, x2-x1); x1 = x2 + 1; x2 = line.indexOf('|', x1); sFlags = line.mid(x1, x2-x1); x1 = x2 + 1; // check for extra fields if(sFlags[1] != '-') { int subflags = QString(sFlags[1]).toInt(NULL,16); // have subject? if(subflags & 1) { x2 = line.indexOf('|', x1); sSubj = line.mid(x1, x2-x1); x1 = x2 + 1; } // have url? if(subflags & 2) { x2 = line.indexOf('|', x1); sUrl = line.mid(x1, x2-x1); x1 = x2 + 1; x2 = line.indexOf('|', x1); sUrlDesc = line.mid(x1, x2-x1); x1 = x2 + 1; } } // body text is last sText = line.mid(x1); // -- read end -- int type = sType.toInt(); if(type == 0 || type == 1 || type == 4 || type == 5) { Message m; m.setTimeStamp(QDateTime::fromString(sTime, Qt::ISODate)); if(type == 1) m.setType("chat"); else if(type == 4) m.setType("error"); else if(type == 5) m.setType("headline"); else m.setType(""); bool originLocal = (sOrigin == "to") ? true: false; m.setFrom(j); if(sFlags[0] == 'N') m.setBody(logdecode(sText)); else m.setBody(logdecode(QString::fromUtf8(sText.toLatin1()))); m.setSubject(logdecode(sSubj)); QString url = logdecode(sUrl); if(!url.isEmpty()) m.urlAdd(Url(url, logdecode(sUrlDesc))); m.setSpooled(true); MessageEvent *me = new MessageEvent(m, 0); me->setOriginLocal(originLocal); return me; } else if(type == 2 || type == 3 || type == 6 || type == 7 || type == 8) { QString subType = "subscribe"; if(type == 2) { // stupid "system message" from Psi <= 0.8.6 // try to figure out what kind it REALLY is based on the text if(sText == tr("[System Message]
You are now authorized.")) subType = "subscribed"; else if(sText == tr("[System Message]
Your authorization has been removed!")) subType = "unsubscribed"; } else if(type == 3) subType = "subscribe"; else if(type == 6) subType = "subscribed"; else if(type == 7) subType = "unsubscribe"; else if(type == 8) subType = "unsubscribed"; AuthEvent *ae = new AuthEvent(j, subType, 0); ae->setTimeStamp(QDateTime::fromString(sTime, Qt::ISODate)); return ae; } return NULL; } QString EDBFlatFile::File::eventToLine(PsiEvent *e) { int subflags = 0; QString sTime, sType, sOrigin, sFlags; if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); const UrlList urls = m.urlList(); if(!m.subject().isEmpty()) subflags |= 1; if(!urls.isEmpty()) subflags |= 2; sTime = m.timeStamp().toString(Qt::ISODate); int n = 0; if(m.type() == "chat") n = 1; else if(m.type() == "error") n = 4; else if(m.type() == "headline") n = 5; sType.setNum(n); sOrigin = e->originLocal() ? "to": "from"; sFlags = "N---"; if(subflags != 0) sFlags[1] = QString::number(subflags,16)[0]; // | date | type | To/from | flags | text QString line = "|" + sTime + "|" + sType + "|" + sOrigin + "|" + sFlags + "|"; if(subflags & 1) { line += logencode(m.subject()) + "|"; } if(subflags & 2) { const Url &url = urls.first(); line += logencode(url.url()) + "|"; line += logencode(url.desc()) + "|"; } line += logencode(m.body()); return line; } else if(e->type() == PsiEvent::Auth) { AuthEvent *ae = (AuthEvent *)e; sTime = ae->timeStamp().toString(Qt::ISODate); QString subType = ae->authType(); int n = 0; if(subType == "subscribe") n = 3; else if(subType == "subscribed") n = 6; else if(subType == "unsubscribe") n = 7; else if(subType == "unsubscribed") n = 8; sType.setNum(n); sOrigin = e->originLocal() ? "to": "from"; sFlags = "N---"; // | date | type | To/from | flags | text QString line = "|" + sTime + "|" + sType + "|" + sOrigin + "|" + sFlags + "|"; line += logencode(subType); return line; } return ""; } psi-0.14/src/profilenew.ui0000644000175000017500000001561311305557613013647 0ustar janjan ProfileNew 0 0 459 311 New Profile 11 6 0 7 0 0 200 0 200 32767 Keep your<i> Profile Name</i> simple. It should be a single word comprised of only letters or numbers.<br> <br> The<i> Default Action</i> is what happens when you double click a contact in your list. The choices are<b> Message</b> (ICQ style) and<b> Chat</b> (AIM style). You can change this later from the Options menu.<br> <br> Check the <i>Enable Emoticons</i> checkbox if you'd like text such as <b>:-)</b> to be turned into graphics like <icon name="psi/smile">. true 0 0 6 Profile Name: Default Action 11 6 Message Chat Enable Emoticons 20 131 Expanding Vertical QFrame::HLine QFrame::Sunken 0 95 20 Expanding Horizontal &Close &Create Alt+C false true psi/addContact qPixmapFromMimeSource le_name rb_message rb_chat ck_useEmoticons te_desc psi-0.14/src/alerticon.cpp0000644000175000017500000001427611305557613013626 0ustar janjan/* * alerticon.cpp - class for handling animating alert icons * Copyright (C) 2003 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "alerticon.h" #include "psioptions.h" #include #include //Added by qt3to4: #include //---------------------------------------------------------------------------- // MetaAlertIcon //---------------------------------------------------------------------------- class MetaAlertIcon : public QObject { Q_OBJECT public: MetaAlertIcon(); ~MetaAlertIcon(); Impix blank16() const; int framenumber() const; signals: void updateFrame(int frame); void update(); public slots: void updateAlertStyle(); private slots: void animTimeout(); private: QTimer *animTimer; int frame; Impix _blank16; }; static MetaAlertIcon *metaAlertIcon = 0; MetaAlertIcon::MetaAlertIcon() : QObject(qApp) { animTimer = new QTimer(this); connect(animTimer, SIGNAL(timeout()), SLOT(animTimeout())); animTimer->start(120 * 5); frame = 0; // blank icon QImage blankImg(16, 16, QImage::Format_ARGB32); blankImg.fill(0x00000000); _blank16.setImage(blankImg); } MetaAlertIcon::~MetaAlertIcon() { } Impix MetaAlertIcon::blank16() const { return _blank16; } void MetaAlertIcon::animTimeout() { frame = !frame; emit updateFrame(frame); } void MetaAlertIcon::updateAlertStyle() { emit update(); } int MetaAlertIcon::framenumber() const { return frame; } //---------------------------------------------------------------------------- // AlertIcon::Private //---------------------------------------------------------------------------- class AlertIcon::Private : public QObject { Q_OBJECT public: Private(AlertIcon *_ai); ~Private(); void init(); public slots: void update(); void activated(bool playSound); void stop(); void updateFrame(int frame); void pixmapChanged(); public: AlertIcon *ai; PsiIcon *real; bool isActivated; Impix impix; }; AlertIcon::Private::Private(AlertIcon *_ai) { if ( !metaAlertIcon ) metaAlertIcon = new MetaAlertIcon(); ai = _ai; real = 0; isActivated = false; } AlertIcon::Private::~Private() { if ( isActivated ) stop(); if ( real ) delete real; } void AlertIcon::Private::init() { connect(metaAlertIcon, SIGNAL(update()), SLOT(update())); connect(real, SIGNAL(iconModified()), SLOT(pixmapChanged())); if ( PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "animate" && real->isAnimated() ) impix = real->frameImpix(); else impix = real->impix(); } void AlertIcon::Private::update() { stop(); activated(false); } void AlertIcon::Private::activated(bool playSound) { if ( PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "animate" && real->isAnimated() ) { if ( !isActivated ) { connect(real, SIGNAL(pixmapChanged()), SLOT(pixmapChanged())); real->activated(playSound); isActivated = true; } } else if ( PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "blink" || (PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "animate" && !real->isAnimated()) ) { connect(metaAlertIcon, SIGNAL(updateFrame(int)), SLOT(updateFrame(int))); } else { impix = real->impix(); emit ai->pixmapChanged(); } } void AlertIcon::Private::stop() { disconnect(metaAlertIcon, SIGNAL(updateFrame(int)), this, SLOT(updateFrame(int))); if ( isActivated ) { disconnect(real, SIGNAL(pixmapChanged()), this, SLOT(pixmapChanged())); real->stop(); isActivated = false; } } void AlertIcon::Private::updateFrame(int frame) { if ( !metaAlertIcon ) // just in case metaAlertIcon = new MetaAlertIcon(); if ( frame ) impix = real->impix(); else impix = metaAlertIcon->blank16(); emit ai->pixmapChanged(); } void AlertIcon::Private::pixmapChanged() { impix = real->frameImpix(); emit ai->pixmapChanged(); } //---------------------------------------------------------------------------- // AlertIcon //---------------------------------------------------------------------------- AlertIcon::AlertIcon(const PsiIcon *icon) { d = new Private(this); if ( icon ) d->real = new PsiIcon(*icon); else d->real = new PsiIcon(); d->init(); } AlertIcon::~AlertIcon() { delete d; } bool AlertIcon::isAnimated() const { return d->real->isAnimated(); } const QPixmap &AlertIcon::pixmap() const { return d->impix.pixmap(); } const QImage &AlertIcon::image() const { return d->impix.image(); } void AlertIcon::activated(bool playSound) { d->activated(playSound); } void AlertIcon::stop() { d->stop(); } const QIcon &AlertIcon::icon() const { return d->real->icon(); } const Impix &AlertIcon::impix() const { return d->impix; } int AlertIcon::frameNumber() const { if ( PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "animate" && d->real->isAnimated() ) { return d->real->frameNumber(); } else if ( PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "blink" || (PsiOptions::instance()->getOption("options.ui.notifications.alert-style").toString() == "animate" && !d->real->isAnimated()) ) { return metaAlertIcon->framenumber(); } return 0; } const QString &AlertIcon::name() const { return d->real->name(); } PsiIcon *AlertIcon::copy() const { return new AlertIcon(d->real); } //---------------------------------------------------------------------------- void alertIconUpdateAlertStyle() { if ( !metaAlertIcon ) metaAlertIcon = new MetaAlertIcon(); metaAlertIcon->updateAlertStyle(); } #include "alerticon.moc" psi-0.14/src/varlist.h0000644000175000017500000000360211305557613012766 0ustar janjan/**************************************************************************** ** varlist.h - class for handling a list of string vars ** Copyright (C) 2001, 2002 Justin Karneges ** ** 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 2 ** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA. ** ****************************************************************************/ #ifndef VARLIST_H #define VARLIST_H #include #include class QDomDocument; class QDomElement; class QStringList; class OptionsTree; class VarListItem { public: VarListItem() { } const QString & key() const { return v_key; } const QString & data() const { return v_data; } void setKey(const QString &s) { v_key = s; } void setData(const QString &s) { v_data = s; } private: QString v_key; QString v_data; }; class VarList : public QList { public: VarList(); void set(const QString &, const QString &); void unset(const QString &); const QString & get(const QString &); VarList::Iterator findByKey(const QString &); VarList::Iterator findByNum(int); QStringList varsToStringList(); void fromOptions(OptionsTree *o, QString base); void toOptions(OptionsTree *o, QString base); QDomElement toXml(QDomDocument &doc, const QString &tagName); void fromXml(const QDomElement &); }; #endif psi-0.14/src/infodlg.cpp0000644000175000017500000004744611305557613013275 0ustar janjan/* * infodlg.cpp - handle vcard * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "infodlg.h" #include #include "vcardphotodlg.h" #include #include #include #include #include #include #include #include #include #include #include "msgmle.h" #include "userlist.h" #include "xmpp_vcard.h" #include "xmpp_tasks.h" #include "psiaccount.h" #include "busywidget.h" #include "iconset.h" #include "common.h" #include "lastactivitytask.h" #include "vcardfactory.h" #include "iconwidget.h" #include "contactview.h" #include "psirichtext.h" #include "psioptions.h" #include "fileutil.h" #include "discodlg.h" using namespace XMPP; class InfoDlg::Private { public: Private() {} int type; Jid jid; VCard vcard; PsiAccount *pa; BusyWidget *busy; bool te_edited; int actionType; JT_VCard *jt; bool cacheVCard; QByteArray photo; QList infoRequested; QPointer showPhotoDlg; QPointer namesDlg; QPointer calendar; QString bdayDateFormat; QLineEdit *le_givenname; QLineEdit *le_middlename; QLineEdit *le_familyname; }; InfoDlg::InfoDlg(int type, const Jid &j, const VCard &vcard, PsiAccount *pa, QWidget *parent, bool cacheVCard) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); if ( PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool() ) setAttribute(Qt::WA_MacMetalStyle); ui_.setupUi(this); d = new Private; setModal(false); d->type = type; d->jid = j; d->vcard = vcard; d->pa = pa; d->te_edited = false; d->jt = 0; d->pa->dialogRegister(this, j); d->cacheVCard = cacheVCard; d->busy = ui_.busy; d->bdayDateFormat = "yyyy-MM-dd"; //FIXME make settings for custom date format, but its ISO now ui_.te_desc->setAcceptRichText(false); setWindowTitle(d->jid.full()); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/vCard").icon()); #endif // names editing dialog d->namesDlg = new QDialog(this); QFormLayout *fl = new QFormLayout; d->le_givenname = new QLineEdit(d->namesDlg); d->le_middlename = new QLineEdit(d->namesDlg); d->le_familyname = new QLineEdit(d->namesDlg); fl->addRow(tr("First Name:"), d->le_givenname); fl->addRow(tr("Middle Name:"), d->le_middlename); fl->addRow(tr("Last Name:"), d->le_familyname); d->namesDlg->setLayout(fl); // end names editing dialog QAction *editnames = new QAction(IconsetFactory::icon(d->type == Self?"psi/options":"psi/info").icon(), "", this); ui_.le_fullname->addAction(editnames); ui_.le_fullname->widgetForAction(editnames)->setPopup(d->namesDlg); connect(ui_.pb_refresh, SIGNAL(clicked()), this, SLOT(doRefresh())); connect(ui_.pb_refresh, SIGNAL(clicked()), this, SLOT(updateStatus())); connect(ui_.te_desc, SIGNAL(textChanged()), this, SLOT(textChanged())); connect(ui_.pb_open, SIGNAL(clicked()), this, SLOT(selectPhoto())); connect(ui_.pb_clear, SIGNAL(clicked()), this, SLOT(clearPhoto())); connect(ui_.pb_close, SIGNAL(clicked()), this, SLOT(close())); connect(ui_.tb_photo, SIGNAL(clicked()), SLOT(showPhoto())); connect(ui_.pb_disco, SIGNAL(clicked()), this, SLOT(doDisco())); //connect(editnames, SIGNAL(triggered()), d->namesDlg, SLOT(show())); if(d->type == Self) { d->calendar = new QCalendarWidget(this); d->calendar->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader); QAction *showcal = new QAction(IconsetFactory::icon("psi/options").icon(), "", this); ui_.le_bday->addAction(showcal); ui_.le_bday->widgetForAction(showcal)->setPopup(d->calendar); connect(ui_.pb_submit, SIGNAL(clicked()), this, SLOT(doSubmit())); connect(ui_.le_bday, SIGNAL(textChanged(QString)), this, SLOT(doBDCheck())); connect(d->calendar, SIGNAL(selectionChanged()), this, SLOT(doUpdateFromCalendar())); ui_.pb_disco->hide(); } else { // Hide buttons ui_.pb_submit->hide(); ui_.pb_open->hide(); ui_.pb_clear->hide(); setReadOnly(true); } // Add a status tab connect(d->pa->client(), SIGNAL(resourceAvailable(const Jid &, const Resource &)), SLOT(contactAvailable(const Jid &, const Resource &))); connect(d->pa->client(), SIGNAL(resourceUnavailable(const Jid &, const Resource &)), SLOT(contactUnavailable(const Jid &, const Resource &))); connect(d->pa,SIGNAL(updateContact(const Jid&)),SLOT(contactUpdated(const Jid&))); ui_.te_status->setReadOnly(true); ui_.te_status->setAcceptRichText(true); PsiRichText::install(ui_.te_status->document()); updateStatus(); foreach(UserListItem* u, d->pa->findRelevant(j)) { foreach(UserResource r, u->userResourceList()) { requestClientVersion(d->jid.withResource(r.name())); } if (u->userResourceList().isEmpty() && u->lastAvailable().isNull()) { requestLastActivity(); } } setData(d->vcard); } InfoDlg::~InfoDlg() { d->pa->dialogUnregister(this); delete d; } /** * Redefined so the window does not close when changes are not saved. */ void InfoDlg::closeEvent ( QCloseEvent * e ) { // don't close if submitting if(d->busy->isActive() && d->actionType == 1) { e->ignore(); return; } if(d->type == Self && edited()) { int n = QMessageBox::information(this, tr("Warning"), tr("You have not published your account information changes.\nAre you sure you want to discard them?"), tr("Close and discard"), tr("Don't close")); if(n != 0) { e->ignore(); return; } } // cancel active transaction (refresh only) if(d->busy->isActive() && d->actionType == 0) { delete d->jt; d->jt = 0; } e->accept(); } void InfoDlg::jt_finished() { d->jt = 0; JT_VCard* jtVCard = static_cast (sender()); d->busy->stop(); ui_.pb_refresh->setEnabled(true); ui_.pb_submit->setEnabled(true); ui_.pb_close->setEnabled(true); fieldsEnable(true); if(jtVCard->success()) { if(d->actionType == 0) { d->vcard = jtVCard->vcard(); setData(d->vcard); } else if(d->actionType == 1) { d->vcard = jtVCard->vcard(); if ( d->cacheVCard ) VCardFactory::instance()->setVCard(d->jid, d->vcard); setData(d->vcard); } if(d->jid.compare(d->pa->jid(), false)) { if (!d->vcard.nickName().isEmpty()) d->pa->setNick(d->vcard.nickName()); else d->pa->setNick(d->pa->jid().node()); } if(d->actionType == 1) QMessageBox::information(this, tr("Success"), tr("Your account information has been published.")); } else { if(d->actionType == 0) { if(d->type == Self) QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve your account information. Perhaps you haven't entered any yet.")); else QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve information about this contact.\nReason: %1").arg(jtVCard->statusString())); } else { QMessageBox::critical(this, tr("Error"), tr("Unable to publish your account information.\nReason: %1").arg(jtVCard->statusString())); } } } void InfoDlg::setData(const VCard &i) { d->le_givenname->setText( i.givenName() ); d->le_middlename->setText( i.middleName() ); d->le_familyname->setText( i.familyName() ); ui_.le_nickname->setText( i.nickName() ); ui_.le_bday->setText( i.bdayStr() ); const QString fullName = i.fullName(); if (d->type != Self && fullName.isEmpty()) { ui_.le_fullname->setText( QString("%1 %2 %3") .arg(i.givenName()) .arg(i.middleName()) .arg(i.familyName()) ); } else { ui_.le_fullname->setText( fullName ); } ui_.le_fullname->setToolTip( QString("")+tr("First Name:")+" "+d->vcard.givenName()+"
"+ ""+tr("Middle Name:")+" "+d->vcard.middleName()+"
"+ ""+tr("Last Name:")+" "+d->vcard.familyName() ); QString email; if ( !i.emailList().isEmpty() ) email = i.emailList()[0].userid; ui_.le_email->setText( email ); ui_.le_homepage->setText( i.url() ); QString phone; if ( !i.phoneList().isEmpty() ) phone = i.phoneList()[0].number; ui_.le_phone->setText( phone ); VCard::Address addr; if ( !i.addressList().isEmpty() ) addr = i.addressList()[0]; ui_.le_street->setText( addr.street ); ui_.le_ext->setText( addr.extaddr ); ui_.le_city->setText( addr.locality ); ui_.le_state->setText( addr.region ); ui_.le_pcode->setText( addr.pcode ); ui_.le_country->setText( addr.country ); ui_.le_orgName->setText( i.org().name ); QString unit; if ( !i.org().unit.isEmpty() ) unit = i.org().unit[0]; ui_.le_orgUnit->setText( unit ); ui_.le_title->setText( i.title() ); ui_.le_role->setText( i.role() ); ui_.te_desc->setText( i.desc() ); if ( !i.photo().isEmpty() ) { //printf("There is a picture...\n"); d->photo = i.photo(); if (!updatePhoto()) { clearPhoto(); } } else clearPhoto(); if (d->type == Self) { doBDCheck(); } setEdited(false); } void InfoDlg::showEvent( QShowEvent * event ) { QDialog::showEvent(event); if ( !d->vcard.photo().isEmpty() ) { //printf("There is a picture...\n"); d->photo = d->vcard.photo(); updatePhoto(); } } bool InfoDlg::updatePhoto() { const QImage img(d->photo); if (img.isNull()) { return false; } int max_width = ui_.tb_photo->width() - 10; // FIXME: Ugly magic number int max_height = ui_.tb_photo->height() - 10; // FIXME: Ugly magic number ui_.tb_photo->setIcon(QPixmap::fromImage(img)); ui_.tb_photo->setIconSize(QSize(max_width, max_height)); return true; } void InfoDlg::fieldsEnable(bool x) { ui_.le_fullname->setEnabled(x); d->le_givenname->setEnabled(x); d->le_middlename->setEnabled(x); d->le_familyname->setEnabled(x); ui_.le_nickname->setEnabled(x); ui_.le_bday->setEnabled(x); ui_.le_email->setEnabled(x); ui_.le_homepage->setEnabled(x); ui_.le_phone->setEnabled(x); ui_.pb_open->setEnabled(x); ui_.pb_clear->setEnabled(x); ui_.le_street->setEnabled(x); ui_.le_ext->setEnabled(x); ui_.le_city->setEnabled(x); ui_.le_state->setEnabled(x); ui_.le_pcode->setEnabled(x); ui_.le_country->setEnabled(x); ui_.le_orgName->setEnabled(x); ui_.le_orgUnit->setEnabled(x); ui_.le_title->setEnabled(x); ui_.le_role->setEnabled(x); ui_.te_desc->setEnabled(x); setEdited(false); } void InfoDlg::setEdited(bool x) { ui_.le_fullname->setModified(x); d->le_givenname->setModified(x); d->le_middlename->setModified(x); d->le_familyname->setModified(x); ui_.le_nickname->setModified(x); ui_.le_bday->setModified(x); ui_.le_email->setModified(x); ui_.le_homepage->setModified(x); ui_.le_phone->setModified(x); ui_.le_street->setModified(x); ui_.le_ext->setModified(x); ui_.le_city->setModified(x); ui_.le_state->setModified(x); ui_.le_pcode->setModified(x); ui_.le_country->setModified(x); ui_.le_orgName->setModified(x); ui_.le_orgUnit->setModified(x); ui_.le_title->setModified(x); ui_.le_role->setModified(x); d->te_edited = x; } bool InfoDlg::edited() { bool x = false; if(ui_.le_fullname->isModified()) x = true; if(d->le_givenname->isModified()) x = true; if(d->le_middlename->isModified()) x = true; if(d->le_familyname->isModified()) x = true; if(ui_.le_nickname->isModified()) x = true; if(ui_.le_bday->isModified()) x = true; if(ui_.le_email->isModified()) x = true; if(ui_.le_homepage->isModified()) x = true; if(ui_.le_phone->isModified()) x = true; if(ui_.le_street->isModified()) x = true; if(ui_.le_ext->isModified()) x = true; if(ui_.le_city->isModified()) x = true; if(ui_.le_state->isModified()) x = true; if(ui_.le_pcode->isModified()) x = true; if(ui_.le_country->isModified()) x = true; if(ui_.le_orgName->isModified()) x = true; if(ui_.le_orgUnit->isModified()) x = true; if(ui_.le_title->isModified()) x = true; if(ui_.le_role->isModified()) x = true; if(d->te_edited) x = true; return x; } void InfoDlg::setReadOnly(bool x) { ui_.le_fullname->setReadOnly(x); d->le_givenname->setReadOnly(x); d->le_middlename->setReadOnly(x); d->le_familyname->setReadOnly(x); ui_.le_nickname->setReadOnly(x); //ui_.le_bday->setReadOnly(x); //always read only. use calendar ui_.le_email->setReadOnly(x); ui_.le_homepage->setReadOnly(x); ui_.le_phone->setReadOnly(x); ui_.le_street->setReadOnly(x); ui_.le_ext->setReadOnly(x); ui_.le_city->setReadOnly(x); ui_.le_state->setReadOnly(x); ui_.le_pcode->setReadOnly(x); ui_.le_country->setReadOnly(x); ui_.le_orgName->setReadOnly(x); ui_.le_orgUnit->setReadOnly(x); ui_.le_title->setReadOnly(x); ui_.le_role->setReadOnly(x); ui_.te_desc->setReadOnly(x); } void InfoDlg::doRefresh() { if(!d->pa->checkConnected(this)) return; if(!ui_.pb_refresh->isEnabled()) return; if(d->busy->isActive()) return; ui_.pb_submit->setEnabled(false); ui_.pb_refresh->setEnabled(false); fieldsEnable(false); d->actionType = 0; d->busy->start(); d->jt = VCardFactory::instance()->getVCard(d->jid, d->pa->client()->rootTask(), this, SLOT(jt_finished()), d->cacheVCard); } void InfoDlg::doSubmit() { if(!d->pa->checkConnected(this)) return; if(!ui_.pb_submit->isEnabled()) return; if(d->busy->isActive()) return; VCard submit_vcard = makeVCard(); ui_.pb_submit->setEnabled(false); ui_.pb_refresh->setEnabled(false); ui_.pb_close->setEnabled(false); fieldsEnable(false); d->actionType = 1; d->busy->start(); VCardFactory::instance()->setVCard(d->pa, submit_vcard, this, SLOT(jt_finished())); } void InfoDlg::doDisco() { DiscoDlg* w=new DiscoDlg(d->pa, d->jid, ""); connect(w, SIGNAL(featureActivated(QString, Jid, QString)), d->pa, SLOT(featureActivated(QString, Jid, QString))); w->show(); } void InfoDlg::doUpdateFromCalendar() { const QString textWas = ui_.le_bday->text(); ui_.le_bday->setText(d->calendar->selectedDate().toString(d->bdayDateFormat)); bool changed = textWas != ui_.le_bday->text(); ui_.le_bday->setModified(changed); if (changed) { d->calendar->hide(); } } void InfoDlg::doBDCheck() { const QString bday = ui_.le_bday->text(); const QString bg = (bday.isEmpty() || QDate::fromString(bday, d->bdayDateFormat).isValid())? "none":QColor(255,128,128,255).name(); ui_.le_bday->setStyleSheet("background-color:" + bg); } VCard InfoDlg::makeVCard() { VCard v; v.setFullName( ui_.le_fullname->text() ); v.setGivenName( d->le_givenname->text() ); v.setMiddleName( d->le_middlename->text() ); v.setFamilyName( d->le_familyname->text() ); v.setNickName( ui_.le_nickname->text() ); v.setBdayStr( ui_.le_bday->text() ); if ( !ui_.le_email->text().isEmpty() ) { VCard::Email email; email.internet = true; email.userid = ui_.le_email->text(); VCard::EmailList list; list << email; v.setEmailList( list ); } v.setUrl( ui_.le_homepage->text() ); if ( !ui_.le_phone->text().isEmpty() ) { VCard::Phone p; p.home = true; p.voice = true; p.number = ui_.le_phone->text(); VCard::PhoneList list; list << p; v.setPhoneList( list ); } if ( !d->photo.isEmpty() ) { //printf("Adding a pixmap to the vCard...\n"); v.setPhoto( d->photo ); } if ( !ui_.le_street->text().isEmpty() || !ui_.le_ext->text().isEmpty() || !ui_.le_city->text().isEmpty() || !ui_.le_state->text().isEmpty() || !ui_.le_pcode->text().isEmpty() || !ui_.le_country->text().isEmpty() ) { VCard::Address addr; addr.home = true; addr.street = ui_.le_street->text(); addr.extaddr = ui_.le_ext->text(); addr.locality = ui_.le_city->text(); addr.region = ui_.le_state->text(); addr.pcode = ui_.le_pcode->text(); addr.country = ui_.le_country->text(); VCard::AddressList list; list << addr; v.setAddressList( list ); } VCard::Org org; org.name = ui_.le_orgName->text(); if ( !ui_.le_orgUnit->text().isEmpty() ) org.unit << ui_.le_orgUnit->text(); v.setOrg( org ); v.setTitle( ui_.le_title->text() ); v.setRole( ui_.le_role->text() ); v.setDesc( ui_.te_desc->toPlainText() ); return v; } void InfoDlg::textChanged() { d->te_edited = true; } /** * Opens a file browser dialog, and if selected, calls the setPreviewPhoto with the consecuent path. * \see setPreviewPhoto(const QString& path) */ void InfoDlg::selectPhoto() { QString str = FileUtil::getImageFileName(this); if (!str.isEmpty()) { setPreviewPhoto(str); } } /** * Loads the image from the requested URL, and inserts the resized image into the preview box. * \param path image file to load */ void InfoDlg::setPreviewPhoto(const QString& path) { QFile photo_file(path); if (!photo_file.open(QIODevice::ReadOnly)) return; QByteArray photo_data = photo_file.readAll(); QImage photo_image(photo_data); if(!photo_image.isNull()) { d->photo = photo_data; updatePhoto(); d->te_edited = true; } } /** * Clears the preview image box and marks the te_edited signal in the private. */ void InfoDlg::clearPhoto() { ui_.tb_photo->setIcon(QIcon()); ui_.tb_photo->setText(tr("Picture not\navailable")); d->photo = QByteArray(); // the picture changed, so notify there are some changes done d->te_edited = true; } /** * Updates the status info of the contact */ void InfoDlg::updateStatus() { UserListItem *u = d->pa->find(d->jid); if(u) { PsiRichText::setText(ui_.te_status->document(), u->makeDesc()); } else { ui_.te_status->clear(); } } /** * Sets the visibility of the status tab */ void InfoDlg::setStatusVisibility(bool visible) { // Add/remove tab if necessary int index = ui_.tabwidget->indexOf(ui_.tab_status); if(index==-1) { if(visible) ui_.tabwidget->addTab(ui_.tab_status,tr("Status")); } else if(!visible) { ui_.tabwidget->removeTab(index); } } void InfoDlg::requestClientVersion(const Jid& j) { d->infoRequested += j.full(); JT_ClientVersion *jcv = new JT_ClientVersion(d->pa->client()->rootTask()); connect(jcv, SIGNAL(finished()), SLOT(clientVersionFinished())); jcv->get(j); jcv->go(true); } void InfoDlg::clientVersionFinished() { JT_ClientVersion *j = (JT_ClientVersion *)sender(); if(j->success()) { foreach(UserListItem* u, d->pa->findRelevant(j->jid())) { UserResourceList::Iterator rit = u->userResourceList().find(j->jid().resource()); bool found = (rit == u->userResourceList().end()) ? false: true; if(!found) continue; (*rit).setClient(j->name(),j->version(),j->os()); d->pa->contactProfile()->updateEntry(*u); updateStatus(); } } } void InfoDlg::requestLastActivity() { LastActivityTask *jla = new LastActivityTask(d->jid.bare(),d->pa->client()->rootTask()); connect(jla, SIGNAL(finished()), SLOT(requestLastActivityFinished())); jla->go(true); } void InfoDlg::requestLastActivityFinished() { LastActivityTask *j = (LastActivityTask *)sender(); if(j->success()) { foreach(UserListItem* u, d->pa->findRelevant(d->jid)) { u->setLastUnavailableStatus(makeStatus(STATUS_OFFLINE,j->status())); u->setLastAvailable(j->time()); d->pa->contactProfile()->updateEntry(*u); updateStatus(); } } } void InfoDlg::contactAvailable(const Jid &j, const Resource &r) { if (d->jid.compare(j,false)) { if (!d->infoRequested.contains(j.withResource(r.name()).full())) requestClientVersion(j.withResource(r.name())); } } void InfoDlg::contactUnavailable(const Jid &j, const Resource &r) { if (d->jid.compare(j,false)) { d->infoRequested.removeAll(j.withResource(r.name()).full()); } } void InfoDlg::contactUpdated(const XMPP::Jid & j) { if (d->jid.compare(j,false)) { updateStatus(); } } void InfoDlg::showPhoto() { if (!d->photo.isEmpty()) { QPixmap pixmap; if (!d->showPhotoDlg) { if (pixmap.loadFromData(d->photo)) { d->showPhotoDlg=new ShowPhotoDlg(this, pixmap); d->showPhotoDlg->show(); } } else { ::bringToFront(d->showPhotoDlg); } } } psi-0.14/src/activeprofiles_stub.cpp0000644000175000017500000000356311305557613015717 0ustar janjan/* * activeprofiles_stub.cpp - Class for interacting with other psi instances * Copyright (C) 2006 Maciej Niedzielski * Copyright (C) 2006-2007 Martin Hostettler * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "activeprofiles.h" #include #include bool ActiveProfiles::isActive(const QString &profile) const { Q_UNUSED(profile); return false; } bool ActiveProfiles::isAnyActive() const { return false; } bool ActiveProfiles::setThisProfile(const QString &profile) { Q_UNUSED(profile); return true; } void ActiveProfiles::unsetThisProfile() { } QString ActiveProfiles::thisProfile() const { return QString(); } ActiveProfiles::ActiveProfiles() : QObject(QCoreApplication::instance()) { } ActiveProfiles::~ActiveProfiles() { } bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const { Q_UNUSED(profile); Q_UNUSED(status); Q_UNUSED(message); return true; } bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const { Q_UNUSED(uri); Q_UNUSED(profile); return true; } bool ActiveProfiles::raise(const QString &profile, bool withUI) const { Q_UNUSED(profile); Q_UNUSED(withUI); return true; } psi-0.14/src/psigrowlnotifier.cpp0000644000175000017500000001527411305557613015253 0ustar janjan/* * psigrowlnotifier.cpp: Psi's interface to Growl * Copyright (C) 2005 Remko Troncon * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "common.h" #include "psiaccount.h" #include "avatars.h" #include "growlnotifier.h" #include "psigrowlnotifier.h" #include "psievent.h" #include "userlist.h" /** * A class representing the notification context, which will be passed to * Growl, and then passed back when a notification is clicked. */ class NotificationContext { public: NotificationContext(PsiAccount* a, Jid j) : account_(a), jid_(j), deleteCount_(0) { } PsiAccount* account() { return account_; } Jid jid() { return jid_; } private: PsiAccount* account_; Jid jid_; public: int deleteCount_; }; /** * (Private) constructor of the PsiGrowlNotifier. * Initializes notifications and registers with Growl through GrowlNotifier. */ PsiGrowlNotifier::PsiGrowlNotifier() : QObject(QCoreApplication::instance()) { // Initialize all notifications QStringList nots; nots << QObject::tr("Contact becomes Available"); nots << QObject::tr("Contact becomes Unavailable"); nots << QObject::tr("Contact changes Status"); nots << QObject::tr("Incoming Message"); nots << QObject::tr("Incoming Headline"); nots << QObject::tr("Incoming File"); // Initialize default notifications QStringList defaults; defaults << QObject::tr("Contact becomes Available"); defaults << QObject::tr("Incoming Message"); defaults << QObject::tr("Incoming Headline"); defaults << QObject::tr("Incoming File"); // Register with Growl gn_ = new GrowlNotifier(nots, defaults, "Psi"); } /** * Requests the global PsiGrowlNotifier instance. * If PsiGrowlNotifier wasn't initialized yet, it is initialized. * * \see GrowlNotifier() * \return A pointer to the PsiGrowlNotifier instance */ PsiGrowlNotifier* PsiGrowlNotifier::instance() { if (!instance_) instance_ = new PsiGrowlNotifier(); return instance_; } /** * Requests a popup to be sent to Growl. * * \param account The requesting account. * \param type The type of popup to be sent. * \param jid The originating jid * \param uli The originating userlist item. Can be NULL. * \param event The originating event. Can be NULL. */ void PsiGrowlNotifier::popup(PsiAccount* account, PsiPopup::PopupType type, const Jid& jid, const Resource& r, const UserListItem* uli, PsiEvent* event) { QString name; QString title, desc, contact; QString statusTxt = status2txt(makeSTATUS(r.status())); QString statusMsg = r.status().status(); QPixmap icon = account->avatarFactory()->getAvatar(jid.bare()); if (uli) { contact = uli->name(); } else if (event->type() == PsiEvent::Auth) { contact = ((AuthEvent*) event)->nick(); } else if (event->type() == PsiEvent::Message) { contact = ((MessageEvent*) event)->nick(); } if (contact.isEmpty()) contact = jid.bare(); // Default value for the title title = contact; switch(type) { case PsiPopup::AlertOnline: name = QObject::tr("Contact becomes Available"); title = QString("%1 (%2)").arg(contact).arg(statusTxt); desc = statusMsg; //icon = PsiIconset::instance()->statusPQString(jid, r.status()); break; case PsiPopup::AlertOffline: name = QObject::tr("Contact becomes Unavailable"); title = QString("%1 (%2)").arg(contact).arg(statusTxt); desc = statusMsg; //icon = PsiIconset::instance()->statusPQString(jid, r.status()); break; case PsiPopup::AlertStatusChange: name = QObject::tr("Contact changes Status"); title = QString("%1 (%2)").arg(contact).arg(statusTxt); desc = statusMsg; //icon = PsiIconset::instance()->statusPQString(jid, r.status()); break; case PsiPopup::AlertMessage: { name = QObject::tr("Incoming Message"); title = QObject::tr("%1 says:").arg(contact); const Message* jmessage = &((MessageEvent *)event)->message(); desc = jmessage->body(); //icon = IconsetFactory::iconPQString("psi/message"); break; } case PsiPopup::AlertChat: { name = QObject::tr("Incoming Message"); const Message* jmessage = &((MessageEvent *)event)->message(); desc = jmessage->body(); //icon = IconsetFactory::iconPQString("psi/start-chat"); break; } case PsiPopup::AlertHeadline: { name = QObject::tr("Incoming Headline"); const Message* jmessage = &((MessageEvent *)event)->message(); if ( !jmessage->subject().isEmpty()) title = jmessage->subject(); desc = jmessage->body(); //icon = IconsetFactory::iconPQString("psi/headline"); break; } case PsiPopup::AlertFile: name = QObject::tr("Incoming File"); desc = QObject::tr("[Incoming File]"); //icon = IconsetFactory::iconPQString("psi/file"); break; default: break; } // Notify Growl NotificationContext* context = new NotificationContext(account, jid); gn_->notify(name, title, desc, icon, false, this, SLOT(notificationClicked(void*)), SLOT(notificationTimedOut(void*)), context); } void PsiGrowlNotifier::cleanup() { // try to keep the garbage bin no larger than 50 entries while (contexts_.count() > 50) { delete contexts_.takeFirst(); } } void PsiGrowlNotifier::tryDeleteContext(NotificationContext* context) { // instead of deleting the context right away, let's put it in a list // to be garbage collected, and bump the delete counter if (context->deleteCount_ == 0) { contexts_ += context; } ++(context->deleteCount_); // perform routine cleanup cleanup(); } void PsiGrowlNotifier::notificationClicked(void* c) { NotificationContext* context = (NotificationContext*) c; context->account()->actionDefault(context->jid()); //delete context; tryDeleteContext(context); } void PsiGrowlNotifier::notificationTimedOut(void* c) { NotificationContext* context = (NotificationContext*) c; //delete context; tryDeleteContext(context); } PsiGrowlNotifier* PsiGrowlNotifier::instance_ = 0; psi-0.14/src/mucjoin.ui0000644000175000017500000001362311305557613013140 0ustar janjan MUCJoin 0 0 410 362 Join Groupchat Identity: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Recent: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Room information Host: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Room: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Nickname: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Password: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QLineEdit::Password Request chat history Qt::Vertical QSizePolicy::Expanding 331 0 QFrame::HLine QFrame::Sunken Qt::Horizontal QDialogButtonBox::Cancel qPixmapFromMimeSource BusyWidget QWidget
busywidget.h
1
AccountsComboBox QComboBox
accountscombobox.h
cb_recent le_host le_room le_nick le_pass ck_history buttonBox rejected() MUCJoin reject() 362 348 406 316 buttonBox accepted() MUCJoin accept() 312 343 336 316
psi-0.14/src/eventdlg.h0000644000175000017500000001147011305557613013114 0ustar janjan/* * eventdlg.h - dialog for sending / receiving messages and events * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef EVENTDLG_H #define EVENTDLG_H #include #include #include "xmpp_url.h" #include "xmpp_rosterx.h" #include "ui_addurl.h" #include "advwidget.h" #include "userlist.h" class QDateTime; class QStringList; class Q3PopupMenu; class PsiEvent; class PsiCon; class PsiAccount; class PsiIcon; class EventDlg; namespace XMPP { class Jid; class XData; } class PsiHttpAuthRequest; using namespace XMPP; class ELineEdit : public QLineEdit { Q_OBJECT public: ELineEdit(EventDlg *parent, const char *name=0); signals: void changeResource(const QString &); void tryComplete(); protected: // reimplemented void dragEnterEvent(QDragEnterEvent *); void dropEvent(QDropEvent *); void keyPressEvent(QKeyEvent *); Q3PopupMenu *createPopupMenu(); private slots: void resourceMenuActivated(int); private: UserResourceList url; }; class AttachView : public QListWidget { Q_OBJECT public: AttachView(QWidget* parent); ~AttachView(); void setReadOnly(bool); void urlAdd(const QString &, const QString &); void gcAdd(const QString &, const QString& = QString(), const QString& = QString(), const QString& = QString()); UrlList urlList() const; void addUrlList(const UrlList &); signals: void childCountChanged(); void actionGCJoin(const QString &, const QString&); protected: // reimplemented void contextMenuEvent(QContextMenuEvent* e); private slots: void qlv_doubleClicked(QListWidgetItem *); private: bool v_readOnly; void goURL(const QString &); }; class AddUrlDlg : public QDialog, public Ui::AddUrl { Q_OBJECT public: AddUrlDlg(QWidget *parent=0); ~AddUrlDlg(); }; class EventDlg : public AdvancedWidget { Q_OBJECT public: // compose EventDlg(const QString &, PsiCon *, PsiAccount *); // read EventDlg(const Jid &, PsiAccount *, bool unique); ~EventDlg(); QString text() const; void setHtml(const QString &); void setSubject(const QString &); void setThread(const QString &); void setUrlOnShow(); PsiAccount *psiAccount(); static QSize defaultSize(); signals: void aChat(const Jid& jid); void aReply(const Jid &jid, const QString &body, const QString &subject, const QString &thread); void aReadNext(const Jid &); void aDeny(const Jid &); void aAuth(const Jid &); void aHttpConfirm(const PsiHttpAuthRequest &); void aHttpDeny(const PsiHttpAuthRequest &); void aRosterExchange(const RosterExchangeItems &); void aFormSubmit(const XData&, const QString&, const Jid&); void aFormCancel(const XData&, const QString&, const Jid&); protected: // reimplemented void showEvent(QShowEvent *); void resizeEvent(QResizeEvent *); void keyPressEvent(QKeyEvent *); void closeEvent(QCloseEvent *); public slots: void optionsUpdate(); void closeAfterReply(); void updateContact(const Jid &); void updateEvent(PsiEvent *); void updateReadNext(PsiIcon *, int); void actionGCJoin(const QString &, const QString&); private slots: void to_textChanged(const QString &); void to_changeResource(const QString &); void to_tryComplete(); void updateIdentity(PsiAccount *); void updateIdentityVisibility(); void accountUpdatedActivity(); void doWhois(bool force=false); void doSend(); void doReadNext(); void doChat(); void doReply(); void doQuote(); void doDeny(); void doAuth(); void doHttpConfirm(); void doHttpDeny(); void doInfo(); void doHistory(); void showHideAttachView(); void addUrl(); void doFormSubmit(); void doFormCancel(); void updatePGP(); void encryptedMessageSent(int, bool, int, const QString &); void trySendEncryptedNext(); public: class Private; private: Private *d; void doneSend(); void init(); QStringList stringToList(const QString &, bool enc=true) const; QString findJidInString(const QString &) const; QString expandAddresses(const QString &, bool enc=true) const; void buildCompletionList(); void setAccount(PsiAccount *); void setTime(const QDateTime &, bool late=false); friend class ELineEdit; UserResourceList getResources(const QString &) const; QString jidToString(const Jid &, const QString &r="") const; }; #endif psi-0.14/src/historydlg.cpp0000644000175000017500000004517111305557613014034 0ustar janjan/* * historydlg.cpp - a dialog to show event history * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "historydlg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psiaccount.h" #include "psievent.h" #include "busywidget.h" #include "applicationinfo.h" #include "common.h" #include "eventdb.h" #include "psiiconset.h" #include "textutil.h" #include "jidutil.h" #include "userlist.h" #include "psioptions.h" #include "fileutil.h" static QString getNext(QString *str) { int n = 0; // skip leading spaces (but *do* return them later!) while(n < (int)str->length() && str->at(n).isSpace()) { ++n; } if(n == (int)str->length()) { return QString::null; } // find end or next space while(n < (int)str->length() && !str->at(n).isSpace()) { ++n; } QString result = str->mid(0, n); *str = str->mid(n); return result; } // wraps a string against a fixed width static QStringList wrapString(const QString &str, int wid) { QStringList lines; QString cur; QString tmp = str; //printf("parsing: [%s]\n", tmp.latin1()); while(1) { QString word = getNext(&tmp); if(word == QString::null) { lines += cur; break; } //printf("word:[%s]\n", word.latin1()); if(!cur.isEmpty()) { if((int)cur.length() + (int)word.length() > wid) { lines += cur; cur = ""; } } if(cur.isEmpty()) { // trim the whitespace in front for(int n = 0; n < (int)word.length(); ++n) { if(!word.at(n).isSpace()) { if(n > 0) { word = word.mid(n); } break; } } } cur += word; } return lines; } //---------------------------------------------------------------------------- // HistoryView //---------------------------------------------------------------------------- class HistoryDlg::Private { public: Private() {} Jid jid; PsiAccount *pa; HistoryView *lv; //BusyWidget *busy; QPushButton *pb_prev, *pb_next, *pb_refresh, *pb_find; QLineEdit *le_find; QString id_prev, id_begin, id_end, id_next; int reqtype; QString findStr; EDBHandle *h, *exp; }; HistoryDlg::HistoryDlg(const Jid &jid, PsiAccount *pa) { setAttribute(Qt::WA_DeleteOnClose); if ( PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool() ) setAttribute(Qt::WA_MacMetalStyle); d = new Private; d->pa = pa; d->jid = jid; d->pa->dialogRegister(this, d->jid); d->exp = 0; setWindowTitle(d->jid.full()); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/history").icon()); #endif d->h = new EDBHandle(d->pa->edb()); connect(d->h, SIGNAL(finished()), SLOT(edb_finished())); QVBoxLayout *vb1 = new QVBoxLayout(this); d->lv = new HistoryView(this); d->lv->setVScrollBarMode(Q3ScrollView::AlwaysOn); connect(d->lv, SIGNAL(aOpenEvent(PsiEvent *)), SLOT(actionOpenEvent(PsiEvent *))); QSizePolicy sp = d->lv->sizePolicy(); sp.setVerticalStretch(1); d->lv->setSizePolicy(sp); vb1->addWidget(d->lv); QHBoxLayout *hb1 = new QHBoxLayout; vb1->addLayout(hb1); QVBoxLayout *vb2 = new QVBoxLayout; hb1->addLayout(vb2); QHBoxLayout *hb2 = new QHBoxLayout; vb2->addLayout(hb2); //d->busy = new BusyWidget(this); //hb1->addWidget(d->busy); d->pb_refresh = new QPushButton(tr("&Latest"), this); d->pb_refresh->setMinimumWidth(80); connect(d->pb_refresh, SIGNAL(clicked()), SLOT(doLatest())); hb2->addWidget(d->pb_refresh); d->pb_prev = new QPushButton(tr("&Previous"), this); d->pb_prev->setMinimumWidth(80); connect(d->pb_prev, SIGNAL(clicked()), SLOT(doPrev())); hb2->addWidget(d->pb_prev); d->pb_next = new QPushButton(tr("&Next"), this); d->pb_next->setMinimumWidth(80); connect(d->pb_next, SIGNAL(clicked()), SLOT(doNext())); hb2->addWidget(d->pb_next); QHBoxLayout *hb3 = new QHBoxLayout; vb2->addLayout(hb3); d->le_find = new QLineEdit(this); connect(d->le_find, SIGNAL(textChanged(const QString &)), SLOT(le_textChanged(const QString &))); connect(d->le_find, SIGNAL(returnPressed()), SLOT(doFind())); hb3->addWidget(d->le_find); d->pb_find = new QPushButton(tr("Find"), this); connect(d->pb_find, SIGNAL(clicked()), SLOT(doFind())); d->pb_find->setEnabled(false); hb3->addWidget(d->pb_find); QFrame *sep; sep = new QFrame(this); sep->setFrameShape(QFrame::VLine); hb1->addWidget(sep); QVBoxLayout *vb3 = new QVBoxLayout; hb1->addLayout(vb3); QPushButton *pb_save = new QPushButton(tr("&Export..."), this); connect(pb_save, SIGNAL(clicked()), SLOT(doSave())); vb3->addWidget(pb_save); QPushButton *pb_erase = new QPushButton(tr("Er&ase All"), this); connect(pb_erase, SIGNAL(clicked()), SLOT(doErase())); vb3->addWidget(pb_erase); sep = new QFrame(this); sep->setFrameShape(QFrame::VLine); hb1->addWidget(sep); hb1->addStretch(1); QVBoxLayout *vb4 = new QVBoxLayout; hb1->addLayout(vb4); vb4->addStretch(1); QPushButton *pb_close = new QPushButton(tr("&Close"), this); pb_close->setMinimumWidth(80); connect(pb_close, SIGNAL(clicked()), SLOT(close())); vb4->addWidget(pb_close); resize(520,320); X11WM_CLASS("history"); d->le_find->setFocus(); setButtons(); doLatest(); } HistoryDlg::~HistoryDlg() { delete d->exp; d->pa->dialogUnregister(this); delete d; } void HistoryDlg::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Escape) close(); else { e->ignore(); } } void HistoryDlg::closeEvent(QCloseEvent *e) { if(d->exp) return; e->accept(); } void HistoryDlg::show() { QWidget::show(); d->lv->doResize(); } void HistoryDlg::le_textChanged(const QString &s) { if(s.isEmpty() && d->pb_find->isEnabled()) d->pb_find->setEnabled(false); else if(!s.isEmpty() && !d->pb_find->isEnabled()) d->pb_find->setEnabled(true); } void HistoryDlg::setButtons() { d->pb_prev->setEnabled(!d->id_prev.isEmpty()); d->pb_next->setEnabled(!d->id_next.isEmpty()); } void HistoryDlg::doLatest() { loadPage(0); } void HistoryDlg::doPrev() { loadPage(1); } void HistoryDlg::doNext() { loadPage(2); } void HistoryDlg::doSave() { UserListItem *u = d->pa->findFirstRelevant(d->jid); QString them = JIDUtil::nickOrJid(u->name(), u->jid().full()); QString s = JIDUtil::encode(them).toLower(); QString str = FileUtil::getSaveFileName(this, tr("Export message history"), s + ".txt", tr("Text files (*.txt);;All files (*.*)")); if (!str.isEmpty()) { exportHistory(str); } } void HistoryDlg::doErase() { int x = QMessageBox::information(this, tr("Confirm erase all"), tr("This will erase all message history for this contact!\nAre you sure you want to do this?"), tr("&Yes"), tr("&No"), QString::null, 1); if (x == 0) { d->h->erase(d->jid); } } void HistoryDlg::loadPage(int type) { d->reqtype = type; if(type == 0) { d->pb_refresh->setEnabled(false); d->h->getLatest(d->jid, 50); //printf("EDB: requesting latest 50 events\n"); } else if(type == 1) { d->pb_prev->setEnabled(false); d->h->get(d->jid, d->id_prev, EDB::Backward, 50); //printf("EDB: requesting 50 events backward, starting at %s\n", d->id_prev.latin1()); } else if(type == 2) { d->pb_next->setEnabled(false); d->h->get(d->jid, d->id_next, EDB::Forward, 50); //printf("EDB: requesting 50 events forward, starting at %s\n", d->id_next.latin1()); } //d->busy->start(); } void HistoryDlg::displayResult(const EDBResult *r, int direction, int max) { //d->lv->setUpdatesEnabled(false); d->lv->clear(); int i = (direction == EDB::Forward) ? r->count()-1 : 0; int at = 0; while (i >= 0 && i <= r->count()-1 && (max == -1 ? true : at < max)) { EDBItem* item = r->value(i); PsiEvent* e = item->event(); d->lv->addEvent(e, item->prevId()); ++at; i += (direction == EDB::Forward) ? -1 : +1; } //d->lv->setUpdatesEnabled(true); //d->lv->repaint(true); } void HistoryDlg::edb_finished() { const EDBResult *r = d->h->result(); if(d->h->lastRequestType() == EDBHandle::Read && r) { //printf("EDB: retrieved %d events:\n", r->count()); if(r->count() > 0) { if(d->reqtype == 0 || d->reqtype == 1) { // events are in backward order // first entry is the end event EDBItem* it = r->first(); d->id_end = it->id(); d->id_next = it->nextId(); // last entry is the begin event it = r->last(); d->id_begin = it->id(); d->id_prev = it->prevId(); displayResult(r, EDB::Backward); //printf("[%s],[%s],[%s],[%s]\n", d->id_prev.latin1(), d->id_begin.latin1(), d->id_end.latin1(), d->id_next.latin1()); } else if(d->reqtype == 2) { // events are in forward order // last entry is the end event EDBItem* it = r->last(); d->id_end = it->id(); d->id_next = it->nextId(); // first entry is the begin event it = r->first(); d->id_begin = it->id(); d->id_prev = it->prevId(); displayResult(r, EDB::Forward); } else if(d->reqtype == 3) { // should only be one entry EDBItem *ei = r->first(); d->reqtype = 1; d->h->get(d->jid, ei->id(), EDB::Backward, 50); //printf("EDB: requesting 50 events backward, starting at %s\n", d->id_prev.latin1()); return; } } else { if(d->reqtype == 3) { QMessageBox::information(this, tr("Find"), tr("Search string '%1' not found.").arg(d->findStr)); return; } } } else if (d->h->lastRequestType() == EDBHandle::Erase) { if (d->h->writeSuccess()) { d->lv->clear(); d->id_prev = ""; d->id_begin = ""; d->id_end = ""; d->id_next = ""; } else { QMessageBox::critical(this, tr("Error"), tr("Unable to delete history file.")); } } else { //printf("EDB: error\n"); } if(d->lv->firstChild()) d->lv->setSelected(d->lv->firstChild(), true); //d->busy->stop(); d->pb_refresh->setEnabled(true); setButtons(); } void HistoryDlg::actionOpenEvent(PsiEvent *e) { openEvent(e); } void HistoryDlg::doFind() { QString str = d->le_find->text(); if(str.isEmpty()) return; if(d->lv->childCount() < 1) return; HistoryViewItem *i = (HistoryViewItem *)d->lv->selectedItem(); if(!i) i = (HistoryViewItem *)d->lv->firstChild(); QString id = i->eventId; if(id.isEmpty()) { QMessageBox::information(this, tr("Find"), tr("Already at beginning of message history.")); return; } //printf("searching for: [%s], starting at id=[%s]\n", str.latin1(), id.latin1()); d->reqtype = 3; d->findStr = str; d->h->find(str, d->jid, id, EDB::Backward); } void HistoryDlg::exportHistory(const QString &fname) { QFile f(fname); if(!f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { QMessageBox::information(this, tr("Error"), tr("Error writing to file.")); return; } QTextStream stream(&f); QString us = d->pa->nick(); UserListItem *u = d->pa->findFirstRelevant(d->jid); QString them = JIDUtil::nickOrJid(u->name(), u->jid().full()); d->exp = new EDBHandle(d->pa->edb()); QString id; while(1) { if(id.isEmpty()) { d->exp->getOldest(d->jid, 1000); } else { d->exp->get(d->jid, id, EDB::Forward, 1000); } while(d->exp->busy()) { qApp->processEvents(); } const EDBResult *r = d->exp->result(); if(!r) { break; } if(r->count() <= 0) { break; } // events are in forward order for(int i = 0; i < r->count(); ++i) { EDBItem* item = r->value(i); id = item->nextId(); PsiEvent *e = item->event(); QString txt; QDateTime dt = e->timeStamp(); QString ts; //ts.sprintf("%04d/%02d/%02d %02d:%02d:%02d", dt.date().year(), dt.date().month(), dt.date().day(), dt.time().hour(), dt.time().minute(), dt.time().second()); ts = dt.toString(Qt::LocalDate); QString nick; if(e->originLocal()) { nick = us; } else { nick = them; } QString heading = QString("(%1) ").arg(ts) + nick + ": "; if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; stream << heading << endl; QStringList lines = me->message().body().split('\n', QString::KeepEmptyParts); foreach(const QString& str, lines) { QStringList sub = wrapString(str, 72); foreach(const QString& str2, sub) { txt += QString(" ") + str2 + '\n'; } } } else { continue; } stream << txt << endl; } // done! if(id.isEmpty()) { break; } } delete d->exp; d->exp = 0; f.close(); } //---------------------------------------------------------------------------- // HistoryView //---------------------------------------------------------------------------- HistoryView::HistoryView(QWidget *parent, const char *name) :Q3ListView(parent, name) { at_id = 0; connect(this, SIGNAL(doubleClicked(Q3ListViewItem *)), SLOT(qlv_doubleclick(Q3ListViewItem *))); connect(this, SIGNAL(rightButtonPressed(Q3ListViewItem *, const QPoint &, int)), SLOT(qlv_contextPopup(Q3ListViewItem *, const QPoint &, int))); setAllColumnsShowFocus(true); addColumn(tr("Type")); addColumn(tr("Origin")); addColumn(tr("Date")); addColumn(tr("Text")); setSorting(2); setResizeMode(Q3ListView::LastColumn); setShowToolTips(false); header()->setClickEnabled(false); header()->setMovingEnabled(false); header()->setResizeEnabled(false); } void HistoryView::resizeEvent(QResizeEvent *e) { Q3ListView::resizeEvent(e); if(e->oldSize().width() != e->size().width()) doResize(); } void HistoryView::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) doOpenEvent(); else Q3ListView::keyPressEvent(e); } void HistoryView::doResize() { Q3ListViewItemIterator it(this); HistoryViewItem *item; for(; it.current() ; ++it) { item = (HistoryViewItem *)it.current(); item->setup(); } } void HistoryView::addEvent(PsiEvent *e, const QString &eid) { new HistoryViewItem(e, eid, at_id++, this); } void HistoryView::doOpenEvent() { HistoryViewItem *i = (HistoryViewItem *)selectedItem(); if(!i) return; aOpenEvent(i->e); } void HistoryView::qlv_doubleclick(Q3ListViewItem *xi) { HistoryViewItem *i = (HistoryViewItem *)xi; setSelected(i, true); doOpenEvent(); } void HistoryView::qlv_contextPopup(Q3ListViewItem *ix, const QPoint &pos, int) { HistoryViewItem *i = (HistoryViewItem *)ix; if(!i) return; Q3PopupMenu popup; popup.insertItem(tr("Open"), 1); popup.insertSeparator(); popup.insertItem(tr("Copy"), 2); if(i->e->type() != PsiEvent::Message) popup.setItemEnabled(2, false); int x = popup.exec(pos); if(x == 1) doOpenEvent(); else if(x == 2) { HistoryViewItem *i = (HistoryViewItem *)selectedItem(); if(!i) return; MessageEvent *me = (MessageEvent *)i->e; QApplication::clipboard()->setText(me->message().body(), QClipboard::Clipboard); if(QApplication::clipboard()->supportsSelection()) QApplication::clipboard()->setText(me->message().body(), QClipboard::Selection); } } //---------------------------------------------------------------------------- // HistoryViewItem //---------------------------------------------------------------------------- HistoryViewItem::HistoryViewItem(PsiEvent *_e, const QString &eid, int xid, Q3ListView *parent) :Q3ListViewItem(parent) { rt = 0; id = xid; eventId = eid; if(_e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)_e; e = new MessageEvent(*me); } else if(_e->type() == PsiEvent::Auth) { AuthEvent *ae = (AuthEvent *)_e; e = new AuthEvent(*ae); } PsiIcon *a = PsiIconset::instance()->event2icon(e); if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); text = TextUtil::plain2rich(m.body()); if(!m.urlList().isEmpty()) setPixmap(0, IconsetFactory::icon("psi/www").impix()); else if(e->originLocal()) setPixmap(0, IconsetFactory::icon("psi/sendMessage").impix()); else if(a) setPixmap(0, a->impix()); } else if(e->type() == PsiEvent::Auth) { AuthEvent *ae = (AuthEvent *)e; text = ae->authType(); if (a) setPixmap(0, a->impix()); } if(e->originLocal()) setText(1, HistoryView::tr("To")); else setText(1, HistoryView::tr("From")); QString date; const QDateTime &ts = e->timeStamp(); /*date.sprintf("%02d/%02d/%02d %02d:%02d:%02d", ts.date().month(), ts.date().day(), ts.date().year(), ts.time().hour(), ts.time().minute(), ts.time().second());*/ date = ts.toString(Qt::LocalDate); setText(2, date); rt = new Q3SimpleRichText(text, listView()->font()); } HistoryViewItem::~HistoryViewItem() { delete rt; delete e; } // reimplemented from QListViewItem. setup() and paintCell() are tricky stuff void HistoryViewItem::setup() { widthChanged(); Q3ListView *lv = listView(); if(rt) { int w = lv->columnWidth(3); rt->setWidth(w); } int y; //y = lv->fontMetrics().size(AlignVCenter, displayStr).height(); if(!rt) y = 22; else y = rt->height(); y += lv->itemMargin() * 2; // ensure an even number if(y & 1) ++y; setHeight(y); } void HistoryViewItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int alignment) { QColorGroup mycg = cg; if(e->originLocal()) { mycg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.messages.sent").toString() ); } else { mycg.setColor(QColorGroup::Text,PsiOptions::instance()->getOption("options.ui.look.colors.messages.received").toString() ); } if(column == 3) { QBrush br; if(isSelected()) { mycg.setColor(QColorGroup::Text, mycg.highlightedText()); br = cg.brush(QColorGroup::Highlight); } else { br = cg.brush(QColorGroup::Base); } int h = height(); if(rt) { Q3SimpleRichText tmp(QString("" + text + "").arg(mycg.text().name()), listView()->font()); tmp.setWidth(rt->width()); tmp.draw(p, 0, 0, QRect(0, 0, width, h), mycg, &br); } } else { alignment = Qt::AlignTop; Q3ListViewItem::paintCell(p, mycg, column, width, alignment); } } int HistoryViewItem::compare(Q3ListViewItem *xi, int, bool) const { HistoryViewItem *i = (HistoryViewItem *)xi; return id - i->id; } int HistoryViewItem::rtti() const { return 7105; } psi-0.14/src/chatsplitter.cpp0000644000175000017500000000725011305557613014346 0ustar janjan/* * chatsplitter.cpp - QSplitter replacement that masquerades it * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "chatsplitter.h" #include #include #include #include "psioptions.h" /** * Handy widget that masquerades itself as QSplitter, and could work * in both QSplitter mode, and QSplitter-less mode. */ ChatSplitter::ChatSplitter(QWidget* parent) : QWidget(parent) , splitterEnabled_(true) , splitter_(0) , layout_(0) { connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionsChanged())); optionsChanged(); if (!layout_) updateLayout(); } /** * Dummy function to fool Qt Designer-generated forms. */ void ChatSplitter::setOrientation(Qt::Orientation orientation) { Q_ASSERT(orientation == Qt::Vertical); Q_UNUSED(orientation); } /** * Adds the given \a widget to the splitter's layout after all the * other items. Don't call this function if widget is already added * to the splitter's layout. */ void ChatSplitter::addWidget(QWidget* widget) { Q_ASSERT(!children_.contains(widget)); children_ << widget; connect(widget, SIGNAL(destroyed(QObject*)), SLOT(childDestroyed(QObject*))); updateChildLayout(widget); } /** * If splitter mode is enabled, the \a list is passed to the * actual splitter. Has no effect otherwise. */ void ChatSplitter::setSizes(const QList& list) { if (splitter_) splitter_->setSizes(list); } /** * Moves \a child either to the real QSplitter, or adds it to the * private layout. */ void ChatSplitter::updateChildLayout(QWidget* child) { if (splitterEnabled() && splitter_) { splitter_->addWidget(child); } else { layout_->addWidget(child); } } /** * Removes destroyed widget from the splitter's child list. */ void ChatSplitter::childDestroyed(QObject* obj) { Q_ASSERT(obj->isWidgetType()); children_.removeAll(static_cast(obj)); } /** * If \a enable is true, the true QSplitter gets enabled, otherwise * all widgets are managed by QLayout. */ void ChatSplitter::setSplitterEnabled(bool enable) { if (splitterEnabled_ == enable) return; splitterEnabled_ = enable; updateLayout(); } /** * Invalidates layout and moves all child widgets to the proper position. */ void ChatSplitter::updateLayout() { foreach(QWidget* child, children_) child->setParent(this); delete splitter_; delete layout_; splitter_ = new QSplitter(this); layout_ = new QVBoxLayout(this); layout_->setMargin(0); layout_->addWidget(splitter_); splitter_->setOrientation(Qt::Vertical); splitter_->setVisible(splitterEnabled()); foreach(QWidget* child, children_) updateChildLayout(child); } /** * Updates layout according to current options. * FIXME: When PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool() finally makes it to PsiOptions, make this slot * private. */ void ChatSplitter::optionsChanged() { setSplitterEnabled(!PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool()); } psi-0.14/src/bookmarkmanager.h0000644000175000017500000000347111305557613014446 0ustar janjan/* * bookmarkmanager.h * Copyright (C) 2006-2008 Remko Troncon, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef BOOKMARKMANAGER_H #define BOOKMARKMANAGER_H #include #include #include "conferencebookmark.h" #include "urlbookmark.h" class PsiAccount; class BookmarkManager : public QObject { Q_OBJECT public: BookmarkManager(PsiAccount* account); bool isAvailable() const; QList urls() const; QList conferences() const; void setBookmarks(const QList&, const QList&); void setBookmarks(const QList&); void setBookmarks(const QList&); signals: void availabilityChanged(); void urlsChanged(const QList&); void conferencesChanged(const QList&); private slots: void getBookmarks_finished(); void setBookmarks_finished(); void accountStateChanged(); private: void getBookmarks(); void setIsAvailable(bool available); private: PsiAccount* account_; bool accountAvailable_; bool isAvailable_; QList urls_; QList conferences_; }; #endif psi-0.14/src/psitrayicon.cpp0000644000175000017500000001022111305557613014174 0ustar janjan#include #include #include // old #include #include "psitrayicon.h" #include "iconset.h" #include "alerticon.h" #include "psioptions.h" // TODO: remove the QPoint parameter from the signals when we finally move // to the new system. PsiTrayIcon::PsiTrayIcon(const QString &tip, QMenu *popup, QObject *parent) : QObject(parent) { icon_ = NULL; trayicon_ = NULL; trayicon_ = new QSystemTrayIcon(); trayicon_->setContextMenu(popup); setToolTip(tip); connect(trayicon_,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),SLOT(trayicon_activated(QSystemTrayIcon::ActivationReason))); } PsiTrayIcon::~PsiTrayIcon() { delete trayicon_; delete icon_; } void PsiTrayIcon::setContextMenu(QMenu* menu) { trayicon_->setContextMenu(menu); } void PsiTrayIcon::setToolTip(const QString &str) { trayicon_->setToolTip(str); } void PsiTrayIcon::setIcon(const PsiIcon *icon, bool alert) { if ( icon_ ) { disconnect(icon_, 0, this, 0 ); icon_->stop(); delete icon_; icon_ = 0; } if ( icon ) { if ( !alert ) icon_ = new PsiIcon(*icon); else icon_ = new AlertIcon(icon); connect(icon_, SIGNAL(pixmapChanged()), SLOT(animate())); icon_->activated(); } else icon_ = new PsiIcon(); animate(); } void PsiTrayIcon::setAlert(const PsiIcon *icon) { setIcon(icon, true); } bool PsiTrayIcon::isAnimating() const { return icon_->isAnimated(); } bool PsiTrayIcon::isWMDock() { return false; } void PsiTrayIcon::show() { trayicon_->show(); } void PsiTrayIcon::hide() { trayicon_->hide(); } // a function to blend 2 pixels taking their alpha channels // into consideration // p1 is in the 1st layer, p2 is in the 2nd layer (over p1) QRgb PsiTrayIcon::pixelBlend(QRgb p1, QRgb p2) { int a2 = qAlpha(p2); if (a2 == 255) return p2; // don't calculate anything if p2 is completely opaque int a1 = qAlpha(p1); double prop1 = double(a1*(255-a2))/double(255*255); double prop2 = double(a2)/255.0; int r = int( qRed(p1)*prop1 + qRed(p2)*prop2 ); int g = int( qGreen(p1)*prop1 + qGreen(p2)*prop2 ); int b = int( qBlue(p1)*prop1 + qBlue(p2)*prop2 ); return qRgba(r, g, b, (a1>a2) ? a1:a2); } QPixmap PsiTrayIcon::makeIcon() { if ( !icon_ ) return QPixmap(); #ifdef Q_WS_X11 // on X11, the KDE dock is 22x22. let's make our icon_ "seem" bigger. QImage real(22,22,QImage::Format_ARGB32); QImage in = icon_->image(); in.detach(); // make sure it is no bigger than 16x16 if(in.width() > 16 || in.height() > 16) in = in.scaled(16,16,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); int xo = (real.width() - in.width()) / 2; int yo = (real.height() - in.height()) / 2; int n, n2; // clear the output and make it transparent // deprecates real.fill(0) for(n2 = 0; n2 < real.height(); ++n2) for(n = 0; n < real.width(); ++n) real.setPixel(n, n2, qRgba(0,0,0,0)); // draw a dropshadow for(n2 = 0; n2 < in.height(); ++n2) { for(n = 0; n < in.width(); ++n) { if(int a = qAlpha(in.pixel(n,n2))) { int x = n + xo + 2; int y = n2 + yo + 2; real.setPixel(x, y, qRgba(0x80,0x80,0x80,a)); } } } // draw the image for(n2 = 0; n2 < in.height(); ++n2) { for(n = 0; n < in.width(); ++n) { if(qAlpha(in.pixel(n,n2))) { QRgb pold = real.pixel(n + xo , n2 + yo); QRgb pnew = in.pixel(n , n2); real.setPixel(n + xo, n2 + yo, pixelBlend(pold, pnew)); } } } return QPixmap::fromImage(real); #else return icon_->pixmap(); #endif } void PsiTrayIcon::trayicon_activated(QSystemTrayIcon::ActivationReason reason) { #ifdef Q_WS_MAC Q_UNUSED(reason) #else if (reason == QSystemTrayIcon::Trigger) emit clicked(QPoint(),Qt::LeftButton); else if (reason == QSystemTrayIcon::MiddleClick) emit clicked(QPoint(),Qt::MidButton); else if (reason == QSystemTrayIcon::DoubleClick) emit doubleClicked(QPoint()); #endif } void PsiTrayIcon::animate() { if ( !icon_ ) return; QString cachedName = "PsiTray/" + PsiOptions::instance()->getOption("options.iconsets.status").toString() + "/" + icon_->name() + "/" + QString::number( icon_->frameNumber() ); QPixmap p; if ( !QPixmapCache::find(cachedName, p) ) { p = makeIcon(); QPixmapCache::insert( cachedName, p ); } trayicon_->setIcon(p); } psi-0.14/src/tools/0000755000175000017500000000000011305557613012270 5ustar janjanpsi-0.14/src/tools/crash/0000755000175000017500000000000011305557613013370 5ustar janjanpsi-0.14/src/tools/crash/crash_kde.cpp0000644000175000017500000000034211305557613016016 0ustar janjan#include "crash.h" #include namespace Crash { void registerSigsegvHandler(QString progname) { KCrash::setApplicationName(progname); KCrash::setCrashHandler(KCrash::defaultCrashHandler); } }; // namespace Crash psi-0.14/src/tools/crash/crash_dummy.cpp0000644000175000017500000000014711305557613016411 0ustar janjan#include "crash.h" namespace Crash { void registerSigsegvHandler(QString) { } }; // namespace Crash psi-0.14/src/tools/crash/crash_sigsegv.h0000644000175000017500000000340211305557613016367 0ustar janjan/* * sigsegv.h -- sigsegv handlers * * Copyright (c) 2003 Juan F. Codagnone * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef CRASH_SIGSEGV_H #define CRASH_SIGSEGV_H namespace Crash { /** * sets the print function (it is used to print the backtrace) * if it isn't set, or it is set to NULL, printf will be used. * * \param _need_cr needs to append an \n at the end? */ void *sigsegv_set_print( int (* fnc)(const char *format, ...), int _needs_cr); /** * try to print a backtrace of the programa, and dump the core */ void sigsegv_handler_fnc(int signal); /** * try to print a verbose backtrace of the program, and dump the core */ void sigsegv_handler_bt_full_fnc(int signal); }; // namespace Crash #endif psi-0.14/src/tools/crash/crash.pri0000644000175000017500000000061611305557613015207 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/crash.h unix { SOURCES += $$PWD/crash_sigsegv.cpp HEADERS += $$PWD/crash_sigsegv.h !isEmpty(KDE) { SOURCES += $$PWD/crash_kde.cpp LIBS += -L$$KDE/lib -lkdecore INCLUDEPATH += $$KDE/include DEPENDPATH += $$KDE/include } else { SOURCES += $$PWD/crash.cpp } } else { SOURCES += $$PWD/crash_dummy.cpp } psi-0.14/src/tools/crash/crash_sigsegv.cpp0000644000175000017500000001300011305557613016715 0ustar janjan/* sigsegv.c -- sigsegv handlers * * Copyright (c) 2003 Juan F. Codagnone * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifdef HAVE_CONFIG_H_ #include #endif #include #include #include #include #include #include #ifdef HAVE_PTHREADS_H # include #endif /* * http://www.gnu.org/manual/glibc-2.2.3/html_chapter/libc_33.html */ #if defined(__GLIBC__) && defined(__GLIBC_MINOR__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 # define HAVE_BACKTRACE # include #endif #include #include "crash_sigsegv.h" namespace Crash { static int (* print)(const char *format, ...) = NULL; static int needs_cr = 1; void *sigsegv_set_print( int (* fnc)(const char *format, ...), int _needs_cr) { void *ret; ret = &print; print = fnc; needs_cr = _needs_cr; return ret; } /** * launchs gdb, and feeds myprint with the backtrace */ static int dump_pid_son(pid_t pid, const char *binary, int full_bt, int (* myprint)(const char *format, ...)) { char tmp[]="/tmp/mrbug-crash-XXXXXX"; int ret = 0; int fd; fd = mkstemp(tmp); if( fd == -1 ) { (*myprint)("opening gdb command (tempory) file `%s'%s", tmp, needs_cr ? "\n" : ""); ret = -1; } else { char gdb_cmd[]="bt\nquit"; char gdb_cmd_full[]="bt full\nquit"; char cmd[128]; FILE *fp; if( full_bt ) write(fd, gdb_cmd_full, strlen(gdb_cmd_full)); else write(fd, gdb_cmd, strlen(gdb_cmd)); close(fd); sprintf(cmd, "gdb -nw -n -batch -x \"%s\" %s %d", tmp, binary, pid); (*myprint)("trying to dump pid: %d (%s)...%s", pid, binary, needs_cr ? "\n" : ""); fflush(NULL); fp = popen(cmd, "r"); if( fp == NULL ) { (*myprint)("err. couldn't exec `%s'%s", cmd, needs_cr ? "\n" : ""); ret = -1; } else { char buff[4096]; size_t len; while(fgets(buff, sizeof(buff), fp)) { len = strlen(buff); if( buff[len-1] == '\n') buff[len-1]=0; (*myprint)("%s%s", buff,needs_cr ? "\n" : ""); } pclose(fp); } if( remove(tmp) == -1 ) (*myprint)("removing `%s` (@;@)%s", tmp, needs_cr ? "\n" : ""); } return ret; } static int dump_pid(pid_t pid, const char *binary, int full_bt ) { pid_t mpid; int (* myprint)(const char *format, ...); myprint = print ? (int(*)(const char *format, ...))print : (int(*)(const char *format, ...))printf; /* * clone the process, so we don't make the bt bigger. */ mpid = fork(); if( mpid == 0 ) { dump_pid_son(pid, binary, full_bt, myprint); exit(0); } else if( mpid == -1 ) (*myprint)("lunching son: `%s' %s", strerror(errno), needs_cr ? "\n" : ""); else { /* father */ int status; alarm(0); waitpid(0, &status, 0); if( WIFEXITED(status) && WEXITSTATUS(status)==0 ) ; } return 0; } /** * get `pid`'s real path * * \param buff buffer for the output * \param nbuff size of the buffer * \param pid pid processes id to use * * \note this function works only in linux * * \return the buffer */ static char *get_path_from_pid(char *buff, size_t nbuff, pid_t pid) { char proc[256]; char *ret = NULL; int n; sprintf(proc, "/proc/%d/exe", pid); if( (n=readlink(proc, buff, nbuff)) == -1 ) ret = NULL; else { buff[n]=0; ret = buff; } return ret; } static void sigsegv_libc_dump( int (* myprint)(const char *format, ...) ) { void *array[48] = {0}; unsigned short i; int n; char **res; #ifdef HAVE_BACKTRACE (*myprint)("Backtrace:%c", needs_cr ? "\n" : ""); n = backtrace(array, sizeof(array)/(sizeof(*array))); res = backtrace_symbols(array, n); for (i = 0; i < n; i++) (*myprint)("%s%s", res[i], needs_cr ? "\n" : ""); (*myprint)("Attempting to generate core file%s", needs_cr ? "" : ""); #endif } static void sigsegv_handler_generic(int signal, int full_bt) { char binary[2048]; int pid = getpid(); int (* myprint)(const char *format, ...); myprint = print ? print : printf; if( get_path_from_pid(binary, sizeof(binary), pid) == NULL) (*myprint)("pid %d does not seems to exist", pid); else { (*myprint)("Segmentation Violation Detected.%s", needs_cr ? "\n" : ""); dump_pid(pid, binary, full_bt); sigsegv_libc_dump(myprint); } #ifdef HAVE_PTHREAD_H pthread_kill_other_threads_np(); #endif fflush(NULL); abort(); } void sigsegv_handler_fnc(int signal) { sigsegv_handler_generic(signal, 0); } void sigsegv_handler_bt_full_fnc(int signal) { sigsegv_handler_generic(signal, 1); } }; // namespace Crash psi-0.14/src/tools/crash/crash.cpp0000644000175000017500000000177011305557613015201 0ustar janjan/* * crash.c - handle psi's crashes * * Copyright (C) 2004 by Juan F. Codagnone * * 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include "crash.h" #include "crash_sigsegv.h" namespace Crash { void registerSigsegvHandler(QString) { signal(SIGSEGV, sigsegv_handler_bt_full_fnc); } }; // namespace Crash psi-0.14/src/tools/crash/crash.h0000644000175000017500000000020611305557613014637 0ustar janjan#ifndef CRASH_H #define CRASH_H #include namespace Crash { void registerSigsegvHandler(QString progname); }; #endif psi-0.14/src/tools/optionstree/0000755000175000017500000000000011305557613014643 5ustar janjanpsi-0.14/src/tools/optionstree/optionstreereader.h0000644000175000017500000000122111305557613020546 0ustar janjan#ifndef OPTIONSTREEREADER_H #define OPTIONSTREEREADER_H #include "atomicxmlfile.h" #include class OptionsTree; class VariantTree; class QStringList; class QSize; class QRect; class OptionsTreeReader : public AtomicXmlFileReader { public: OptionsTreeReader(OptionsTree*); // reimplemented virtual bool read(QIODevice* device); protected: void readTree(VariantTree* tree); QVariant readVariant(const QString& type); void readUnknownElement(QXmlStreamWriter* writer); QStringList readStringList(); QVariantList readVariantList(); QSize readSize(); QRect readRect(); private: OptionsTree* options_; QString unknown_; }; #endif psi-0.14/src/tools/optionstree/optionstreereader.cpp0000644000175000017500000001061211305557613021105 0ustar janjan#include "optionstreereader.h" #include #include #include #include "optionstree.h" #include "varianttree.h" #include "xmpp/base64/base64.h" OptionsTreeReader::OptionsTreeReader(OptionsTree* options) : options_(options) { Q_ASSERT(options_); } bool OptionsTreeReader::read(QIODevice* device) { setDevice(device); while (!atEnd()) { readNext(); if (isStartElement()) { readTree(&options_->tree_); } } return !error(); } void OptionsTreeReader::readTree(VariantTree* tree) { Q_ASSERT(isStartElement()); Q_ASSERT(tree); while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (!attributes().value("comment").isEmpty()) { tree->comments_[name().toString()] = attributes().value("comment").toString(); } if (attributes().value("type").isEmpty()) { if (!tree->trees_.contains(name().toString())) tree->trees_[name().toString()] = new VariantTree(tree); readTree(tree->trees_[name().toString()]); } else { QVariant v = readVariant(attributes().value("type").toString()); if (v.isValid()) { tree->values_[name().toString()] = v; } else { tree->unknowns2_[name().toString()] = unknown_; } } } } } QVariant OptionsTreeReader::readVariant(const QString& type) { QVariant result; if (type == "QStringList") { result = readStringList(); } else if (type == "QVariantList") { result = readVariantList(); } else if (type == "QSize") { result = readSize(); } else if (type == "QRect") { result = readRect(); } else if (type == "QByteArray") { result = QByteArray(); result = XMPP::Base64::decode(readElementText()); } else { QVariant::Type varianttype; bool known = true; if (type=="QString") { varianttype = QVariant::String; } else if (type=="bool") { varianttype = QVariant::Bool; } else if (type=="int") { varianttype = QVariant::Int; } else if (type == "QKeySequence") { varianttype = QVariant::KeySequence; } else if (type == "QColor") { varianttype = QVariant::Color; } else { known = false; } if (known) { result = readElementText(); result.convert(varianttype); } else { QString result; QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); QXmlStreamWriter writer; writer.setDevice(&buffer); writer.writeStartDocument(); readUnknownElement(&writer); writer.writeEndDocument(); buffer.close(); // qWarning("ba: %d, '%s'", ba.length(), qPrintable(QString::fromUtf8(ba))); unknown_ = QString::fromUtf8(ba); } } return result; } QStringList OptionsTreeReader::readStringList() { QStringList list; while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "item") { list << readElementText(); } } } return list; } QVariantList OptionsTreeReader::readVariantList() { QVariantList list; while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "item") { list << readVariant(attributes().value("type").toString()); } } } return list; } QSize OptionsTreeReader::readSize() { int width = 0, height = 0; while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "width") { width = readElementText().toInt(); } else if (name() == "height") { height = readElementText().toInt(); } } } return QSize(width, height); } QRect OptionsTreeReader::readRect() { int x = 0, y = 0, width = 0, height = 0; while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "width") { width = readElementText().toInt(); } else if (name() == "height") { height = readElementText().toInt(); } else if (name() == "x") { x = readElementText().toInt(); } else if (name() == "y") { y = readElementText().toInt(); } } } return QRect(x, y, width, height); } void OptionsTreeReader::readUnknownElement(QXmlStreamWriter* writer) { Q_ASSERT(isStartElement()); writer->writeStartElement(name().toString()); foreach(QXmlStreamAttribute attr, attributes()) { writer->writeAttribute(attr.name().toString(), attr.value().toString()); } while (!atEnd()) { writer->writeCharacters(text().toString()); readNext(); if (isEndElement()) break; if (isStartElement()) readUnknownElement(writer); } writer->writeEndElement(); } psi-0.14/src/tools/optionstree/unittest/0000755000175000017500000000000011305557613016522 5ustar janjanpsi-0.14/src/tools/optionstree/unittest/unittest.pri0000644000175000017500000000033011305557613021111 0ustar janjanOPTIONSTREE_CPP = .. CONFIG += optionstree include(../optionstree.pri) include(../../atomicxmlfile/atomicxmlfile.pri) include(../../../../iris/src/xmpp/base64/base64.pri) SOURCES += \ $$PWD/OptionsTreeMainTest.cpp psi-0.14/src/tools/optionstree/unittest/untitled.pri0000644000175000017500000000024311305557613021065 0ustar janjanOPTIONSTREE_CPP = .. CONFIG += optionstree include(../optionstree.pri) include(../../atomicxmlfile/atomicxmlfile.pri) SOURCES += \ $$PWD/OptionsTreeMainTest.cpp psi-0.14/src/tools/optionstree/unittest/unittest.pro0000644000175000017500000000021111305557613021115 0ustar janjaninclude(../../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$PSI_MOCKQCA_MODULE) include(unittest.pri) QT += xml gui psi-0.14/src/tools/optionstree/unittest/OptionsTreeMainTest.cpp0000644000175000017500000001703411305557613023153 0ustar janjan#include #include #include #include #include #include #include "qttestutil/qttestutil.h" #include "optionstree.h" class Benchmark { public: void end(const QString& msg) { float avg = 0.0; foreach(int i, results_) { avg += float(i); } avg /= float(results_.count()); qWarning() << msg << avg << results_; // qWarning("BENCH: %s: %ds %dmsec", qPrintable(msg), msecs / 1000, msecs % 1000); results_.clear(); } void startIteration() { time_ = QTime::currentTime(); } void endIteration() { results_ << time_.msecsTo(QTime::currentTime()); } private: QTime time_; QList results_; }; class OptionsTreeMainTest : public QObject { Q_OBJECT private slots: void initTestCase() { QVariantList l; l << QVariant(QString("item1")) << qVariantFromValue(QKeySequence("CTRL+L")); QStringList sl; sl << "String 1" << "String 2"; l << sl; l << QRect(10, 20, 30, -666); l << l; goodValues_["ba"] = QByteArray(QString("0xDEADBEEF").toLatin1()); goodValues_["paris"] = QVariant(QString("sirap")); goodValues_["Benvolio"] = QVariant(QString("Benvolio")); goodValues_["Benvolio"] = QVariant(QString("Not benvolio!!")); goodValues_["capulet.Juliet"] = QVariant(QString("girly")); goodValues_["verona.montague.romeo"] = QVariant(QString("poisoned")); goodValues_["capulet.Nursey"] = QVariant(QString("matchmaker")); goodValues_["verona.city"] = QVariant(true); goodValues_["verona.lovers"] = QVariant(2); goodValues_["verona.size"] = QVariant(QSize(210,295)); goodValues_["verona.stuff"] = l; goodValues_["verona.stringstuff"] = sl; // qWarning() << goodValues_; badValues_["capulet.Juliet.dead"] = QVariant(true); // qWarning() << badValues_; comments_["verona"] = "Fair city"; comments_["paris"] = "Bloke or city?"; comments_["verona.montague.romeo"] = "Watch what this one drinks"; // qWarning() << comments_; } void cleanupTestCase() { } void createTreeTest() { OptionsTree tree; initTree(&tree); verifyTree(&tree); // foreach(QString name, tree.allOptionNames()) { // qWarning() << name << " = " << tree.getOption(name).toString(); // } } void saveLoadTreeTest() { OptionsTree tree; initTree(&tree); verifyTree(&tree); tree.saveOptions(dir() + "/options.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); OptionsTree tree2; tree2.loadOptions(dir() + "/options.xml","OptionsTest","http://psi-im.org/optionstest","0.1", true); // tree2.saveOptions(dir() + "/options2.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); tree2.saveOptions(dir() + "/options3.xml","OptionsTest","http://psi-im.org/optionstest","0.1", true); verifyTree(&tree2); } #if 0 void stressTest() { bench_.startIteration(); QMap data = generateStressTestValues(100, 100); bench_.endIteration(); bench_.end("generateStressTestValues"); OptionsTree tree; initTreeValues(&tree, data); for (int i = 0; i < 100; ++i) { bench_.startIteration(); verifyTreeValues(&tree, data); bench_.endIteration(); } bench_.end("verifyTreeValues"); } #endif // #if 0 QString dir() { return "/Users/mblsha/src/psi/src/tools/optionstree/unittest"; } void benchLoadOptions() { // sleep(1); // OptionsTree tree; // QBENCHMARK { // tree.loadOptions(dir() + "/mbl_options.xml", "options", "http://psi-im.org/options", "0.1"); // } // for (int i = 0; i < 100; ++i) { QBENCHMARK { OptionsTree tree; tree.loadOptions(dir() + "/mbl_options.xml", "options", "http://psi-im.org/options", "0.1"); } } void benchLoadOptionsStream() { QBENCHMARK { OptionsTree tree; tree.loadOptions(dir() + "/mbl_options.xml", "options", "http://psi-im.org/options", "0.1", true); } } void benchLoadAccounts() { // sleep(1); // OptionsTree tree; // QBENCHMARK { // tree.loadOptions(dir() + "/mbl_accounts.xml", "accounts", "http://psi-im.org/options", "0.1"); // } // for (int i = 0; i < 100; ++i) { QBENCHMARK { OptionsTree tree; tree.loadOptions(dir() + "/mbl_accounts.xml", "accounts", "http://psi-im.org/options", "0.1"); } } void benchLoadAccountsStream() { QBENCHMARK { OptionsTree tree; tree.loadOptions(dir() + "/mbl_accounts.xml", "accounts", "http://psi-im.org/options", "0.1", true); } } void benchSaveAccounts() { OptionsTree tree; tree.loadOptions(dir() + "/mbl_accounts.xml", "accounts", "http://psi-im.org/options", "0.1"); QBENCHMARK { tree.saveOptions(dir() + "/mbl_accounts2.xml", "accounts", "http://psi-im.org/options", "0.1"); } } void benchSaveAccountsStream() { OptionsTree tree; tree.loadOptions(dir() + "/mbl_accounts.xml", "accounts", "http://psi-im.org/options", "0.1"); QBENCHMARK { tree.saveOptions(dir() + "/mbl_accounts2.xml", "accounts", "http://psi-im.org/options", "0.1", true); } } // #endif // #endif private: QMap goodValues_; QMap badValues_; QMap comments_; QMap generateStressTestValues(int count, int depth) { QMap result; for (int i = 1; i <= count; ++i) { QMap r = generateStressTestValues(QString("i%1").arg(i), depth); QMapIterator it(r); while (it.hasNext()) { it.next(); result[it.key()] = it.value(); } } return result; } QMap generateStressTestValues(const QString& name, int depth) { Q_ASSERT(depth >= 1); QMap result; for (int i = 1; i <= depth; ++i) { QStringList children; for (int j = 1; j < i; ++j) { children << "child"; } QString n = name; if (!children.isEmpty()) n += '.' + children.join('.'); n += ".value"; result[n] = QVariant(i); } return result; } void initTree(OptionsTree* tree) { initTreeValues(tree, goodValues_); initTreeValues(tree, badValues_); initTreeComments(tree, comments_); } void initTreeValues(OptionsTree* tree, const QMap& values) { Q_ASSERT(tree); Q_ASSERT(!values.isEmpty()); QMapIterator it(values); while (it.hasNext()) { it.next(); tree->setOption(it.key(), it.value()); } } void initTreeComments(OptionsTree* tree, const QMap& comments) { Q_ASSERT(tree); Q_ASSERT(!comments.isEmpty()); QMapIterator it(comments); while (it.hasNext()) { it.next(); tree->setComment(it.key(), it.value()); } } void verifyTree(const OptionsTree* tree) { verifyTreeValues(tree, goodValues_); verifyTreeBadValues(tree, badValues_); verifyTreeComments(tree, comments_); } void verifyTreeValues(const OptionsTree* tree, const QMap& values) { Q_ASSERT(tree); Q_ASSERT(!values.isEmpty()); QMapIterator it(values); while (it.hasNext()) { it.next(); QCOMPARE(tree->getOption(it.key()), it.value()); Q_ASSERT(!tree->getOption(it.key()).isNull()); } } void verifyTreeBadValues(const OptionsTree* tree, const QMap& values) { Q_ASSERT(tree); Q_ASSERT(!values.isEmpty()); QMapIterator it(values); while (it.hasNext()) { it.next(); Q_ASSERT(tree->getOption(it.key()).isNull()); } } void verifyTreeComments(const OptionsTree* tree, const QMap& comments) { Q_ASSERT(tree); Q_ASSERT(!comments.isEmpty()); QMapIterator it(comments); while (it.hasNext()) { it.next(); QCOMPARE(tree->getComment(it.key()), it.value()); } } Benchmark bench_; }; QTTESTUTIL_REGISTER_TEST(OptionsTreeMainTest); #include "OptionsTreeMainTest.moc" psi-0.14/src/tools/optionstree/optionstreemodel.h0000644000175000017500000000475611305557613020424 0ustar janjan/* * optionstreemodel.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef OPTIONSTREEMODEL_H #define OPTIONSTREEMODEL_H #include #include #include #include class OptionsTree; class OptionsTreeModel : public QAbstractItemModel { Q_OBJECT public: OptionsTreeModel(OptionsTree* tree, QObject* parent = 0); // Reimplemented from QAbstractItemModel int rowCount(const QModelIndex& parent = QModelIndex()) const; int columnCount (const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex& index, int role) const; bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex() ) const; QModelIndex parent(const QModelIndex& index) const; Qt::ItemFlags flags(const QModelIndex& index) const; // custom accessors QString indexToOptionName(QModelIndex idx) const; public slots: void setFlat(bool); protected: enum Section { Name = 0, Type = 1, Value = 2, Comment = 3, SectionBound=4}; QString getParentName(const QString &option) const; QModelIndex index(const QString &option, Section sec=Name) const; int nameToIndex(QString name) const; bool internalNode(QString name) const; protected slots: void optionChanged(const QString& option); void optionAboutToBeInserted(const QString& option); void optionInserted(const QString& option); void optionAboutToBeRemoved(const QString& option); void optionRemoved(const QString& option); private: OptionsTree* tree_; bool flat_; mutable QHash indexMap; mutable QHash nameMap; mutable int nextIdx; QStack realRemove; }; #endif psi-0.14/src/tools/optionstree/optionstree.cpp0000644000175000017500000002031511305557613017723 0ustar janjan/* * optionstree.cpp - Soft-coded options structure implementation * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "optionstree.h" #include #include #include #include "atomicxmlfile.h" #include "optionstreereader.h" #include "optionstreewriter.h" /** * Default constructor */ OptionsTree::OptionsTree(QObject *parent) : QObject(parent) { } /** * Destructor */ OptionsTree::~OptionsTree() { } /** * Returns the value of the specified option * \param name 'Path' to the option ("appearance.emoticons.useSmilies") * \return value of the option. Will be invalid if non-existant. */ QVariant OptionsTree::getOption(const QString& name) const { QVariant value=tree_.getValue(name); if (value==VariantTree::missingValue) { value=QVariant(QVariant::Invalid); qWarning("Accessing missing option %s", qPrintable(name)); } return value; } /** * \brief Sets the value of the named option. * If the option or any parents in the * hierachy do not exist, they are created and optionAboutToBeInserted and * optionInserted will be emited. * * Emits the optionChanged signal if the value differs from the existing value. * \param name "Path" to the option * \param value Value of the option */ void OptionsTree::setOption(const QString& name, const QVariant& value) { const QVariant &prev = tree_.getValue(name); if ( prev == value ) { return; } if (!prev.isValid()) { emit optionAboutToBeInserted(name); } tree_.setValue(name, value); if (!prev.isValid()) { emit optionInserted(name); } emit optionChanged(name); } /** * @brief returns true iff the node @a node is an internal node. */ bool OptionsTree::isInternalNode(const QString &node) const { return tree_.isInternalNode(node); } /** * \brief Sets the comment of the named option. * \param name "Path" to the option * \param comment the comment to store */ void OptionsTree::setComment(const QString& name, const QString& comment) { tree_.setComment(name,comment); } /** * \brief Returns the comment of the specified option. * \param name "Path" to the option */ QString OptionsTree::getComment(const QString& name) const { return tree_.getComment(name); } bool OptionsTree::removeOption(const QString &name, bool internal_nodes) { emit optionAboutToBeRemoved(name); bool ok = tree_.remove(name, internal_nodes); emit optionRemoved(name); return ok; } /** * Names of every stored option * \return Names of options */ QStringList OptionsTree::allOptionNames() const { return tree_.nodeChildren(); } /** * Names of all child options of the given option. * \param direct return only the direct children * \param internal_nodes include internal (non-final) nodes * \return Full names of options */ QStringList OptionsTree::getChildOptionNames(const QString& parent, bool direct, bool internal_nodes) const { return tree_.nodeChildren(parent,direct,internal_nodes); } bool OptionsTree::isValidName(const QString &name) { foreach(QString part, name.split('.')) { if (!VariantTree::isValidNodeName(part)) return false; } return true; } QString OptionsTree::mapLookup(const QString &basename, const QVariant &key) const { QStringList children = getChildOptionNames( basename, true, true); foreach (QString path, children) { if (getOption(path+".key") == key) { return path; } } qWarning("Accessing missing key '%s' in option map '%s'", qPrintable(key.toString()), qPrintable(basename)); return basename + "XXX"; } QVariant OptionsTree::mapGet(const QString &basename, const QVariant &key, const QString &node) const { return getOption(mapLookup(basename, key) + '.' + node); } QVariant OptionsTree::mapGet(const QString &basename, const QVariant &key, const QString &node, const QVariant &def) const { QVariantList keys = mapKeyList(basename); if (keys.contains(key)) { return getOption(mapLookup(basename, key) + '.' + node); } else { return def; } } QString OptionsTree::mapPut(const QString &basename, const QVariant &key) { QStringList children = getChildOptionNames( basename, true, true); foreach (QString path, children) { if (getOption(path+".key") == key) { return path; } } // FIXME performance? // allocate first unused index QString path; int i = 0; do { path = basename+".m"+QString::number(i); ++i; } while (children.contains(path)); setOption(path + ".key", key); return path; } void OptionsTree::mapPut(const QString &basename, const QVariant &key, const QString &node, const QVariant &value) { setOption(mapPut(basename, key) + '.' + node, value); } QVariantList OptionsTree::mapKeyList(const QString &basename) const { QVariantList ret; QStringList children = getChildOptionNames( basename, true, true); foreach (QString path, children) { ret << getOption(path+".key"); } return ret; } /** * Saves all options to the specified file * \param fileName Name of the file to which to save options * \param configName Name of the root element for the file * \param configVersion Version of the config format * \param configNS Namespace of the config format * \return 'true' if the file saves, 'false' if it fails */ bool OptionsTree::saveOptions(const QString& fileName, const QString& configName, const QString& configNS, const QString& configVersion, bool streamWriter) const { AtomicXmlFile f(fileName); if (streamWriter) { OptionsTreeWriter writer(this); writer.setName(configName); writer.setNameSpace(configNS); writer.setVersion(configVersion); return f.saveDocument(&writer); } QDomDocument doc(configName); QDomElement base = doc.createElement(configName); base.setAttribute("version", configVersion); if (!configNS.isEmpty()) base.setAttribute("xmlns", configNS); doc.appendChild(base); tree_.toXml(doc, base); if (!f.saveDocument(doc)) return false; return true; } /** * Loads all options to from specified file * \param fileName Name of the file from which to load options * \param configName Name of the root element to check for * \param configVersion If specified, the function will fail if the file version doesn't match * \param configNS Namespace of the config format * \return 'true' if the file loads, 'false' if it fails */ bool OptionsTree::loadOptions(const QString& fileName, const QString& configName, const QString& configNS, const QString& configVersion, bool streamReader) { AtomicXmlFile f(fileName); if (streamReader) { OptionsTreeReader reader(this); return f.loadDocument(&reader); } QDomDocument doc; if (!f.loadDocument(&doc)) return false; return loadOptions(doc.documentElement(), configName, configVersion, configNS); } /** * Checks for existing saved Options. * Does not guarantee that load succeeds if the config file was corrupted. */ bool OptionsTree::exists(QString fileName) { return AtomicXmlFile::exists(fileName); } /** * Loads all options from an XML element * \param base the element to read the options from * \param configName Name of the root element to check for * \param configNS Namespace of the config format * \param configVersion If specified, the function will fail if the file version doesn't match */ bool OptionsTree::loadOptions(const QDomElement& base, const QString& configName, const QString& configNS, const QString& configVersion) { Q_UNUSED(configName); Q_UNUSED(configNS); Q_UNUSED(configVersion); // Version check //if(base.tagName() != configName) // return false; //if(configVersion!="" && base.attribute("version") != configVersion) // return false; //if(configNS!="" && base.attribute("xmlns") != configNS) // return false; // Convert tree_.fromXml(base); return true; } psi-0.14/src/tools/optionstree/optionstreewriter.h0000644000175000017500000000136111305557613020625 0ustar janjan#ifndef OPTIONSTREEWRITER_H #define OPTIONSTREEWRITER_H #include "atomicxmlfile.h" #include class OptionsTree; class VariantTree; class OptionsTreeWriter : public AtomicXmlFileWriter { public: OptionsTreeWriter(const OptionsTree*); void setName(const QString& configName); void setNameSpace(const QString& configNS); void setVersion(const QString& configVersion); // reimplemented virtual bool write(QIODevice* device); protected: void writeTree(const VariantTree* tree); void writeVariant(const QVariant& variant); void writeUnknown(const QString& unknown); void readUnknownTree(QXmlStreamReader* reader); private: const OptionsTree* options_; QString configName_; QString configNS_; QString configVersion_; }; #endif psi-0.14/src/tools/optionstree/optionstest/0000755000175000017500000000000011305557613017236 5ustar janjanpsi-0.14/src/tools/optionstree/optionstest/optionstest.pro0000644000175000017500000000017111305557613022352 0ustar janjanTEMPLATE = app QT -= GUI CONFIG += console CONFIG -= app_bundle include(../optionstree.pri) SOURCES += optionstest.cpp psi-0.14/src/tools/optionstree/optionstest/optionstest.cpp0000644000175000017500000000524311305557613022341 0ustar janjan/* * optionstest.cpp - Test class for OptionsTree * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "optionstree.h" int main (int argc, char const* argv[]) { OptionsTree tree; QVariantList l; l << QVariant(QString("item1")) << qVariantFromValue(QKeySequence("CTRL+L")); QStringList sl; sl << "String 1" << "String 2"; tree.setOption("paris",QVariant(QString("sirap"))); tree.setOption("Benvolio",QVariant(QString("Benvolio"))); tree.setOption("Benvolio",QVariant(QString("Not benvolio!!"))); tree.setOption("capulet.Juliet",QVariant(QString("girly"))); tree.setOption("verona.montague.romeo",QVariant(QString("poisoned"))); tree.setOption("capulet.Nursey",QVariant(QString("matchmaker"))); //should fail, values can't have subnodes tree.setOption("capulet.Juliet.dead",QVariant(true)); tree.setOption("verona.city",QVariant(true)); tree.setOption("verona.lovers",QVariant(2)); tree.setOption("verona.size",QVariant(QSize(210,295))); tree.setOption("verona.stuff",l); tree.setOption("verona.stringstuff",sl); tree.setComment("verona","Fair city"); tree.setComment("paris","Bloke or city?"); tree.setComment("verona.montague.romeo","Watch what this one drinks"); foreach(QString name, tree.allOptionNames()) { qWarning(qPrintable(name)); qWarning(qPrintable(tree.getOption(name).toString())); } tree.saveOptions("options.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); OptionsTree tree2; tree2.loadOptions("options.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); foreach(QString name, tree2.allOptionNames()) { qWarning(qPrintable(name)); qWarning(qPrintable(tree2.getOption(name).toString())); } tree2.saveOptions("options2.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); OptionsTree tree3; tree3.loadOptions("options.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); tree3.saveOptions("options3.xml","OptionsTest","http://psi-im.org/optionstest","0.1"); return 0; } psi-0.14/src/tools/optionstree/optionstreewriter.cpp0000644000175000017500000000734111305557613021164 0ustar janjan#include "optionstreewriter.h" #include #include #include #include #include "optionstree.h" #include "varianttree.h" #include "xmpp/base64/base64.h" OptionsTreeWriter::OptionsTreeWriter(const OptionsTree* options) : options_(options) { Q_ASSERT(options_); } void OptionsTreeWriter::setName(const QString& configName) { configName_ = configName; } void OptionsTreeWriter::setNameSpace(const QString& configNS) { configNS_ = configNS; } void OptionsTreeWriter::setVersion(const QString& configVersion) { configVersion_ = configVersion; } bool OptionsTreeWriter::write(QIODevice* device) { setDevice(device); // turn it off for even more speed setAutoFormatting(true); setAutoFormattingIndent(1); writeStartDocument(); writeDTD(QString("").arg(configName_)); writeStartElement(configName_); writeAttribute("version", configVersion_); writeAttribute("xmlns", configNS_); writeTree(&options_->tree_); writeEndDocument(); return true; } void OptionsTreeWriter::writeTree(const VariantTree* tree) { foreach(QString node, tree->trees_.keys()) { Q_ASSERT(!node.isEmpty()); writeStartElement(node); if (tree->comments_.contains(node)) writeAttribute("comment", tree->comments_[node]); writeTree(tree->trees_[node]); writeEndElement(); } foreach(QString child, tree->values_.keys()) { Q_ASSERT(!child.isEmpty()); writeStartElement(child); if (tree->comments_.contains(child)) writeAttribute("comment", tree->comments_[child]); writeVariant(tree->values_[child]); writeEndElement(); } foreach(QString unknown, tree->unknowns2_.keys()) { writeUnknown(tree->unknowns2_[unknown]); } } void OptionsTreeWriter::writeVariant(const QVariant& variant) { writeAttribute("type", variant.typeName()); if (variant.type() == QVariant::StringList) { foreach(QString s, variant.toStringList()) { writeStartElement("item"); writeCharacters(s); writeEndElement(); } } else if (variant.type() == QVariant::List) { foreach(QVariant v, variant.toList()) { writeStartElement("item"); writeVariant(v); writeEndElement(); } } else if (variant.type() == QVariant::Size) { writeTextElement("width", QString::number(variant.toSize().width())); writeTextElement("height", QString::number(variant.toSize().height())); } else if (variant.type() == QVariant::Rect) { writeTextElement("x", QString::number(variant.toRect().x())); writeTextElement("y", QString::number(variant.toRect().y())); writeTextElement("width", QString::number(variant.toRect().width())); writeTextElement("height", QString::number(variant.toRect().height())); } else if (variant.type() == QVariant::ByteArray) { writeCharacters(XMPP::Base64::encode(variant.toByteArray())); } else if (variant.type() == QVariant::KeySequence) { QKeySequence k = variant.value(); writeCharacters(k.toString()); } else { writeCharacters(variant.toString()); } } void OptionsTreeWriter::writeUnknown(const QString& unknown) { QByteArray ba = unknown.toUtf8(); QBuffer buffer(&ba); buffer.open(QIODevice::ReadOnly); QXmlStreamReader reader; reader.setDevice(&buffer); while (!reader.atEnd()) { reader.readNext(); if (reader.isStartElement()) { readUnknownTree(&reader); } } } void OptionsTreeWriter::readUnknownTree(QXmlStreamReader* reader) { Q_ASSERT(reader->isStartElement()); writeStartElement(reader->name().toString()); foreach(QXmlStreamAttribute attr, reader->attributes()) { writeAttribute(attr.name().toString(), attr.value().toString()); } while (!reader->atEnd()) { writeCharacters(reader->text().toString()); reader->readNext(); if (reader->isEndElement()) break; if (reader->isStartElement()) readUnknownTree(reader); } writeEndElement(); } psi-0.14/src/tools/optionstree/optionstree.h0000644000175000017500000000604711305557613017376 0ustar janjan/* * optionstree.h - Soft-coded options structure header * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef OPTIONSTREE_H #define OPTIONSTREE_H #include "varianttree.h" /** * \class OptionsTree * \brief Dynamic hierachical options structure * OptionsTree allows the dynamic creation of options (of type QVariant) * and will save and load these to/from xml. */ class OptionsTree : public QObject { Q_OBJECT public: OptionsTree(QObject *parent = 0); ~OptionsTree(); QVariant getOption(const QString& name) const; void setOption(const QString& name, const QVariant& value); bool isInternalNode(const QString &node) const; void setComment(const QString& name, const QString& comment); QString getComment(const QString& name) const; QStringList allOptionNames() const; QStringList getChildOptionNames(const QString& = QString(""), bool direct = false, bool internal_nodes = false) const; bool removeOption(const QString &name, bool internal_nodes = false); static bool isValidName(const QString &name); // Map helpers QString mapLookup(const QString &basename, const QVariant &key) const; QString mapPut(const QString &basename, const QVariant &key); void mapPut(const QString &basename, const QVariant &key, const QString &node, const QVariant &value); QVariant mapGet(const QString &basename, const QVariant &key, const QString &node) const; QVariant mapGet(const QString &basename, const QVariant &key, const QString &node, const QVariant &def) const; QVariantList mapKeyList(const QString &basename) const; bool saveOptions(const QString& fileName, const QString& configName, const QString& configNS, const QString& configVersion, bool streamWriter = false) const; bool loadOptions(const QString& fileName, const QString& configName, const QString& configNS = "", const QString& configVersion = "", bool streamReader = false); bool loadOptions(const QDomElement& name, const QString& configName, const QString& configNS = "", const QString& configVersion = ""); static bool exists(QString fileName); signals: void optionChanged(const QString& option); void optionAboutToBeInserted(const QString& option); void optionInserted(const QString& option); void optionAboutToBeRemoved(const QString& option); void optionRemoved(const QString& option); private: VariantTree tree_; friend class OptionsTreeReader; friend class OptionsTreeWriter; }; #endif psi-0.14/src/tools/optionstree/varianttree.h0000644000175000017500000000637511305557613017353 0ustar janjan/* * varianttree.h - Tree structure for QVariants and Comments * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _VARIANTTREE_H_ #define _VARIANTTREE_H_ #include #include #include class QDomDocument; class QDomElement; class QDomDocumentFragment; /** * \class VariantTree * \brief A recursive structure for storing QVariants in trees, with comments * * All the methods in this class are recursive, based on a hierachy delimited * with dots in the node name. As such, the nodes "Paris" and "Benvolio" are * top level elements (members of this layer), while "Capulet.Juliet" is a * member of a deeper node ("Capulet") and "Verona.Montague.Romeo" represents * the node "Romeo" which is a member of "Montague", which is again a member * of "Verona" (which is a member of this layer). * * As such, for each function, if the supplied node contains a dot ("."), * the node name is split at the first (if there are several) dot, with the * remainder passed to the same method of the member of this node with the * name given by the primary component. For the set methods, multiple layers * in the hierachy may be created implicitly if the node is not found. */ class VariantTree : public QObject { Q_OBJECT public: VariantTree(QObject *parent = 0); ~VariantTree(); void setValue(QString node, QVariant value); QVariant getValue(const QString& node) const; bool isInternalNode(QString node) const; void setComment(QString node, QString comment); QString getComment(QString node) const; bool remove(const QString &node, bool internal_nodes = false); QStringList nodeChildren(const QString& node = "", bool direct = false, bool internal_nodes = false) const; void toXml(QDomDocument &doc, QDomElement& ele) const; void fromXml(const QDomElement &ele); static bool isValidNodeName(const QString &name); static const QVariant missingValue; static const QString missingComment; protected: static QVariant elementToVariant(const QDomElement&); static void variantToElement(const QVariant&, QDomElement&); static bool getKeyRest(const QString& node, QString &key, QString &rest); private: QHash trees_; QHash values_; QHash comments_; QHash unknowns_; // unknown types preservation QHash unknowns2_; // unknown types preservation // needed to have a document for the fragments. static QDomDocument *unknownsDoc; friend class OptionsTreeReader; friend class OptionsTreeWriter; }; #endif /* _VARIANTTREE_H_ */ psi-0.14/src/tools/optionstree/optionstree.pri0000644000175000017500000000061611305557613017735 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/optionstree.h \ $$PWD/varianttree.h \ $$PWD/optionstreereader.h \ $$PWD/optionstreewriter.h SOURCES += $$PWD/optionstree.cpp \ $$PWD/varianttree.cpp \ $$PWD/optionstreereader.cpp \ $$PWD/optionstreewriter.cpp # Model/view classes HEADERS += $$PWD/optionstreemodel.h SOURCES += $$PWD/optionstreemodel.cpp QT += xml psi-0.14/src/tools/optionstree/optionstreeviewtest/0000755000175000017500000000000011305557613021011 5ustar janjanpsi-0.14/src/tools/optionstree/optionstreeviewtest/optionstreeviewtest.pro0000644000175000017500000000017311305557613025702 0ustar janjanTEMPLATE = app OPTIONSTREE_CPP = .. CONFIG += optionstree include(../optionstree.pri) SOURCES += optionstreeviewtest.cpp psi-0.14/src/tools/optionstree/optionstreeviewtest/optionstreeviewtest.cpp0000644000175000017500000000200311305557613025656 0ustar janjan#include #include #include #include #include #include "optionstree.h" #include "optionstreemodel.h" class MyHeaderViewWidget : public QWidget { Q_OBJECT public: MyHeaderViewWidget(QWidget* parent = 0) : QWidget(parent) { o_.loadOptions("../options.xml","OptionsTest", "", "0.1"); tm_ = new OptionsTreeModel(&o_); QVBoxLayout* layout = new QVBoxLayout(this); tv_ = new QTreeView(this); tv_->setModel(tm_); tv_->setAlternatingRowColors(true); layout->addWidget(tv_); cb_ = new QCheckBox(this); cb_->setText(tr("Flat")); connect(cb_,SIGNAL(toggled(bool)),tm_,SLOT(setFlat(bool))); layout->addWidget(cb_); } ~MyHeaderViewWidget() { o_.saveOptions("../options.xml","OptionsTest", "", "0.1"); } private: OptionsTree o_; QTreeView* tv_; OptionsTreeModel* tm_; QCheckBox* cb_; }; int main(int argc, char* argv[]) { QApplication app(argc,argv); MyHeaderViewWidget w; w.resize(600,300); w.show(); return app.exec(); } psi-0.14/src/tools/optionstree/optionstreemodel.cpp0000644000175000017500000002017211305557613020745 0ustar janjan/* * optionstreemodel.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "optionstreemodel.h" #include #include "optionstree.h" // Enable this if you have Trolltech Labs' ModelTest and are not going // to distribute the source or binary. You need to include modeltest.pri // somewhere too. //#define HAVE_MODELTEST #ifdef HAVE_MODELTEST #include #endif OptionsTreeModel::OptionsTreeModel(OptionsTree* tree, QObject* parent) : QAbstractItemModel(parent), tree_(tree), flat_(false), nextIdx(0) { connect(tree_, SIGNAL(optionChanged(const QString&)), SLOT(optionChanged(const QString&))); connect(tree_, SIGNAL(optionAboutToBeInserted(const QString&)), SLOT(optionAboutToBeInserted(const QString&))); connect(tree_, SIGNAL(optionInserted(const QString&)), SLOT(optionInserted(const QString&))); connect(tree_, SIGNAL(optionAboutToBeRemoved(const QString&)), SLOT(optionAboutToBeRemoved(const QString&))); connect(tree_, SIGNAL(optionRemoved(const QString&)), SLOT(optionRemoved(const QString&))); #ifdef HAVE_MODELTEST new ModelTest(this, this); #endif } void OptionsTreeModel::setFlat(bool b) { if (flat_ != b) { flat_ = b; reset(); } } /** * Get the parent option of @a option * @param option the option name to be splitted * @return the part of option until the last dot (or empty) */ QString OptionsTreeModel::getParentName(const QString &option) const { QString parentname; int dot_index = option.lastIndexOf('.'); if (dot_index != -1) { parentname = option.left(dot_index); } return parentname; } /** * Get index of given @a option * @param option the option to retrieve the index for * @param sec Section the new index should point to * @return a QModelIndex to @a option */ QModelIndex OptionsTreeModel::index(const QString &option, Section sec) const { if (option.isEmpty()) { return QModelIndex(); } if (flat_) { QStringList options = tree_->getChildOptionNames("",false,false); options.sort(); int row = options.indexOf(option); return createIndex(row, sec, nameToIndex(options.at(row))); } else { QString parentname(getParentName(option)); QStringList children = tree_->getChildOptionNames(parentname,true,true); children.sort(); int row = children.indexOf(option); return createIndex(row, sec, nameToIndex(option)); } } Qt::ItemFlags OptionsTreeModel::flags(const QModelIndex& index) const { if (!index.isValid()) { // Root item return 0; } Qt::ItemFlags f = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if ((index.column() == Value) && !internalNode(indexToOptionName(index))) f |= Qt::ItemIsEditable; return f; } int OptionsTreeModel::rowCount(const QModelIndex& parent) const { if ((Section)parent.column() == Name || !parent.isValid()) { if (flat_) { return (parent.isValid() ? 0 : tree_->getChildOptionNames("",false,false).count()); } else { QString option; if (parent.isValid()) option = indexToOptionName(parent); return tree_->getChildOptionNames(option,true,true).count(); } } return 0; } int OptionsTreeModel::columnCount(const QModelIndex&) const { return 4; } QVariant OptionsTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); QString option = indexToOptionName(index); Section section = (Section) index.column(); if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) { if (section == Name) { if (flat_) { return option; } else { int dot_index = option.lastIndexOf('.'); return option.mid(dot_index + 1); } } else if (section == Comment) { return tree_->getComment(option); } else if (!tree_->isInternalNode(option)) { if (section == Type) return tree_->getOption(option).typeName(); else if (section == Value) return tree_->getOption(option);//.toString(); } } else if (role == Qt::ToolTipRole) { if (!tree_->isInternalNode(option)) { return tree_->getComment(option); } } return QVariant(); } QVariant OptionsTreeModel::headerData(int s, Qt::Orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); Section section = (Section) s; switch (section) { case Name: return tr("Name"); case Type: return QString(tr("Type")); case Value: return QString(tr("Value")); case Comment: return QString(tr("Comment")); default: return QVariant(); } } QModelIndex OptionsTreeModel::index(int row, int column, const QModelIndex & parent) const { if (column < 0 || column >= SectionBound || row < 0) { return QModelIndex(); } int id = 0; QStringList options; if (flat_) { options = tree_->getChildOptionNames("",false,false); } else { QString parent_option; if (parent.isValid()) { parent_option = indexToOptionName(parent); } options = tree_->getChildOptionNames(parent_option,true,true); } if (row >= options.size()) { return QModelIndex(); } options.sort(); id = nameToIndex(options.at(row)); return createIndex(row,column,id); } QModelIndex OptionsTreeModel::parent(const QModelIndex& modelindex) const { if (!modelindex.isValid() || flat_) return QModelIndex(); QString option = indexToOptionName(modelindex); QString parent_option = getParentName(option); return index(parent_option); } bool OptionsTreeModel::setData ( const QModelIndex & index, const QVariant & value, int role) { QString option = indexToOptionName(index); if ((role != Qt::EditRole) || ((Section) index.column() != Value) || internalNode(option)) { return false; } QVariant current = tree_->getOption(option); QVariant newval = value; if (!newval.canConvert(current.type())) { qWarning("Sorry don't know how to do that!"); return false; } newval.convert(current.type()); tree_->setOption(option, newval); return true; } void OptionsTreeModel::optionAboutToBeInserted(const QString& option) { QString parentname(getParentName(option)); // FIXME? handle cases when parent doesn't exist either. QModelIndex parent(index(parentname)); QStringList children = tree_->getChildOptionNames(parentname,true,true); children << option; children.sort(); int row = children.indexOf(option); emit beginInsertRows(parent, row, row); } void OptionsTreeModel::optionInserted(const QString& option) { Q_UNUSED(option) endInsertRows (); } void OptionsTreeModel::optionAboutToBeRemoved(const QString& option) { QString parentname(getParentName(option)); QModelIndex parent(index(parentname)); QStringList children = tree_->getChildOptionNames(parentname,true,true); children.sort(); int row = children.indexOf(option); if (row != -1) { realRemove.push(true); emit beginRemoveRows(parent, row, row); } else { realRemove.push(false); } } void OptionsTreeModel::optionRemoved(const QString& option) { Q_UNUSED(option) if (realRemove.pop()) endRemoveRows (); } void OptionsTreeModel::optionChanged(const QString& option) { // only need to notify about options the view can possibly know anything about. if (nameMap.contains(option)) { QModelIndex modelindex(index(option, Value)); emit dataChanged(modelindex, modelindex); } } bool OptionsTreeModel::internalNode(QString option) const { return tree_->isInternalNode(option); } int OptionsTreeModel::nameToIndex(QString name) const { if (!nameMap.contains(name)) { int idx = nextIdx++; //qDebug() << "adding " << name << " as " << idx; nameMap[name] = idx; indexMap[idx] = name; return idx; } else { return nameMap[name]; } } QString OptionsTreeModel::indexToOptionName(QModelIndex idx) const { return indexMap[idx.internalId()]; } psi-0.14/src/tools/optionstree/varianttree.cpp0000644000175000017500000003427111305557613017702 0ustar janjan/* * varianttree.cpp - Tree structure for storing QVariants and comments * Copyright (C) 2006 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "varianttree.h" #include #include #include #include #include #include #include #include #include "xmpp/base64/base64.h" using namespace XMPP; // FIXME: Helpers from xmpp_xmlcommon.h would be very appropriate for // void VariantTree::variantToElement(const QVariant& var, QDomElement& e) // void VariantTree::elementToVariant(const QVariant& var, QDomElement& e) QDomDocument *VariantTree::unknownsDoc=0; /** * Default Constructor */ VariantTree::VariantTree(QObject *parent) : QObject(parent) { } /** * Default Destructor */ VariantTree::~VariantTree() { foreach(VariantTree* vt, trees_.values()) { delete vt; } } /** * Split a @a node into local key and rest * @param node * @param key part of the @a node before first dot * @param rest part of the @a node after first dot * @return */ bool VariantTree::getKeyRest(const QString& node, QString &key, QString &rest) { int idx = node.indexOf(QChar('.')); if (idx != -1) { key=node.left(idx); rest=node.mid(idx+1); return true; } return false; } bool VariantTree::isValidNodeName(const QString &name) { /* XML backend: [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender [5] Name ::= (Letter | '_' | ':') (NameChar)* but we don't want to have namespaces in the node names.... but for now just allow ascii subset of this: */ if (name.isEmpty()) return false; int len = name.length(); QString other(".-_"); QChar ch = name[0]; if (!((ch>='A' && ch<='Z') || (ch>='a' && ch<='z') || (ch=='_'))) return false; for (int i=1; i < len; i++) { ch = name[i]; if (!((ch>='A' && ch<='Z') || (ch>='a' && ch<='z') || (other.contains(ch)) || (ch >= '0' && ch <= '9'))) return false; } return true; } /** * Set @a node to value @a value */ void VariantTree::setValue(QString node, QVariant value) { QString key, subnode; if (getKeyRest(node, key, subnode)) { //not this tier Q_ASSERT(isValidNodeName(key)); if (!trees_.contains(key)) { if (values_.contains(key)) { qWarning() << QString("Error: Trying to add option node %1 but it already exists as a value").arg(key); return; } //create a new tier trees_[key]=new VariantTree(this); } //pass it down a level trees_[key]->setValue(subnode,value); } else { //this tier Q_ASSERT(isValidNodeName(node)); if (trees_.contains(node)) { qWarning() << QString("Error: Trying to add option value %1 but it already exists as a subtree").arg(node); return; } values_[node]=value; } } /** * Get value at @a node * @return the value of @a node if @a node exists, otherwise VariantTree::missingValue */ QVariant VariantTree::getValue(const QString& node) const { QString key,subnode; if (getKeyRest(node, key, subnode)) { //not this tier if (trees_.contains(key)) { return trees_[key]->getValue(subnode); } } else { //this tier if (values_.contains(node)) return values_[node]; } return missingValue; } bool VariantTree::remove(const QString &node, bool internal_nodes) { QString key,subnode; if (getKeyRest(node, key, subnode)) { //not this tier if (trees_.contains(key)) { return trees_[key]->remove(subnode, internal_nodes); } } else { //this tier if (values_.contains(node)) { values_.remove(node); return true; } else if (internal_nodes && trees_.contains(node)) { trees_.remove(node); return true; } } return false; } /** * @return true iff the node @a node is an internal node (i.e. has a child tree). */ bool VariantTree::isInternalNode(QString node) const { QString key,subnode; if (getKeyRest(node, key, subnode)) { //not this tier if (trees_.contains(key)) { return trees_[key]->isInternalNode(subnode); } qWarning("isInternalNode called on non existant node: %s", qPrintable(node)); return false; } else { return trees_.contains(node); } } /** * \brief Sets the comment of the specified node. * \param name "Path" to the node * \param comment the comment to store */ void VariantTree::setComment(QString node, QString comment) { if (node.contains(QChar('.'))) { //not this tier QString key=node.left(node.indexOf(QChar('.'))); QString subnode=node.remove(0,node.indexOf(QChar('.'))+1); Q_ASSERT(isValidNodeName(key)); if (!trees_.contains(key)) { if (values_.contains(key)) { qWarning() << QString("Error: Trying to add option node %1 but it already exists as a value").arg(key); return; } //create a new tier trees_[key]=new VariantTree(this); } //pass it down a level trees_[key]->setComment(subnode,comment); } else { //this tier Q_ASSERT(isValidNodeName(node)); comments_[node]=comment; } } /** * Returns the comment associated with a node. * (or a null QString if the node has no comment) */ QString VariantTree::getComment(QString node) const { if (node.contains(QChar('.'))) { //not this tier QString key=node.left(node.indexOf(QChar('.'))); QString subnode=node.remove(0,node.indexOf(QChar('.'))+1); if (trees_.contains(key)) { return trees_[key]->getComment(subnode); } } else { //this tier if (comments_.contains(node)) return comments_[node]; } return QString(); } /** * Find all the children of the provided node \a node or, if no node is provided, * all children. * * \param direct only return direct children * \param internal_nodes include internal (non-final) nodes */ QStringList VariantTree::nodeChildren(const QString& node, bool direct, bool internal_nodes) const { QStringList children; QString key = node; if (!node.isEmpty()) { // Go down further QString subnode; if (node.contains('.')) { key = node.left(node.indexOf(QChar('.'))); subnode = node.right(node.length() - node.indexOf(QChar('.')) - 1); } if (trees_.contains(key)) { children = trees_[key]->nodeChildren(subnode,direct,internal_nodes); } } else { // Current tree foreach (QString subnode, trees_.keys()) { if (internal_nodes) children << subnode; if (!direct) children += nodeChildren(subnode,direct,internal_nodes); } foreach (QString child, values_.keys()) { children << child; } } if (key.isEmpty()) { return children; } else { QStringList long_children; foreach (QString child, children) { QString long_child = QString("%1.%2").arg(key).arg(child); long_children << long_child; } return long_children; } } /** * */ void VariantTree::toXml(QDomDocument &doc, QDomElement& ele) const { // Subtrees foreach (QString node, trees_.keys()) { Q_ASSERT(!node.isEmpty()); QDomElement nodeEle = doc.createElement(node); trees_[node]->toXml(doc, nodeEle); if (comments_.contains(node)) nodeEle.setAttribute("comment",comments_[node]); ele.appendChild(nodeEle); } // Values foreach (QString child, values_.keys()) { Q_ASSERT(!child.isEmpty()); QVariant var = values_[child]; QDomElement valEle = doc.createElement(child); variantToElement(var,valEle); ele.appendChild(valEle); if (comments_.contains(child)) valEle.setAttribute("comment",comments_[child]); } // unknown types passthrough foreach (QDomDocumentFragment df, unknowns_) { ele.appendChild(doc.importNode(df, true)); } } /** * * @param ele */ void VariantTree::fromXml(const QDomElement &ele) { QDomElement child = ele.firstChildElement(); while (!child.isNull()) { bool isunknown=false; QString name = child.nodeName(); Q_ASSERT(!name.isEmpty()); if (!child.hasAttribute("type")) { // Subnode if ( !trees_.contains(name) ) trees_[name] = new VariantTree(this); trees_[name]->fromXml(child); } else { // Value QVariant val; val = elementToVariant(child); if (val.isValid()) { values_[name] = val; } else { isunknown = true; if (!unknownsDoc) unknownsDoc = new QDomDocument(); QDomDocumentFragment frag(unknownsDoc->createDocumentFragment()); frag.appendChild(unknownsDoc->importNode(child, true)); unknowns_[name] = frag; } } // Comments if (!isunknown && child.hasAttribute("comment")) { QString comment=child.attribute("comment"); comments_[name]=comment; } child=child.nextSiblingElement(); } } /** * Extracts a variant from an element. * The attribute of the element is used to determine the type. * The tagname of the element is ignored. */ QVariant VariantTree::elementToVariant(const QDomElement& e) { QVariant value; QString type = e.attribute("type"); if (type == "QStringList") { QStringList list; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull() && e.tagName() == "item") { list += e.text(); } } value = list; } else if (type == "QVariantList") { QVariantList list; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull() && e.tagName() == "item") { QVariant v = elementToVariant(e); if (v.isValid()) list.append(v); } } value = list; } else if (type == "QSize") { int width = 0, height = 0; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull()) { if (e.tagName() == "width") { width = e.text().toInt(); } else if (e.tagName() == "height") { height = e.text().toInt(); } } } value = QVariant(QSize(width,height)); } else if (type == "QRect") { int x = 0, y = 0, width = 0, height = 0; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull()) { if (e.tagName() == "width") { width = e.text().toInt(); } else if (e.tagName() == "height") { height = e.text().toInt(); } else if (e.tagName() == "x") { x = e.text().toInt(); } else if (e.tagName() == "y") { y = e.text().toInt(); } } } value = QVariant(QRect(x,y,width,height)); } else if (type == "QByteArray") { value = QByteArray(); for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isText()) { value = Base64::decode(node.toText().data()); break; } } } else { // Standard values QVariant::Type varianttype; bool known = true; if (type=="QString") { varianttype = QVariant::String; } else if (type=="bool") { varianttype = QVariant::Bool; } else if (type=="int") { varianttype = QVariant::Int; } else if (type == "QKeySequence") { varianttype = QVariant::KeySequence; } else if (type == "QColor") { varianttype = QVariant::Color; } else { known = false; } if (known) { for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { if ( node.isText() ) value=node.toText().data(); } if (!value.isValid()) value = QString(""); value.convert(varianttype); } else { value = QVariant(); } } return value; } /** * Modifies the element e to represent the variant var. * This method adds an attribute 'type' and contents to the element. */ void VariantTree::variantToElement(const QVariant& var, QDomElement& e) { QString type = var.typeName(); if (type == "QVariantList") { foreach(QVariant v, var.toList()) { QDomElement item_element = e.ownerDocument().createElement("item"); variantToElement(v,item_element); e.appendChild(item_element); } } else if (type == "QStringList") { foreach(QString s, var.toStringList()) { QDomElement item_element = e.ownerDocument().createElement("item"); QDomText text = e.ownerDocument().createTextNode(s); item_element.appendChild(text); e.appendChild(item_element); } } else if (type == "QSize") { QSize size = var.toSize(); QDomElement width_element = e.ownerDocument().createElement("width"); width_element.appendChild(e.ownerDocument().createTextNode(QString::number(size.width()))); e.appendChild(width_element); QDomElement height_element = e.ownerDocument().createElement("height"); height_element.appendChild(e.ownerDocument().createTextNode(QString::number(size.height()))); e.appendChild(height_element); } else if (type == "QRect") { QRect rect = var.toRect(); QDomElement x_element = e.ownerDocument().createElement("x"); x_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.x()))); e.appendChild(x_element); QDomElement y_element = e.ownerDocument().createElement("y"); y_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.y()))); e.appendChild(y_element); QDomElement width_element = e.ownerDocument().createElement("width"); width_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.width()))); e.appendChild(width_element); QDomElement height_element = e.ownerDocument().createElement("height"); height_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.height()))); e.appendChild(height_element); } else if (type == "QByteArray") { QDomText text = e.ownerDocument().createTextNode(Base64::encode(var.toByteArray())); e.appendChild(text); } else if (type == "QKeySequence") { QKeySequence k = var.value(); QDomText text = e.ownerDocument().createTextNode(k.toString()); e.appendChild(text); } else { QDomText text = e.ownerDocument().createTextNode(var.toString()); e.appendChild(text); } e.setAttribute("type",type); } const QVariant VariantTree::missingValue=QVariant(QVariant::Invalid); psi-0.14/src/tools/iconset/0000755000175000017500000000000011305557613013734 5ustar janjanpsi-0.14/src/tools/iconset/unittest/0000755000175000017500000000000011305557613015613 5ustar janjanpsi-0.14/src/tools/iconset/unittest/iconsets/0000755000175000017500000000000011305557613017442 5ustar janjanpsi-0.14/src/tools/iconset/unittest/iconsets/system/0000755000175000017500000000000011305557613020766 5ustar janjanpsi-0.14/src/tools/iconset/unittest/iconsets/system/crystal_system.jisp0000644000175000017500000022262411305557613024752 0ustar janjanPK 50crystal_system/UT @=@Uxn'+PK[S0 bXcrystal_system/editclear.pngUT Nw@:@Uxn'+ sb``p ҂@,$,b)tG_GY||7b !Z H 7?3Nɼ(^~_Aij˴@!$owgy.!dh,u돩I ER9Sdfym`agCCF曓YV W9)1,wdPPcqWf;oqhOW?uN MPK K0*E crystal_system/changeacc.pngUT  @:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<}IDATxb?2cv623Ҵ`aūO?9y%? @C~?>mt%utd‘!ŠaB`{}?+3d[S3E1+L@1\b\"bx ? 0} ]d`faePUѓg CMMUGR  þC?89j8X~0|z_v.n1~&]>]OH.U5=-MVfFvn^P6NV&q^ ڎ/<2ƚO_1|AGT߆+Ë7>| ^*j \<ܪ.@axÂ.. n`X]ATǟ R lo@zlǟ}qADJARV!h6 gN>2x93 I}p+n1<쏧o~\ٲ' ĕXDĤ LXX~}?2\ n]mf}{._Y3(+#K_.w O~߷uͿ޿````=K{>z hs?xֿru6cdNnV6a_30>uŻW  ‘k<=Kj, ?՚׀ʣ F zʼB"fxӓ5t]+sCIENDB`PK [S0VScrystal_system/time.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<RIDAT8OL[u^_/-뜨H72EaŸxVn'&F=(]4p iDc&3eM[ھ#&&f0ME2B^M8R5#;\w&'oH3#艎zà\7W Jlj&}1ɥSRJMbLI  Dy*tǻǺ{@hf $ulA7aoF(L'}뺷@*ed,ԙܮb1 _R ; F>§^$L58 ],2wl՜4 IjRjj \]eRr` {P^ V=ngQRC0ߤaT,Ľ{|w_'| ) Ejk KtU#Z.3U -.8NSqqbpqel Uޤ#$;Di)Wx\:> ^nG+nR*WMõ ǹE8}}` (T o=4q%һ Y?Mߙr;#t;<*AlVWpMXcc_ݜMd;dr=>5t*HhZ 7iˬGf]p^:ʅ@01 CJU3O&gwk 򴢨]`:Aj5 `@d NIENDB`PK [S0! Hcrystal_system/arrow_up.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs ,tIME +w-bKGDeIDAT8˅SKSqO!!BoAEs6b *z ݵf–V,DAJДtFfVn57=Wss=s9KxɯF3V*Nyi?N98 @h ??z=jqdoݼmz#'osHgʈ0K-F$M5!ݶmjܙL09=/=]$jL{۩LedPR:ǦѝQw;ܘGRi}I=FaoSlzc>"EXrw 4pږWp_z":sBֆoHa4D<t("9 Pb椱R^#Sr?Yg`bՖW}lZ`%|{g=QGrXNQ N46M#W|X(J򆎛\@$4Ϻޣ^@k.3F Q[0 VEӦћf"[JB >IENDB`PK [S0ҕ__crystal_system/psimain.pngUT Nw@:@Uxn'+PNG  IHDRobKGD pHYs  d_tIME  IDATxOhu??ɛMmtzݟ(8wSAޤz30P)dhh!)Mtk%M^䛌n~O'^=ȡ}zQ]*^:O]ZptR(N5$9<[۷ׯ/?_^Ł_;x`_y#0ͼ9=l[_<>-m꾾\{z@{/_89c5z #>yqڤ\Tgr̯~zn l_kg6-;>8đ pۅv洛 gl@()oB)L%ẋeZJ#7v/ :h#R4Z4c!@}@pA:~0PAp,2dt$ꊌ2RW?觧t6^͞?C5:f&\i&''[oL$mO}~H`j>`o~Ep9u.hIENDB`PK [S0  crystal_system/play_sounds.pngUT Nw@:@Uxn'+PNG  IHDR;mG pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb? R L-|\ fDW@L 8@ C1PH Y |डqbvlj!30qr\%Ӑ?.zaZi d_G  .CYxf olj[aP5fd* 2 Y3###,]Ci}7,gv v* 2lǐT5~pBK?^w3 ߭c%C(P,A#LDt5[/0XyD@d"s @a@~?e`q=Pf8" C"c!o0|_B|͈fŐne N>z 00܍0HbACv}h@(3k{1|:  =.+]Q&p懥3B ؽ;b^]gत& 3ã;/\p=N td ?Hݟ w}/@! y5ڜIENDB`PK [S0{ԍ88crystal_system/browse.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% XT1X0|/Ьc'^2Xd'_X8X}>v#uo}uh8?b߼_ q_9YQׯ v V_Yt?FEĢʛ/?  ??I d˗@'108:7@  &6V/L  ~`)_GRW[o?@C/ëtD,$0# 0@t oy0X(Á @/T~p)qn}fQUF  @~s2:O f/_ @sGt`e4{sßOXA?++fv1| r< : 21 A{! h4y؅N\g`xà wcxó><|{!#.c3d*Ѐ1ǯ ~gJ8l$.ƿs/by'*?P 3w0 70&_0>y;܀\4$8} 7`}H߿~,3#@U4733 D (yp{S3nv&`S_7d C0gdeamIENDB`PK [S0Qcrystal_system/editcut.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<lIDAT8KqnS"%v/*N^ukA`%%%jid^!,uti6$at3#~σ "tb=pg,&ޢwaWU#J}Aղz"e=x=սVDp+-4iœQ- &JFރGJn'+p\q^j-Ի@ T015آ7TxR .L&{GTgXeQk:V rPdAJJ!Sh0 `b mϊ0/5C4}}tJ/2w U+*ͳXh}k?C#7s ֺO{y!%3!!7o߀le hNj 7^abb ׺8-Bp̭"P70? JQV`x mW]cyw/@1)2ʊ>d(igdbe`Rb#ïTaÖ7>][ :@z.pg`J20s*IF`}WΒP`x[gy};PWboj?dXN1YQf]-_@ / TsRb|879:uzOV>#8E mڎ~]2 XY>xd)u`4~wд3 1|f7P9p(@,`dgggdf͗_O102013)3b l{nbqҿmr#ߟ~~mέg0_^{Tq L`,ECEMVEi~XaBF FvlY3mENvCsjPs$@,gJ~030i2%(,\_ _Gmbz}d_x~p%}__: x<Ҧ_a27mS1B5&uz$UjE7XJ2NO5:']fls^d/|X'ן߳Lj_',7&H_~tBSU!]wNs3h@I>ie+VlY-NC^ >y#U1gTQa9>vh|m{s4>_A@YD(MYJ`0] n4 WM0S[3tS<2 Ԟ!F7vD9f+p?Df0q9zcT,*;YVlO%F {1>uɆ:ږ8{3 +^O8O|K[ `ܺUN36 0) э3V԰{ʉZphشEj[s@WGә7h E5^8p&cכ]zΩ(.Z2S$) -:FX*ZlxݾŢ7oɆ7I7ģ^˻IضxSK0;fNbDkDwdmv^dWF2NkΙHQGݏ7azu Ͷ/*3x7L$xD3`w =:iES4̡73O&zn垡eл1 إ5G|=xħ()OgQOq82 = k%\fRRjb Vډ&PK [S0˗qcrystal_system/search.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8e{Lǿ2G5n`TNV X bp$\q.im!&_RWD_8m&Mi&9J97ӪF{cQ\V^ީKi]^~L\򩙜]&[kS]²nKMMw_||ѱԝoөD4[5򩉜6li%jx-@TbWzz#"6*{4'&g6`WY=j#|b{С\&P&SSg4'+䌑\q7ƭpgt.~}}cٮ 6~?ne~ݷ,^*;~dvB*l񍨬̳!y^o ئYߚYq-WHߌ3f8R`;z``bM kSj+C\ m'XiY-xN%& b-Րɢ}T[!ƽp%~>+S],D|6Mڽ8i81`l()c ;絗PPyIДqrY {lR MI){3 .Em[:ᓚNԔqbSE, ;w}xC&W%Sž t/IZBȌ%%M񅜛[""R r*b%l8*ej(!!)FX\$ J 7! H$;qTlt% %5jtIENDB`PK [S0ũHcrystal_system/play.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  d_gAMA|Q cHRMz%u0`:o_FkIDATxb?0222Cy>7_>i*2r1(+2MЄ &,@AB!;YD7`so?=H,2e3@Q @X '` Dx0GYzZj? 02{E-@a50~@2;d|x/X ;w6ZjO~ ?h 9ƛ~| p |f`FQ @X 5ϟ@# ^?'T ad ,=WOR:`#/wA!n@ +)!*9B4@RսK_/>qǗaߙ9 "k yy IZZV[YGyN0?$8  %j}D3Ͽ00/p4ٞϰ ~0|`虃H 7*L?wO^2>{[x3܀W׆qBYKW<}pණNiπ#Rv_@́?_{p2l #`CX>IENDB`PK [S0@@crystal_system/reload.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs ,tIME AbKGDCIDAT8mSKQ/"(Aoك|..BL(ɗQcGA!(fb~hzXNE$tfiMMۜkΝ8{ι~(0JS3 c0˖Se2Qakd|J.p n_Ɠ e¤'yBow ÿGE0lCH9KJJϦ1i[+0Vw͏]:fupAL$kr``j&+OX1= 'Hm,8bMvpoL=IMJ!kbȸIkq-D-d/WU=II}0Bhmwrkk+ᐐd\B(GM0Ӆ_IDATxڅ_HSqǿ۽s.ݝ;r$h. ՞k>CHЋK"ɇcX {t>$8)2 4tKt89G}f2n|>aDBdt:=L]ܬ~Qw +++zAp{S Tjp,+hQ{mmml.naaw040{3 ^G,v6?/Ib6.55Xm PT`/Ʊ[>#(a9V}=Ib[J܁DT谞$0<4.\^߀(#"ܭTdߏ pP4bXR2\bY Ȭ<##`ffFpݵͽGa>M&JEfhny @ʔh4J#1͏tT-9VWBv:-@zzAb1DA544J\[UomltrBTeD #@Oj zoIENDB`PK [S0Icrystal_system/editdelete.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  ~tIMEQ8bKGDpIDAT8KNP. ]FGn8rN `O4J@^RV("mR_5)h nswϣ:?%,l ^`2D|Qu?0~a|b0rYhj}ȥ ߥZZ@f%zrÀTGf**.-y_qt'@Ugalg^&{~xp{M$w#-#.)!3(06{' r 1Q {_ d:b %"V*'j=g_XFZ]PRԙa|`a yz>IENDB`PK [S0}crystal_system/ssl_yes.pngUT Nw@:@Uxn'+PNG  IHDRabKGD pHYs  tIME :)6zIDATxڭkQƿɤi0Lj[\ѸrНWE7 u bB( R}$՘L'$$wf=.4Z9w=?;̳H$O&NRd"`bRkoLa,.RW1$Rlvp\ǑRcʓz|(bz$odқ[nGGeTU)o;splq-N&t.|aUd,C-ue҉dd2]P_X5W4GzP(ҏaOfZ+6*n~iU?|Ʒ̨ vZyveI2̨{5j5r-g}q6&OcQ~\mf@B 6 h!Q.09FG_u!pX *(#{C(p5hZ` ݦ-B6CIK \B@씜y2jTΠ\e=Ց hٞH . p.aS p` oC#%`` $y@C+Ag`ۻ,|n@[G@)3՝^MӇP:IENDB`PK [S0"\*crystal_system/arrow_down.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs ,tIME &˫^bKGDsIDAT8uRKSQBB՗B栤OAvi? [d- 5F "&%#MȐ>ԭ9km_ {sx=sy߇aװ_ŚftɧgMVֲ|Jp3'aǀ=Lי.7{Xs lɻ<E7(uu"&ƪZּ2%!"g t?"I~h&o 9| т7֞(NO8&zGҗxAඇ|jtQ@u\N1ڢpiEwppsX1ȂN Zz p@(c(?r9V* (?;۠"<(dz_(@qƠIdM]%8$#6Ǎ@2 : .^ CD1GD041עVGHb`HQ:gb9*o1@[f-}(M$/+EisdtKI} By;eι7+^?,q7zԒ]L5О0u?{aJg9|ߛg$8gvx6c(]IENDB`PK [S0B:  crystal_system/editpaste.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8=he}KrgRإVA**E:":"DJQAq"jE:bXP%䒦t|Nn3~@X\u|C# s;s]Y9ه75zݧg_\2hLSϚ85ًweW1=nEsOyY;~ť-ЃDUY:tGs͡THו^390YKi4уvj4<Ý:v{u: Ay8jLZl m- Co_?v(guڬ$l[!h9HqQFJ5_f^Q~ݱae B54 "kd|HwcpXXpcb֠AJEEwj!Km&}̊Q*j.< =UKy6Coe7 _NIENDB`PK [S0Rcrystal_system/cancel.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  ~tIME )2bKGD&IDAT8uOka'ZU[AQR=x"b.Wѻ*JTh]Ѥ qdSCܼ0733#[+CAh >cL~tV]}l~2_7rhΡt&S]?`^&g gKŴ,z'ȫ  M.EEm`A _>gҹ~IzTn v̰ e|R_fOi;\<S#R-1y'jfm(YpA֧Nmnse0뫪| ^y?-T(lu:3 3T$W*}V8L9ۡA|g Me<#Ց;)_xem;cXfm(8߹4g(nx"awo0P[HjD(Vx"amwƶ- PZ߉"Z6@O$,Θ 5QIaguvO7Θ9 e;@703l*BiIENDB`PK [S0ϝ..crystal_system/pgp.pngUT Nw@:@Uxn'+PNG  IHDR(-S&PLTEvIibuABVi͔ÜɉFekzmn{os|B_vhiw⚇kpUm)KhѡxxƢYqq~|oodO؃Ԙ|ǥ}IdftmǮhrĝxyykgIz{JL_Poh֤_SOLHUBCWRqA_yz0Fo܅i/ġD)"k2e-Ȫe{ P|IR"=X=n)4ZhtRNS@fbKGDH pHYs  ɍItIME &2żpIDATcd@P ~!`kWPqc@P o4a<9Fc 9T#=#~'POm `A12@vz$Pz @,#B%0-tcmDVIENDB`PK [S0 ̻crystal_system/edittrash.pngUT Nw@:@Uxn'+PNG  IHDRagAMA|Q cHRMz%u0`:oFIDAT8mS=oAp!&"i ( R$+2J !;l.oC~ۙ ]^R?aMٲt; &8 km;4O}Og4J<ߣ/^]&XNg8d!2J\9(%bE[gg`@r̒I9<')s{Q 4^iL_ j6@l7iJɄ&8*y}ȥz2₲L(лv$OG167Vֺn J:Y HK qPf~Z-j۴K*JZjFmZ]E]]< + :m/YkN2lč\aa\yD 1k ,`,R'QF9 εEKR'SfviQS` ~+)BJ蟈a@[ Oڅi>[A2`6x(w:}e׈[[@X'+ܧ\?ܼIENDB`PK [S0K%crystal_system/configure_toolbars.pngUT Nw@:@Uxn'+PNG  IHDRVΎW pHYs  d_gAMA|Q cHRMz%u0`:o_FoIDAT8O\e܀ִtb)^H@#k,_` Fp],LlҒbB"1{1bf̹̙b>o&" ~|JOO'F"zRzg';k'jF׭2*>1lNݼbĉnZZbJxa;z{;/uW*|'uh<ތU4էfr(L" V O/SΜ9IdiBwݶzy<5e#j^<*Z_kkd^!H%=ӮwNĖeV]cp z{vqq(DQp+%'ZFMOO3?ڦ#Af.lq ǎrѵ=K Lf^  x871M&cxӣ:Ǝ fnrc!xmOesҼ @I(],jlB:_Sx NKW{VÄ#0RJ8]Me^F1W}{3\+=%RtTt:|y60{#4B03J)~rM<;GD/ĢQX\ZͧP(ir~o{VSR)/B4M5R lԔR Cܺ~{V5;4iPq7߮ m/ )Ljx_m*IENDB`PK K03crystal_system/add.pngUT @:@Uxn'+PNG  IHDRabKGD pHYs  tIME![)IDATxڭSMKQ=CJ"\h%66H+mK7!D$D\6.qGtaZ832`w}sN^;kbj]y3d0 P S!f!f-$w'ȑ ̈́mi@3JEGqE AGޗ:`/>8J&69b"MI׏lf)Hjc 8? N=8qNf]A{^Q@ꈵ \ ZhPz=U5@l5S”'g:xϿ [hf6v̚6Ͱ,eg`AZ9p'nğZ ;IENDB`PK [S0~:!crystal_system/help.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  #utIME 1q,(bKGDGIDAT8ˍKQ](*B73i.]!Ii+e"]di)$0C5I 3#b3יF/<̼gyϱٖgI^c[%-vqr|o 鳹mi3Α"ɁWM&f:#:c_<e},9p٠w4)c`Ф% :/|*/ d{ V,jf }<ʷ3f+TV<:͝%'oQ~3 *g(ȹ r<.c*Τ$\ )&LEDŽÖ^#-SO&>đ^)H2u Pςkl0SG#9zC'Pfb/2bt-I}ņ߂uӠ?țewH#V]aL};C AHR%Ra9CxEhx ^Z=~yESR uo}C?fTg{O{ 47rIENDB`PK K0"a1crystal_system/key.pngUT  @:@Uxn'+PNG  IHDRagAMA7lIDATxAHSqǿmo:ޞ{\c)<]ޡ( (v6A%!V/^6kn鞋|ӗ'Т`8~ZV]55M[^^~);\g<\X,?::B@4}y xF?0#OlfV{{^7a  wE9o&)-,, Zx<. :I(|p8X[[KD"~V:66v$ N'rBPnέ`4; 0 z{{A4@Ql6dY>RU#fO+++JFEvV8UU0F:Nɮ.Růfxh)2$g~d2IMMMeo,--EQ8 Ba_R\n Eggggټj%^]ZY3jH$>ooo7^%A"g tLnłJ\oiIcggr庹zJ qFFF,{]P E0Q$ YH?c777:'0%pl'$&OX䙔 ]]o߁_<(-#d,--㕔IJJm@@l'2vIdPXXй nnn Mgɑ@i;qJcIENDB`PK [S0YZcrystal_system/options.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8KO\uΙs@nZ@ U &Ʀ2qg\G5q Z/""a\wѴO]'VW?cx8пHVqV|%s݀(sxXm{819yk~G~2!@Q+%ǍVlo( 燇( 3;;y!AlZd2iFPA̶Zz s2]U}v˭,*xZRhqfټ3ݫԷb\8O__7ǒ 8:*Qoyst@ܽq8Gё&fPԉ~=Z^J4v)8nv>-z喭''w])4S7ޥn8ފi&_N:&,+/|{f\`(8G"eHh-˹lf,?e\#2:0Z$͵mݠNMq#%Hf׳?ֻۭg*g HlĊ8xB)ol٫ mD({=<PU"־ wmH%@-@:(#DJ ˵żbHj'u@,(nrp⾟8U]axjoIENDB`PKK0Dwcrystal_system/account.pngUT  @:@Uxn'+-{LgׯҾ%G9b%q`6'bE;d&Biad"z)MܒŸY-f-E.A)866+h)-X9OIΓs~iٷ(bKlS<(-1Opׯn&T`lucKlP} l$// %ӏ+CM@@eoHZ%r^G_}T˒IRk:>SU$wfq@,<_y) <~Ǿpeտۊݿs< /XZeg`$险2^m}m$$v ٱ@rÆ@BL|(Hͳn:E=ʊk^s5 P^:"BAE˔1?@hB2}c)sn`Brۏ=&gRZe~Tyu uoM59̣dҲTDaꜻ'CJX& 1<]$ ͼ;ZrcݒW qڶ m4Ͼi^* Z>qM됧s7&g]ѣ({Ĝ\w^$O&V1fVV=P&)XXF)|FF]lF]I ^tEpn-J<οdS37K)`mcFV@ @Qeo6y̨(~4}8R+RAec֝nꇋ(}oq( 읟0tj\=|F ~5* ]Fr$w^;\Pp苄5d[WfnG?&9'gYmN^uwያ:݆?/D f*|[a[~J )mPK [S0|rR##crystal_system/groupchat.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbd RyEc`~̹aO D ;C!Ouu;=ckbO[pg3biV= ح&, SpqN^ۇ,&^veNob1f}8bf#]c;2:A]KE_]8Wex| ' j ~NdwÇO| >  0~L A @f!)$%6155+>b#'`o5Ж`qrs0ZC~p̙E˞G q*gl$(޹p<|⚶ ԞMZV-O P4re(4oQbe+n kͷI&6r/IrbS| @d&B[3c^˰(-T?!C~;_7 [C#?INHDT6J[980ʕ _3m] %|azÊo/O3HavL33')%sk1{_20}.!G)UU?^&g}AKVbq):O @L[ X00$|p Dc~߹( 45EVV vv{.C@ ⎙ ne@ ;b(wr>cvv+? [v0~NڣIENDB`PK [S0LLcrystal_system/tip.pngUT Nw@:@Uxn'+PNG  IHDRaIDATxjSQszI\`MQP-XT| s'Od$NPP "REKKPkI4MOrrĶɁ׿ֿ>ȿJFcce>4ߥ})_)HQ7bn'-󴑸 ͊Fj3nƆ<OMEcx뀻IPuDsXMN5ǐ x߀JKXj~j88 ZwT}R}*1+-V Ooo@~t\*|JJQ-dbYr^τEHA?"ݑE_@ϫ`̬R 4npNH Tx,Vv@}y,Bx-s6{piSz!zRP@>lA)E&2~vW (6QlVy;~\.wܶqh49G IENDB`PK 50̌mmcrystal_system/icon-16.pngUT @:@Uxn'+PNG  IHDRagAMA7bKGDIDATxڅ[Hqq[fKIN6*K(FVґJХV5 bYQTt!tt "eZ5[t6.b^x=Q<XHg@ E@4J4np8VbxvGޭln m8m'M/LuB8==\Tng6\nЋ cV7x8.F@"oxvol|ˍVSTqKQ.++#7_%FDl62)ھF@l6A%!N΀x`K4@%_ $Rb:L+P{8vҔ!W8 p ris ZYhd^O`~T`J+F&S<*"9@er;rssؔ`"p3˘%Ţ s*k*l^ J~;L2tڿnSkNOD&ϖo ^o IENDB`PK [S0 ̻crystal_system/remove.pngUT Nw@:@Uxn'+PNG  IHDRagAMA|Q cHRMz%u0`:oFIDAT8mS=oAp!&"i ( R$+2J !;l.oC~ۙ ]^R?aMٲt; &8 km;4O}Og4J<ߣ/^]&XNg8d!2J\9(%bE[gg`@r̒I9<')s{Q 4^iL_ j6@l7iJɄ&8*y}ȥz2₲L(лv$OG167Vֺn J:Y HK qPf~Z-j۴K*JZjFmZ]E]]< + :m/YkN2lč\aa\yD 1k ,`,R'QF9 εEKR'SfviQS` ~+)BJ蟈a@[ Oڅi>[A2`6x(w:}e׈[[@X'+ܧ\?ܼIENDB`PK K0ggcrystal_system/key_bad.pngUT  @:@Uxn'+PNG  IHDRagAMA7bKGD pHYsHHFk>IDATxڅ[HSƿs[tʜD+h7H`,ˇ^,=dH"(!|(e:KJS6u9$#ZʳE% k>'\tHVTuuul||JJJSRR.E)N1+ZM|>nVXvttU,/... l^kZMݿR[j./a I>$#&=D\^lq^e,rIc2tNpWO4=UҭHݲ +IKvޚTE`m |y=9U{`jx^tG60ָdjkx[ۡ넆ԐӅbN-ež9+'2D#-U8()젗1l ֞&2˲-+@Kx Q4AV&tikll].) ;@ 3T&j11b[Alar4M444\H$9K]&/''dpb*uQiY@NjC)3lXae@M*߽d~)ʪ$2x@< Cuggg^U P#F !vZj2N̂S6,c&10,(E$xN$*lH}\_y.10K *APm|h tL"Gq@ !k7^onT~S9&s[QT( 9d3(WAs@Cv%~Ky2@ !gxT,L`tcK2ss0dR8*j$!Zx2?9A$V6I>o= 8zPXy(T4ih @,+N=m$5M&6^=a`N $)n'Ϗ7MY! 6ᅛpUIH Q~{TS'N7/C \c\YD 8lFF&I Sѧ:Ξ=[qEסC;:rȏ"]]]_c96uڴy?qDQPMM 48.7# @!6*hjjv1z0r݈>=XT P p ;Kp~V eR?nI ێ} ~u`Thi& Px^4>etEXtSoftwareAdobe ImageReadyqe<IENDB`PK [S0 ucrystal_system/vcard.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbdgϦO 4Ʌ,,Lv2b܌ `?399鮮~+nSP ˶,d4M β*(Jotnc6B`Y˗|;wC2R'eJ0 IRJj?z'~ !mcvAA$xp8v8} G^{8mx4%MSz#۲,q" C$AkMDQDE!ZmjJX}Q#R0p]qZ.iR"< R  2$0 s![Ri"r"DkM$ap8\.S1`Yn*ۤiJ$q֚,y,p]uvv(> uw Q!Q$ ^O_n7lnn @%l6i4B`???~ |fyKtL5t:c1A 緼k599yVRSzGecchkk;ŧ_OMM}o1׃Vu~ppW[¿(s>"и9IENDB`PK [S0CWWcrystal_system/history.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbe;_ L  VV|İ_o~002 cP95WG]\ϟ 2" &~.& )~m 䳀ˑ嬨c+&Xci +l*&ҕl @1kK112|pW32Y@L?疠/ -$x e@ ""),#k %bdצ㷿 _4dy%DExAWd`raz ׭xAS]D _ b *B "Pf  K=z;߿޼ ?2|AH \ z ~;3|@Le`ӗV}gs=Ý4А <@WAEVAAEǛ_&b~ƛ>ū@@?w?89X$E9dxT% @/VGO>3 r2<}_@W}AA}).+  3#'Ý$>o8, @,j $ OGNM^>v``22|ș /dx× Wog FC tTtěfax o1po[~ܺv?- F&M/`?C~E'3 ~39痟6wL`%JgXؙT4EsEݓm d}L; KK|UjIENDB`PK [S0$crystal_system/arrow_left.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs ,tIME  f_bKGDPIDAT8RkQޓ)74bC4œPAHȮ5[AF"m*5*9" C FTTzJID55ZClRt|og潙a V\laŨuXlg6[Yq˺ޖ $7\sR3;r˝7 /|!isy⎱ĒXYR!?iNT`pp})8z 2N TR ;d׿ H|DCv3hMZFGpMxX\+WhlA'6:2Jz]#qNp""y^ Ir5ɬO*Eck8q.u>h>P$#79=^sO'S>+!a3EgowׯR` ĭ[1?$1 *<!lUD[[?>nY0a2RAkh۹3KXqy88tI"عs^Gɽ Vk"@(Zq^o9o&).<\DG g?*s_X={FǏ_nKLhkͥCC/y7n<@NN5U)P^~<d¸o;Ֆd[+*'܉()q.-zNg՚"#wH;uܕÇJr]nץ:44N8`'!@~~-**."rsBGM?DN;*/dz!"b7O? ?yk\IENDB`PK [S0D77crystal_system/icon_mac.pngUT Nw@:@Uxn'+PNG  IHDR>agAMA7tEXtSoftwareAdobe ImageReadyqe<7%IDATx} dUuZzfeAT>P0F(~bFI/g0!P a% 0+30[O{~s}U{{ ޯ{j9=\!ǻaMO4~L`|8z 2, Kˈm9NH5s)Y_"Qߧ~O?f#‘ޠU/݈HeBXfKܒ Nn'7֯IOD_z~̆#)Az)m;~T)7Tt)?}~F=P ߋxmnk"Nuud7')@854$(vIWR(S&|:GY̭ʑf(6 ۗNt~+8KB XEԼXΡH&.QQΥKtJhgmś72̇^kpSy_*zFɩwȊFPKJ]*Ӕ+i+ߋ:7U@=K~N׿6v5SvjjodnmRR)R|(Ws;GodhSwnݔ]M[Ǭ[3.)T fJtvR|҈ 91Qu.ٗolo-3ovldC4Y1[H{Ϭx0٢G0}H%TP<҅ lfJ$ڒgWuOH$[s_G| W^+ula.A]IS@]6X$?A]|iQ[ҦC ~HԽf đ\7^rha'O8M@/*SYL)fӆ?eZ{xLY=l=@,rA@]v׷mB"{2?R r0(ւU9jNFC;ɑ-E>ؽ1cVE),xu \X\,9Ts)p|O ;ϸ 9i=X ߠ7,92)D|mIO A^aAaD)v*lY=O~`u|%|v n:bp2{Rn{{am"MxsF/MO󠞫&xKLz;xW#b>u;>2kFvn^*`EJ|a!H[_a@b.t/+w_ iPi%((k?|2[PB&?i?3W>5VEG{L'mcS( <*8@kBf=φxƜ4Zє3 [Oxyo̽owHDbXBx20\t%E<6l.<\Xucsu~*!(͗$B Pܼ7)?3WX?u0*{:\tج\ Ȫ*̍/ٺ +- M72џޱK6Fۭ(A#9|;mX  㫥|9m ;)/ILH=H2Pz90y̾;9?YhB&ahAhq:ȈT >~[߀ozQO osUK6p$?})ly'9sVV ,ܹdy=R[Vlᚉ$x@ RTN-$"7Y{V:|.,K܇3k8lī7MOT?5<3g(UVt|. xAK4 t7ZM]k$p`VUʺhBCD=]%G߷ɧ R-@֖ŷ)$N<ܓi43 W'#7R[KowO| +A7U%Ɯb*"*o 02{=@9(ΖAe@p1qAыu *N_щ2\x ^-^Ocei&*ry087 `zd՜)-)̴Ƥ4۬0> c`/'EM}x7_bReaIԫO"o^F\?ƝQh@Ӛ ~C X.W*[eS|LbpR(6"xg,@!w|$ʰ?w!L3ly5W$# `}o 4)O74ā!J lrJQۛsliZ*k\!PˬjW~s%5?i }_>-埄&`)*ZgxsDz3. # cH1UrQ|d){cH[#ݣND1mX|Ϥ&&cyz2Ƙ NHSRiHs$Z|̘иnNq^k 4K{0?KI 3t,a94?TU)mx0v T'z  M*~uE"(mJ Kkڎ&xeo^pAiaadk1,Y> ^!2iD9< k7X%o(Aۏ/Φ:dC 3H 1"L:ʢOI,gGf&AMi+'&7Ҁ-z-aɩrc|/lm pU4̈B h'fGr0,TE*`T)ciBH5ȑUI|5/>dO1{\pQ`xi4d0B%𻧣&0aUJ~oMHO3Rqԣ9*z_dƢ 70⌱|$[3AG1~Z - '6Hc=f@Lʧp&+7{|>+Gr 1̙n"I =`&FuK2f ? :1;' T$ . \!ٙqO<6c2#mAXRBTi &rBm@"6ǃ<%H{.SgխyAUQ-*ǐN=˒VUB6D<PЪb\?1Y9%`Eʱx j\BV'n?\@Aru0 mF,k*8AXlV3sreZh*mQdj .[,0A;rN!V}/?;K=U_z[ Za3 {DMϖ&L,8! Ou' N ;:BdEYk$Zpx+RwXmyXP$㽒VTrF g!q7f̘^yotttGyZhD"tA3?%=Pf,aJ_k«)h j7RWLXŤ-8;4blx?)±ѭM$}o| 0}paW_ɇf{-_}|9\yƍ+WWWg=Wn`5} |4h t-d^ȯ'8g"m21 M<'7X#@bT+k;4X8t*/_~ ;|4̙3'#Z:>_qiG8-u<|e إ|!ZO!)cCU^oOt75-cmy6<7{ u 15 M|_po7o_w8Rkn?!T?"?x|@3Mwy'Cl6 ȾN߇ַ̯"8z_߹zj֧Ac7pq6l8i…{,X[iK!C)ɐz=\U]SICf814PHKc:dž5y\1Id O~̢6A*>,|㑃R nXK/믿H$rBY 9N:=أk79ac:YDED Lp]]]$p!t9xoLهp%0)"bAT<>'MB.O-&?xxC& X.q[5h:)b`&,}"~ ̩465Z\s7@}kO\o0>L #sp7>`Μ9c9Lbl@le"z^o ώ E[@_Ӄ̩-$\m ϱ{#g-_Mo 4XFf ?m.[Hq42W/;OǪ ̿kܭ[5^*9[a7oAM7tܖ-[Ag&9/O[ Hz뭷˗ +h"v6l;Y ´hEYjN)L+5zr Q 1[IDń'W-shKYg_כ33?BtWo}5ct"D#pGXMZ VԎP0K;O)M6A`[]RCph4:>å/h:7+Haq5,g.Ј( T6& rtmx)D? &R& \CL%`R:ppǁg_&K(\q=EНxtٽf 䲥Sl0Q>|6'='{ g<ڻ5UW/aqoAx2 6qŊ6,Ea_ <Ea59A|>Wjuuu *`FlVi_Ҿ&L<.h˫@I+kZ3hهV}f?_5v Q%L$J][S!Hx ,8=g~=̞ỈDHpXJ,x , =fN*2d%be'oiZ`:silǂN\:Jl!|ޝ1qN/]2u9{`+m{y_~C/B  k+r.AB$܅]=s;L~т h1d2'!qBXadLU6,~O]|:WToN>W-Bu9<1<=hz{@ߵ64`9-fe^BZ=5U_Gy<^2v":`ZGusWus{W39]mokL2Ii%ope9&pU."%Nlw{i˝~q%5~(4dA4A`}B*w9z v>2Qz+Hu5"1Xa9H !* TcsC_>:< ['{|}>@P- bQa H# \[ВOoZR6OqA]BNp<~5dʬ$R,szf~V@~~>Ҽ H?0pa}!ykRp;;Br&C$q.,2/@T>UvQ*ÁzqG.{Y=po{G4PzFp |{*ȇl/D ~g{V 2ȠuV i]*L"'{scaC]s0~l /RGtMvurm_^!-P9}w]Fdn׿#K|Sz~x1<r4-@%>&9 Qd[nݪn!bnc+i83Xy׵]{_u+( 95Qd>[yAρ<̿` m! ` BP$,\uK f<u"g0ks3=y>[(2G-*?O ;2C_-+|bm?O=ԧ 뱪7㡇:>%SN9 N^~dб`e=ϫn;'1TŠoǹ;G9?6;K?`6ɠ_,\T³NktWfk*DƲj_"wԢ{r) te^93< C—( Q#:-[e^Yz k׮u'pB!➨ٗ aO!YK(,^0'$t`cV5wca Jt,%g$FsVVGHB"ٲ4A/~_q_p wx!$R 0|{@֪,=*zZP/NY _{^ˇ[Xo:D kp8s}G(ڂ0 >:̽+;W țE&Q &_}}ѓ.CW(P_ a#jL$ҫk&Q &zAN"[F"G3hŀUWl|iCC/PdHomف+"/X?x}w@@)hM;X#Q H8>,ZQv, A]s[uuԩK~o6xQuL9h. ci DP9N!SxB ULyZ;سy]?3ag7 06dAO N5F@jЫ'aw˖ºngn?D];ά!!b-?{wDớA7||CyOd2:P7v'/ꪫB)b GQ t7jBH$ק!=NWYߝ Փ@k *s:3{QZҀψз8dU)j[:[_2ܯnh^}S9Cy-/YQшd΁H== 'a9f4.Fq&HBO_w[^d$Q^G"JN ֠"`KB9OF"ـK^(7x9Tٞ5||s7򍻡CĐ@2'&ۼrH082{|',Á gbUpKvYd7s=9@4my%U!pU+Ծ!: 5j+Gg2ͪ=sf o.RŊȠ3n;0u1HxgypO#"syͺ=_ʍ& SZ EaEBJ$Wdmp*-pAf@(O5 ,X Q ,o8s{Iт)E/} l|`Az`Ҥ YbTټw\ [;PU@m`ec/z}@=0~ C~WPQ\ߥPm2kXnFg%~D }E=i`cG}EEڏ|#ׯ_/Q0JH |2|GfvIԲ Lj*n4,`a,%M?vK'q: $J F`~}+kmACkÂi{˿00-jb5mv[E)`7ѝͿ/*i0Cx^5 ) ,u[V^aRQ]}I]u"e0wIX:>KC_:]w(@ʨkkomq0 \D!0(`7%pQPEeJx s#¨eoi {ɿCAERUjY=1 8;V8H71ؕvWE{{<|+Ȣ.f]Dn=PA_L`7_3|cyƫ:y~ihÐ/,l ܄u 3Gcb*N bb?h5W3me"x+ @N{-vT!,RW4R gnkOpK4vaZI?;lO; ]'k*UH&C@qr[ҧ%IENDB`PK [S0Vcrystal_system/ok.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  ~tIME '8ribKGDIDAT8Ւ+q_&DAp4'%3J٭ Id 'a f®Erom[d bA2â$9~ÛKE0 c{10>M9OEa5B1,8"H6j_;iCVdJOC8԰,X+ {%Lw|qY9gO1NzԆԙMw}Y\-0r2I袌Nr顖k.'p^C7hUQW \`~Xse)Qj.׊AĹB3餕?H ˜O !%3ig[KG#$#>ecU%ftjh+B (50@.,C]A7'w$FIENDB`PK[S0_gRecrystal_system/smile.pngUT Nw@:@Uxn'+}LSW߶jJs4s5eFQ3\%0B7ޢ:S0K & ̸#~`2 +nbghw{sNr9\X?yD/q:*fk1ѽܲ(}l.9OQYuMl(#0H8@Oe|:VMh#1Y g^qY1)O"!ŁfԜP.H$뱔=.&  MS2U#$PÒ We9d'|&i=Ncxߞ옓op|027vN!Ie#LuzA<{iWlw3-ڂ+!_`F)b͍3H)_#U}Dh^i{uUrTJ>g $pWoj]Pxc"o2E4! TkG +{:1mJmʪ*}lm>:UɈ>O8K=rE`swl6_~q Nj渞9Y2ySM?9I:O,2U_>`Z3sK|~qT.ԉ= _~}|,&v)N-nPfE൹R.`ma$넨T:qҨ6O1[ښ+["cKc.;Q90[rN@oL 9)iY֞bswϹ\#aYqwy5Tlq6FG5QYY`8N<0w|-"%yv-X1$TWWC&=+QɄu$~0i8KTL,8\"322F_ 5ͭKzHBOԖaEx!2dA*Cq sR R"J`̝RzLd,r󑜜G`\( R`Զ^rX5#f95 qqq쬀Jr|oRu>}y\t08C\ZVDFh4o8彵 7ck@gX(H,ɬM+>vO/l3NG1t,1VPFWPTdsD &=n4\o#!4[UcU*Ja2':s'ç*1_p-^ʲ+nBB?Q*)D"5\D;=U *̮-*SkB%DEEm9rQ"chxB(8ؙA[U\ | իHJJZ;{{j_()CߐxBل*ؐ5bGKݍBr477swQKgvM21iż Y<6"n&- m,AѫN7kʁrP"VVbSs/|b|jDߢF 7Nw_;l1 @("b+￷]1BIENDB`PK[S0crystal_system/psilogo.pngUT Nw@:@Uxn'+MT{8{Kcl.[% 9VX.i1u[ٌIn%/Y0V8{JVTO[9?s|}$!@ C RGUVn/ >p=rbx* (Ԣq@PTADORԈzjyz[GoΓ-&i lo4t2kEl# D]$e=Ӕll9 tTTН.6nQr 2JH*lidU[]ԛkW;pJH ?z蔄t"Ks6J2 +ިYy+f>ӊIs T] XW#枩m)YWHJX\Ξ0 ^fz#vw$YM[ZʄJ%wQ#VeC$.p#}Ѥx]yb #U Z%=wdhG%k/ ۮO=+hS4B`n"6Vb)=4`[b$2u e`痿gsS2Ej~ B7v"`6 I7^G֞D3vQ~i4@aMMXuwo?2+Mju\ۆ# 46Z)>[4JmM)U/τdp7TKdǦnd+:+M5QX]ɟ赗6R:3H[/5nmn T2=k[+1N u'f3e^/X2Ҵb6xueU q6}ruZJgh *o`G-VY Մ,Fz]xrr>x>GV2 \9+ 1hrWuwӋbŨNs_WÁ5p.Jc'+&⸪px#60t>A0Ymwbކ 2u;MzL([-L=BeϋՌf88%ī))Kb ZaӉ)xR/(u'F6XH~V 52O7:F1܉eWJhS^ |v}B}FMo<{ʭկ oVx$|'3&͹>i5)wW`B>x%e{4#Jb,1t!5}*O%kV> *%s& jvam1Q$T`lE(Qb c^;^V*D{MQMPz@gwSAHktG-ЙC.:<5_PK [S0b0crystal_system/editcopy.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  ~tIME.bKGDIDAT8KOQqF71qGL5^n\hQ0K7PJJ R -SWj+X9clPDo̜={oDDeX\5;ǒwk'Β%(6.{s5p1Yٸ[yXz X.@͢_cƇ1CeZ_$_C掠V z{eIJ|&`I:_r%I."d#S =c<0lLkke D"\7W˕f`Z d 4J&kq>*n?A [~vdV8֣`mEfr.E0r ٥E_J */o$ t|\͉EНdbGHYlwGkBЃ W`Ys&Ls" ƸA-G5XzasVS&tIP43A}Z h1:bt vdSU?#SN)#]ށa]cjڄy+6|AhlH;7 2"! b 6֓,vqC*WC/V_ &-GIQT!} W!~"iIENDB`PK [S05X__crystal_system/quit.pngUT Nw@:@Uxn'+PNG  IHDRagAMA a pHYs )ItIME 4<;bKGDIDAT8]SYHQ# ,"l! K ڋ40DDA+1LQIq)qMRA1& 5ʅ(8sm|o9|"B4l v6d jĩ ބIG W{*n0AraN< KJ7IMtjv'(!}D +>A4yDZ"w5:=™hO8c9%=%I(RAۻ]T GmxƸCk˜v95 p8.r/oQˊA}&F s?gѕkF$yQaƙٶ\͍0ObDMt@ ΏCE@M¬N<!ۦ/c+W݃ \ gZS-LB9 PSmr_e6F55PU\ zhL6 .Cr{H9*.M{a4 uTdqfbY $:aIENDB`PK 50)crystal_system/icon-48.pngUT @:@Uxn'+PNG  IHDR00WgAMA7bKGDIDATxY{tUՙ}{s}&7!CB@]KD;vVu!3 3d*Uc:8 5R@`In!$u:s? @t^#9{}IJR3Uq)xKS#;;OPg`KI`$.-CuOoWׯۆoLQnA\'Ǎ/Lɏ6.]:'nhj .`\)G{cS~ػ{~A{иgFNrjut|>h&W~xHJ5?x*W1 ,!3$ ! uvx_s]vIy;vn8R7YZHR&&r-S7Ngi"q!T n7ww迾wj:w\|8 H3͠Ő0%8#85 \j7zᒒrq>ES0Я@.uL0i Ʊi3' F#A4UB 1)\񒒒QM/}]Ӗjًk]Jj*#8TSE{rjw_{_\2TZZ:@(GC1@?cg~bj>-Q) at4YF'f%]{ԌǢX8oډW_}uWY7= N.€ƽPj=k>t܉t3a1k<4!k?p3yB$! ƪ~x !cs@2`0ءhwb$ 2'[IR^^^7J0, $$lo%?9/^!- bP~5hГ/XXvG0s='555oX?22h;( P`Ps+//G I RF 7͍=rXO!2. H xǸiџlmS.&22 3\s3")> WGyy4L161Cqgm="0"@DD0aT_dYXK:F*LI%}S"%AFB'{2™,oRB&@*+P9G ^w) g85h3 cq6!= H$99H5HW2w,$iHi\,%uB6ΧB`$pzF&iAVͥK^4RHs+Ap rp ]zF` 1؅BŽnRH@ 90iԐB`)$20M53 @ K2QxzFDY~v0A*KRr0o5^qB 'R3:ǓqHwFfff[0cVl#0H@D"|M ;)s 8'flreϬP_I0pܩ@<"I>p^ nP@Õj` (z(䟑geHFiʠp_3wNra<U 8ȫ;qNoE f38SO @aiT؅XJ7M#rrH:D"LF`N:L^ܽw̾C* 2ٕBpgx IsPDlgSX`pT(}尺#O>Ћڷo߼ά{hh@Q47n^pʧzʵvZ/ `+/ 42q:=2hފD$ e@D0QȺ?dEo6}ɒ%֭[{=N-\q˖-y䑻\tIXz}$cmDHo-3nZD\ JF26g7 TۮN@nbMƢEW\m/ҏc \.#ߟ_QQᨩ8xgoqkR 3Ɯ9KKJJԺHNbe=yy^"4haV,xzڴi 'O\ںȑ#Mx?,YzQaa͉D"utIEEEx;Zן]鈈4(㘽f߂y|(G[ `tⅷݎ9yDXn@ol {Сy444~)Gvvv FcmpXKMMpR`͢rnw䶝MYjD't%q\vY/GKPu:69#\woѬ[WvU4u^^V7{|G=wLIIi9{WUU\D"eY\u2MS[[/|0V^x@c$a?$#Ձ2yM WIfd()SX΀`:G!W4_xяw D1cԖ윜a u\F(B0D_z(**rOw'׭<`Qy%Buq(8 3f8޼K:t|IĊdVn h`wʎ'̾pY`'F!aQHeI 1Ο f;khmK˟RkQLOg\?/`OaocY+z tEXtSoftwareAdobe ImageReadyqe<IENDB`PK [S0a!crystal_system/upload.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?.,#.52fHl-2 ѽr6 . `x P i?E$ĤŨVee> KoB4[(@1a*T >Ah\@,b?g_!n Ӏ?@}g WB@1nf򟑁)?,vO6Ċ1z c򜡍Oƍ b3~?~Ui@|k{~,W&@MRk>f`b``f`* 0/1 ^@p "ɁiFWDPcPѰHjh$IENDB`PK [S0V22crystal_system/register.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8ՓOHq?mmif,Y`B[]`FaE ZD AC)\nX7αW黽CXxx.9<h6oEwڛ 6Oǝk6[VdZ0 cZ/v̩KR/'Qc60ԅ#."> @irytN8_!A` ʳۏ1shh.*KTELcFe T%At|8xd*Эe6Cٚhv\Я9:==s8nI|ϋU!^b+pF[>ؤyq^˘ w.ϣD[؇Z%.z$E8ٌ,(]9w>'?I$&V(Ӳխg3zH kWXNLa*m;wxIgNRl 5Mʂ(*m3WLs-K\L:F;s ߚO\6˼@?aehmc MR+ۦh)`bATHL:`͡:ddwQmP +]D^[C̝srtzZV !n.FOzX_g3=q{]Y ({6_."e'zV]u}B{ZwhlFN1=/H `^X@JX,w+Wql @-! #Z2!tO_Ξ_"*Gmz%7~%TrးK+ KR1(`W6OW?uN MPK [S0Ycrystal_system/arrow_right.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs ,tIME &0NQbKGDSIDAT8RkQޓ)74bJP$Tkv V6J =T%#zZPDz165h~%1FӚ:y4[|0kX1bd6)Ygxw+lZͬ8a]o \O%'\O B3c+Jw,A*[2[X1/!q*kF ůYi&A4§2句ʧrpVEr&u/v~jU( Ļ"t^Nwl 7$G*D(46 y4[؆q -BH sΥc 7ם]`' ج>7@ZOg l dHփ6@y=hF DGoR^=WhGm7A-xVi ڱ!m-ta>;µUx+8xs3'qpzejQ0'* |pNxߣ 1tb8᳒ML#О0Swx)t2v : M{Uq`f͵ ~F_uIENDB`PK [S0(8crystal_system/send.pngUT Nw@:@Uxn'+PNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_F&IDATxb?% (IJrB 15A4f@;;@ 1283 wő~@,w^aЗabfI#2 oc8u@zaKQ#5QKU6VF¿PDu?00|3\ ĸ ǯ`JGA_7H@.ưsU_ Ǯb mlll r ?}r' ؀00g>a_`0 (4Ad?f6u? " 30VFvAX. _@_ l@? L(~"icfg`dab,@o@ rY ̆b FJ3@Qb k>q^IENDB`PK [S04lWWcrystal_system/info.pngUT Nw@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbd@*q_Ll @G~Ⅿ'/@V@0Z~ei-l, Qî#֮ɋ @C?\{ j) ΋((120s0010|73ؠ?j'b8~yP @@*Ô f`Y +0uqا_ f v~~^R @̪{~re$203Bla&  K7gx,%, SВe8_F` r ߀?~ ( 4}b`6expQ<@ׁCT~0h-Ug2d;" ߿70^bed@9 ф/=p-981 Ͽ00*gl ۏBE!ԧH M; (|7 b2v$u XUV% Dl16ﬨ|ЎNsϳjp%x.33 6| ^_y Tz张>p.g[vhg&I ^%"d mi }gxv >?zvT@ArĈnd[0 sg//߂ 5dgb&IENDB`PK 0$@FFcrystal_system/filemanager.pngUT 30@:@Uxn'+PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% X@ĒGqr }? _~g ×/~w Ow0\x @.XO?iˎɞG`>:z̟?oN+{ _a셯_1|:?>6V~c߿b7?116 s QTŘ!߽RĘ=*rǎ5C!Z @C!;++#3#';!^.W@O?  @; 4Xr`G(a= .]@@^ tf`|i ' Y_?>'v?A O80‚ hׯ ?;Û7؁3 LL@W`@~@Ac0?Pd 4ϟpb/^axSEׯO@ Z`F_??#Çׯ} @_7778l (Iׯ3 `2  IENDB`PK K0H`;crystal_system/roster.pngUT  @:@Uxn'+PNG  IHDRagAMA7IDATx}Kq?SwpfnPW5,:be..O.""0(C(ҁ,ZiI95}ܻ_Wz}Xr,SenϪμx۩JKGݽ_#B,G <w\/KކN"$$HclƋ^-ag; 2 #ֈMưYϾ˽=hJPlf֙"4mYWXʖ@޺:08N{ ~}hݺ!3XpKta4@C@P@&9u>WN:^ҳ,d4tzxJh_g?={ES!_ 1RG\c[b{Sj_%yLErWhQ(+[|p|4*DxB)!"Q!_xkF^Ϝzeoof&6UYl>oُ1wDR]iϾ]Z2YH `|dT 29vX:`OBX@SJ uz>Gzh|; J7حA& 1;&جPj*LNLΪekLk9MM5mDw·o]LƾHKpfϿ媨())*Q% B?D#ooq<%]IENDB`PK K0uk[[crystal_system/advanced.pngUT  @:@Uxn'+PNG  IHDRabKGD pHYs  ~tIME ⡕IDATx1hqriZZh0-&zUD8tD:P*Ԁ {,lq l% MB5՚\rL,oyumni!HikGxiMMOwEȹGS&5`] 39tDӅ ~[*]8QF45e[z!i)hg/$ẘ HB!H$jLF2: v#e Q'15ebp$}}0vMR&u`|^²,4 P&SjmLV W E*wff<v!:c 5Zc=֏Ձaʤi~!TrM7crystal_system/ssl_yes.pngUTNw@UxPK [S0"\* x:crystal_system/arrow_down.pngUTNw@UxPK [S0B:   =crystal_system/editpaste.pngUTNw@UxPK [S0 Acrystal_system/edit.pngUTNw@UxPK [S0R Dcrystal_system/cancel.pngUTNw@UxPK [S0ϝ.. Fcrystal_system/pgp.pngUTNw@UxPK [S0 ̻ rIcrystal_system/edittrash.pngUTNw@UxPK [S0K% |Lcrystal_system/configure_toolbars.pngUTNw@UxPK K03 Pcrystal_system/add.pngUT@UxPK [S0~:! Scrystal_system/help.pngUTNw@UxPK K0"a1 Vcrystal_system/key.pngUT @UxPK [S0| Ycrystal_system/eye_blue.pngUTNw@UxPK [S0YZ .\crystal_system/options.pngUTNw@UxPKK0Dw _crystal_system/account.pngUT @UxPK [S0|rR## dcrystal_system/groupchat.pngUTNw@UxPK [S0LL hcrystal_system/tip.pngUTNw@UxPK 50̌mm kcrystal_system/icon-16.pngUT@UxPK [S0s޼ ncrystal_system/ssl_no.pngUTNw@UxPK [S0 ̻ pcrystal_system/remove.pngUTNw@UxPK K0gg scrystal_system/key_bad.pngUT @UxPK 503Occ wcrystal_system/icon-32.pngUT@UxPK [S0 u Tcrystal_system/vcard.pngUTNw@UxPK [S0 >crystal_system/xml.pngUTNw@UxPK [S0CWW crystal_system/history.pngUTNw@UxPK [S0$ Gcrystal_system/arrow_left.pngUTNw@UxPK [S0{{ Zcrystal_system/close.pngUTNw@UxPK [S0D77 crystal_system/icon_mac.pngUTNw@UxPK [S0V crystal_system/ok.pngUTNw@UxPK[S0_gRe Ocrystal_system/smile.pngUTNw@UxPK [S0G crystal_system/key2.pngUTNw@UxPK[S0 &crystal_system/psilogo.pngUTNw@UxPK [S0b0 Ucrystal_system/editcopy.pngUTNw@UxPK [S05X__ crystal_system/quit.pngUTNw@UxPK 50) Kcrystal_system/icon-48.pngUT@UxPK [S0a! crystal_system/upload.pngUTNw@UxPK [S0V22 crystal_system/register.pngUTNw@UxPK [S0;B crystal_system/stop.pngUTNw@UxPK K00 crystal_system/jabber.pngUT @UxPK[S0» crystal_system/chatclear.pngUTNw@UxPK [S0Y crystal_system/arrow_right.pngUTNw@UxPK [S0(8 crystal_system/send.pngUTNw@UxPK [S04lWW crystal_system/info.pngUTNw@UxPK 0$@FF wcrystal_system/filemanager.pngUT30@UxPK K0H`;  crystal_system/roster.pngUT @UxPK K0uk[[ Zcrystal_system/advanced.pngUT @UxPK>>{psi-0.14/src/tools/iconset/unittest/iconsets/roster/0000755000175000017500000000000011305557613020760 5ustar janjanpsi-0.14/src/tools/iconset/unittest/iconsets/roster/default.jisp0000644000175000017500000002350311305557613023276 0ustar janjanPK g?4default/UT BCuCUxPK?4=default/ask.pngUT )CrCUx sb``p  $?OR B xn {+%..3V %y0{Oy8XtA%reDCf~ܺ+%T|5d~hƝ(gM)9+IJJ_Mww`յ|NzV@< m:y4 Upd{XWFS$h k'GY $n}Pǚyt:&PK ?4 Wdefault/away.pngUT )CrCUxPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8 0D;3{t(FHE8Jr~q-DT"=ZG(]/bNVC'( 8RdpӺ̮o;YEt4 Il~  7LIENDB`PK ?4[ydefault/chat.pngUT )CrCUxPNG  IHDR"gAMA7tEXtSoftwareAdobe ImageReadyqe<0PLTEŻsss$̌' X6tRNS#]IDATH͖ے Dh HݭZB4&걩sqI~ zqđwp=xoizޯ@o";?O;+#ȷ_/n >˟a(Sĕ.5 ɽ)!qS)5`Fhk(-;sB˧\l]5!}H״*pĻݹb<ǐrq88MeH 9wPLvM]q|Hz҉6N8|K״*Mp6j+]tt.^syJ4*Zqr=.f[KzKDSkk*&X뀫53|$-͈\#Nwwok-|-)D"pFtTp솋iV&ojx$"{Ac㵋yA?5?(`A+og]oMU,W9U̐rs\zk0Z gKcIENDB`PK ?4b 6default/connect.pngUT )CrCUxPNG  IHDR`gAMA a pHYs  d_tIME UbKGDIDATh͍0N:&  88d`ϳ@s~8,; :P4Rcq?Pkym9f>n0 /qߣr<_˓ry꿖G6ciY8k  %iIA x !k|GN&yn~-/y|I{'$N$n8tO/\\ק^Yyɿ ^O x[DILj; 0L_Hѧ?a$DR۶/v|jSα_3__X;IENDB`PK ?4ldefault/dnd.pngUT )CrCUxPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˭ )7qZIKBK#iM&ZK!Gf^&FՕM {@ٖոLYБõAOBT$+4(1&ziLqhy|24ĩXZql0ZYzk^|a+~|ane oڜ 6MFHp$Yz#.d-2_<]\9%4PK ?4ldefault/file.pngUT )CrCUxPNG  IHDR`*tEXtCreation Times 9 maj 2004 19:32:34 +0100*z'tIME %2S|C pHYsnu>gAMA aIDATx1n0 E%GZcӱ@!zȰdEjs "}_ 8kU@o4.SҼ'GҼٟ~IUg.r)C&K sזCNIRmH 7G&_8yTCc%1.Pyn l/{ DNuSVm5~\QVunwM$YuGEM@+P8,~X Az f\(Pq6CtDߍV T9x1:` t}DH#/WjpxA}Rd@ W@!N`f26.C-*H(/ dʞ 5QnHyKGC>=I3=0"R~cA?fSx}AwA+!w{ J3)J|f-__{P]JQCS]_ ϫBՋ' ({s[dU-Ë Ԡbq}z 9/ N1FmKI~_dIGtZw l,%MR*yAGtR!%^ #e)#-lNS֬.1_#kZJՈJRS-GEThݖx_'RF;e;s{RGͷ7I~JI!f~P8΍'d%.;\y4glZ53%f ŕR;.2%x&Mc6dKv!DL$$?hZ!uD34[S8VuMȥiy}/PvliXDo7+C6 y ZK.{Asjǰ 6Luv7k*v2R/\K4N{ lH؄[˜*PD8|ꥆ;ԡqM3 i͠PK?44qdefault/invisible.pngUT )CrCUx sb``p  $?OR B xn {+eAn*q~[ \wdHcE҉98b/[OϚ=Ijۼ SgLWkTa j:;6[w}fbށ Շx~d_)VyhCH؉]w%='kފ {ĝ9OW?uN MPK ?4d..default/message.pngUT )CrCUxPNG  IHDRgAMA a pHYs  ~tIME qbKGDIDATh[0 DUeO$B@{ENi۶tvy#wByE@I~/Nܡ|tSͷˋlw˃G Y0>#›>[S 3ǒ8+g/0oVVD/L# ?u+gW\`>#1Hx6rl ׾XIENDB`PK?4O'default/noauth.pngUT )CrCUx sb``p  $?OR,鎾 $ B xn {+%NNVE{ؒ]'Ez8X^;y7|:TY Sx$8b+?O8p6ǺFe6t_5&GL6Y/]]3Mq98E@S_w9|q(8ݣx:K^L5g[u_}2o ":&PK?4I<default/offline.pngUT )CrCUx sb``p  $2X}֟0gz KF秕'28'*x&&TL*tq јwPvWoas|D# !/<5w>YRp}'k/:V޸ƦICsX#æI,Gf?XjNeSBPK?4wdefault/online.pngUT )CrCUx sb``p  $?OR,鎾 Ov%K\#JJRSRQ#\ E?Wcb>,)/OW?uN MPK?4)-default/perr.pngUT )CrCUx sb``p  $?OR,鎾 $ B xn {+%NNV5Kؒ]'EVy8XN=Wxeg=y#O'Vb:dr&|,sW:ɤ۸1L\.塯]?WΞòb?Ipgcf4V9tyJb8z ^ 5XO')'4^njr~kT^ pzlPVFFXtmٶ'G[M'8WԝttXKx| *mx%ƭ]< Gz!z]8n_._ݻ}7X*2!H 2W^LF(N+;yݙw_x؟ ??IENDB`PK?4`default/xa.pngUT )CrCUx sb``p  $2X}֟0gz KF秕'28'*x&&TL*tq јwP^U8r,K>-2yS4 6>W!0Uz=&_U"\^vmNIaT4atsYPK g?4 Adefault/UTBCUxPK?4= ;default/ask.pngUT)CUxPK ?4 W xdefault/away.pngUT)CUxPK ?4[y default/chat.pngUT)CUxPK ?4b 6 default/connect.pngUT)CUxPK ?4l default/dnd.pngUT)CUxPK?4  default/ffc.pngUT)CUxPK ?4l  default/file.pngUT)CUxPK?4dCb default/groupclose.pngUT)CUxPK?4hM default/groupempty.pngUT)CUxPK?4 default/groupopen.pngUT)CUxPK?4#/ default/headline.pngUT)CUxPK?4KmBG  default/icondef.xmlUT)CUxPK?44q Pdefault/invisible.pngUT)CUxPK ?4d.. }default/message.pngUT)CUxPK?4O' default/noauth.pngUT)CUxPK?4I< Gdefault/offline.pngUT)CUxPK?4w Wdefault/online.pngUT)CUxPK?4)- default/perr.pngUT)CUxPK ?4l@ default/system.pngUT)CUxPK?4` default/xa.pngUT)CUxPKF psi-0.14/src/tools/iconset/unittest/iconsets/roster/small.jisp0000644000175000017500000000442311305557613022762 0ustar janjanPK GC4small/UT 5uCQuCUxPK ʸ?4[ysmall/chat.pngUT ˟a(Sĕ.5 ɽ)!qS)5`Fhk(-;sB˧\l]5!}H״*pĻݹb<ǐrq88MeH 9wPLvM]q|Hz҉6N8|K״*Mp6j+]tt.^syJ4*Zqr=.f[KzKDSkk*&X뀫53|$-͈\#Nwwok-|-)D"pFtTp솋iV&ojx$"{Ac㵋yA?5?(`A+og]oMU,W9U̐rs\zk0Z gKcIENDB`PKʸ?4wsmall/online.pngUT Q#\ E?Wcb>,)/OW?uN MPKrA4*z}0small/.icondef.xml.swpUT Cv CUx1o1p/MP!: U@(C+ gM]: `##3_K#E:scrG~w~٧c2slcoچ"sQ~U0˸6֕}ɽ :C*v[1]ݾ̗nn_QŪNzDL5dle#J}|||S(;ACY\\_((o=/?CѝvMu5VcHʍ,/TJvGy'tוN2x'l)K*Qir:S.)\ܨ7/4\4N\U|D7÷v۹#XUӳn5KѬAu8C'^µиQ?~>H3 PKܸ?4'({small/icondef.xmlUT _CuCUx!Dk ,8,m@\O̱\4߻v̼Zcw | 'mX*gଧ!ƃtE)Kj&ۆlIrGdB\֥ddṁ;X2xwiAr]SsJLA/]?}t^Lz~6Hۉ+w|| PK GC4 Asmall/UT5uCUxPK ʸ?4[y 9small/chat.pngUT=L_m޼yr%dڥiWas̈iS)~sczǴwӡM+36`e>lTeg/.=&?ibqA@q~Մ]FքOVTDX\f^+/&yL-v**ULIiҲտxWQE_U^xFŇj*j\Zm2P>$amugYVۘa\0cL Ro~(Nphy^& L,m{J~]ajnRR-ƅo. ^ ]V(0XPKI/FJr : puz/kazak.gifUT ?kzCUxstLTcP`8TeL;%iٲeMMM. 2+K/M.LiYӃiLy~lzmbZӮ2u ,2Z4+2eEl޽v#M}L1][tڥ$/_8qA@qB{)9vLd"Dz_YRN@r .uFA }SCm9{894+ 3\(r&fQ-uZ.ʽj~PVPTA_ k 6O/nJ<8OKGzDmndQPr@KEԒ 2/X[x_54ws(XQ^d GejoSbVz U%"Af (:s@aR<V};n8vzQ |oF}W``d1Zsk2 0!n/1ѭ[:ꁄ󤪖C\F! (bJ֮r^2~riRʦŒvrVnNrtb6޶ΎߖfN^Jޮ̆vf:joRs99))vjbnΊ!?,pp98 9` Sq.ftHai%e*ڹ(C.? {~}r]NFST !"SN #$%&'(T($)J* N+,N( '-+./00+(12C!3(45!L67133$89aV:;44%6wVB&""V;PKc/\ puz/zorro.gifUT ?kzCUxstL`c8ӤiIlvvv=322LSژ455oݺr1Ӿ}Ҭ޻ջ8/[dddu1[NHH(,,ջwژʪu1_hKӧ}LIII&1}]IMINNNYYY};tةy+fe=n5ӕ+$,Cfff2yM6?Yt' tX$[$&MfS2azL ;'m60P^Zrt2hKJ[b1ذb-X>h$ kN5fаtޅ ]o0k<߇ 5˟nc&[kL>=Ǧk.6ū^)ኅ BW'<+p1@҇3`['OBi˗N-g$db<PKC4хWIpuz/icondef.xmlUT OzC|zCUxn S0-Ed+f7 SeE1]OkLm!CnODGЍP&L8ܲTUU !ZXm[޾%>t˒h-)VMEm\3;AR)j\P%qjZJ R ܫqW\`@I_q a`)`1@jJQ&%ρbukJzsFNpm}^>f&ku9fPQø{MhNC|n¡^Iۼv#ijMx=G)S>p d(#) ]kPK C4 Apuz/UTzCUxPK / p 7puz/bebebe.gifUTd?UxPKd /5^,| puz/broken_heart.gifUTg?UxPKI/FJr : puz/kazak.gifUT?UxPK )h/ZΞ puz/laugh.gifUTmX?UxPKc/\ puz/zorro.gifUT?UxPKC4хWI  puz/icondef.xmlUTOzCUxPK psi-0.14/src/tools/iconset/unittest/testiconset.cpp0000644000175000017500000001267011305557613020671 0ustar janjan#include #include "iconset.h" #include "anim.h" class TestIconset: public QObject { Q_OBJECT private: Iconset *iconset; private slots: void initTestCase() { iconset = new Iconset(); QVERIFY(iconset->load("iconsets/roster/default.jisp")); iconset->addToFactory(); } void cleanupTestCase() { iconset->clear(); QCOMPARE(iconset->count(), 0); delete iconset; } void testIconsetData() { // verify metadata QCOMPARE(iconset->name(), QString("Stellar (default)")); QCOMPARE(iconset->version(), QString("1.0")); QCOMPARE(iconset->authors().count(), 2); QCOMPARE(iconset->authors()[0], QString("Jason Kim
  Email: jmkim@uci.edu")); QCOMPARE(iconset->authors()[1], QString("Michail Pishchagin (icondef.xml)
  Email: mblsha@users.sourceforge.net
  JID: mblsha@jabber.ru
  WWW: http://maz.sf.net")); QCOMPARE(iconset->creation(), QString("2003-07-08")); QCOMPARE(iconset->description(), QString("Default Psi 0.9.1 iconset")); // verify icons QCOMPARE(iconset->count(), 19); } void testIterator() { QStringList iconNames; QListIterator it = iconset->iterator(); while ( it.hasNext() ) { PsiIcon *icon = it.next(); iconNames << icon->name(); } QCOMPARE(iconNames.count(), iconset->count()); } void testHeadlineIcon() { const PsiIcon *messageHeadline = IconsetFactory::iconPtr("psi/headline"); QVERIFY(messageHeadline != 0); QCOMPARE(messageHeadline->name(), QString("psi/headline")); QCOMPARE(messageHeadline->isAnimated(), false); QCOMPARE(messageHeadline->frameNumber(), 0); QCOMPARE(messageHeadline->anim(), (const Anim *)0); QVERIFY(!messageHeadline->impix().isNull()); QVERIFY(!messageHeadline->pixmap().isNull()); QCOMPARE(messageHeadline->impix().image().width(), 16); QCOMPARE(messageHeadline->impix().image().height(), 16); QCOMPARE(messageHeadline->impix().pixmap().width(), 16); QCOMPARE(messageHeadline->impix().pixmap().height(), 16); QCOMPARE(messageHeadline->pixmap().width(), 16); QCOMPARE(messageHeadline->pixmap().height(), 16); } void testAnim() { const PsiIcon *chat = IconsetFactory::iconPtr("psi/chat"); QVERIFY(chat->anim() != 0); const Anim *anim = chat->anim(); Anim *copy1 = new Anim(*anim); Anim *copy2 = new Anim(*copy1); Anim *copy3 = new Anim(*copy2); // at first, all animations should contain 15 frames QCOMPARE(copy3->numFrames(), 15); copy3->stripFirstFrame(); QCOMPARE(copy3->numFrames(), 14); QCOMPARE(copy2->numFrames(), 15); QCOMPARE(copy1->numFrames(), 15); QCOMPARE(anim->numFrames(), 15); int i; for (i = 0; i < 2; i++) copy2->stripFirstFrame(); QCOMPARE(copy3->numFrames(), 14); QCOMPARE(copy2->numFrames(), 13); QCOMPARE(copy1->numFrames(), 15); QCOMPARE(anim->numFrames(), 15); for (i = 0; i < 5; i++) copy1->stripFirstFrame(); QCOMPARE(copy3->numFrames(), 14); QCOMPARE(copy2->numFrames(), 13); QCOMPARE(copy1->numFrames(), 10); QCOMPARE(anim->numFrames(), 15); delete copy3; delete copy2; delete copy1; } void testIconStripping() { const PsiIcon *chat = IconsetFactory::iconPtr("psi/chat"); QVERIFY(chat != 0); QVERIFY(chat->isAnimated() == true); QCOMPARE(chat->anim()->numFrames(), 15); PsiIcon *stripping = new PsiIcon(*chat); QCOMPARE(chat->name(), QString("psi/chat")); QCOMPARE(stripping->name(), QString("psi/chat")); stripping->stripFirstAnimFrame(); QCOMPARE(stripping->anim()->numFrames(), 14); QCOMPARE(chat->anim()->numFrames(), 15); stripping->setName("yohimbo"); QCOMPARE(chat->name(), QString("psi/chat")); QCOMPARE(stripping->name(), QString("yohimbo")); delete stripping; } void testIconsetFactory() { QCOMPARE(IconsetFactory::icons().count(), 19); QVERIFY(IconsetFactory::iconPtr("psi/message")); } void testCombineIconsets() { Iconset *is = new Iconset(); QVERIFY(is->load("iconsets/roster/small.jisp")); Iconset *combined = new Iconset(*is); QCOMPARE(combined->count(), is->count()); *combined += *is; QCOMPARE(combined->count(), is->count()); QListIterator it = is->iterator(); while (it.hasNext()) { PsiIcon *icon = new PsiIcon(*it.next()); icon->setName(icon->name() + '2'); combined->setIcon(icon->name(), *icon); delete icon; } QCOMPARE(combined->count(), 4); combined->clear(); QCOMPARE(combined->count(), 0); QCOMPARE(is->count(), 2); delete combined; delete is; } void testLoadGifIconset() { Iconset *is = new Iconset(); QVERIFY(is->load("iconsets/emoticons/puz.jisp")); QVERIFY(is->count() > 0); delete is; } void testMultipleIconTextStrings() { // all puz iconset icons contain multiple // text strings. we need to verify that. Iconset *is = new Iconset(); QVERIFY(is->load("iconsets/emoticons/puz.jisp")); QVERIFY(is->count() > 0); QListIterator it = is->iterator(); while (it.hasNext()) { const QList text = it.next()->text(); QVERIFY(text.count() > 1); } delete is; } void testCreateQIcon() { const PsiIcon *chat = IconsetFactory::iconPtr("psi/chat"); QVERIFY(chat != 0); QIcon icon = chat->icon(); QVERIFY(!icon.isNull()); } }; QTEST_MAIN(TestIconset) #include "testiconset.moc" psi-0.14/src/tools/iconset/unittest/testiconset.pro0000644000175000017500000000070111305557613020677 0ustar janjan# unittest helpers TARGET = testiconset CONFIG += unittest include($$PWD/../../../../qa/oldtest/unittest.pri) QT += gui xml RESOURCES += ../../../../iconsets.qrc SOURCES += testiconset.cpp # iconset library DEFINES += NO_ICONSET_SOUND ICONSET_CPP = .. CONFIG += iconset include($$ICONSET_CPP/iconset.pri) # zip (for .jisp-processing) PSICS_CPP = ../.. CONFIG += zip ZIP_CPP = $$PSICS_CPP/zip INCLUDEPATH += $$ZIP_CPP include($$ZIP_CPP/zip.pri) psi-0.14/src/tools/iconset/iconset.pri0000644000175000017500000000021411305557613016111 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += \ $$PWD/iconset.cpp \ $$PWD/anim.cpp HEADERS += \ $$PWD/iconset.h \ $$PWD/anim.h psi-0.14/src/tools/iconset/iconset.cpp0000644000175000017500000010260711305557613016112 0ustar janjan/* * iconset.cpp - various graphics handling classes * Copyright (C) 2001-2006 Justin Karneges, Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconset.h" #include #include #include #include #include #include #include #include #include #include #include #include "anim.h" // sound support #ifndef NO_ICONSET_SOUND #define ICONSET_SOUND #endif #ifdef ICONSET_SOUND # include # include #endif #ifndef NO_ICONSET_ZIP #define ICONSET_ZIP #endif #ifdef ICONSET_ZIP # include "../zip/zip.h" #endif #include #include #include static void moveToMainThread(QObject *obj) { if (Anim::mainThread() && Anim::mainThread() != QThread::currentThread()) obj->moveToThread(Anim::mainThread()); } //---------------------------------------------------------------------------- // Impix //---------------------------------------------------------------------------- /** * \class Impix iconset.h * \brief Combines a QPixmap and QImage into one class * * Normally, it is common to use QPixmap for all application graphics. * However, sometimes it is necessary to access pixel data, which means * a time-costly conversion to QImage. Impix does this conversion on * construction, and keeps a copy of both a QPixmap and QImage for fast * access to each. What you gain in speed you pay in memory, as an Impix * should occupy twice the space. * * An Impix can be conveniently created from either a QImage or QPixmap * source, and can be casted back to either type. * * You may also call unload() to free the image data. * * \code * Impix i = QImage("icon.png"); * QLabel *iconLabel; * iconLabel->setPixmap(i.pixmap()); * QImage image = i.image(); * \endcode */ /** * \brief Construct a null Impix * * Constructs an Impix without any image data. */ Impix::Impix() { d = new Private; } /** * \brief Construct an Impix based on a QPixmap * * Constructs an Impix by making a copy of a QPixmap and creating a QImage from it. * \param from - source QPixmap */ Impix::Impix(const QPixmap &from) { d = new Private; *this = from; } /** * \brief Construct an Impix based on a QImage * * Constructs an Impix by making a copy of a QImage and creating a QPixmap from it. * \param from - source QImage */ Impix::Impix(const QImage &from) { d = new Private; *this = from; } /** * Unloads image data, making it null. */ void Impix::unload() { if ( isNull() ) return; d->unload(); } bool Impix::isNull() const { return !d->image.isNull() || d->pixmap ? false: true; } const QPixmap & Impix::pixmap() const { if (!d->pixmap) { d->pixmap = new QPixmap(); if (!d->image.isNull()) { *d->pixmap = QPixmap::fromImage(d->image); } } return *d->pixmap; } const QImage & Impix::image() const { if (d->image.isNull() && d->pixmap) d->image = d->pixmap->toImage(); return d->image; } void Impix::setPixmap(const QPixmap &x) { d->unload(); d->pixmap = new QPixmap(x); } void Impix::setImage(const QImage &x) { d->unload(); d->image = x; } bool Impix::loadFromData(const QByteArray &ba) { bool ret = false; delete d->pixmap; d->pixmap = 0; QImage img; if ( img.loadFromData(ba) ) { Q_ASSERT(img.width() > 0); Q_ASSERT(img.height() > 0); setImage( img ); ret = true; } Q_ASSERT(ret); return ret; } //---------------------------------------------------------------------------- // IconSharedObject //---------------------------------------------------------------------------- class IconSharedObject : public QObject { Q_OBJECT public: IconSharedObject() #ifdef ICONSET_SOUND : QObject(qApp) #endif { setObjectName("IconSharedObject"); } QString unpackPath; signals: void playSound(QString); private: friend class PsiIcon; }; static IconSharedObject *iconSharedObject = 0; //---------------------------------------------------------------------------- // PsiIcon //---------------------------------------------------------------------------- /** * \class PsiIcon * \brief Can contain Anim and stuff * * This class can be used for storing application icons as well as emoticons * (it has special functions in order to do that). * * Icons can contain animation, associated sound files, its own names. * * For implementing emoticon functionality, PsiIcon can have associated text * values and QRegExp for easy searching. */ //! \if _hide_doc_ class PsiIcon::Private : public QObject, public QSharedData { Q_OBJECT public: Private() { moveToMainThread(this); anim = 0; icon = 0; activatedCount = 0; } ~Private() { unloadAnim(); if ( icon ) delete icon; } // copy all stuff, this constructor is called when detaching Private(const Private &from) : QObject(), QSharedData() { moveToMainThread(this); name = from.name; regExp = from.regExp; text = from.text; sound = from.sound; impix = from.impix; anim = from.anim ? new Anim ( *from.anim ) : 0; icon = 0; activatedCount = from.activatedCount; } void unloadAnim() { if ( anim ) delete anim; anim = 0; } void connectInstance(PsiIcon *icon) { connect(this, SIGNAL(pixmapChanged()), icon, SIGNAL(pixmapChanged())); connect(this, SIGNAL(iconModified()), icon, SIGNAL(iconModified())); } void disconnectInstance(PsiIcon *icon) { disconnect(this, SIGNAL(pixmapChanged()), icon, SIGNAL(pixmapChanged())); disconnect(this, SIGNAL(iconModified()), icon, SIGNAL(iconModified())); } signals: void pixmapChanged(); void iconModified(); public: const QPixmap &pixmap() const { if ( anim ) return anim->framePixmap(); return impix.pixmap(); } public slots: void animUpdate() { emit pixmapChanged(); } public: QString name; QRegExp regExp; QList text; QString sound; Impix impix; Anim *anim; QIcon *icon; int activatedCount; friend class PsiIcon; }; //! \endif /** * Constructs empty PsiIcon. */ PsiIcon::PsiIcon() : QObject(0) { moveToMainThread(this); d = new Private; d->connectInstance(this); } /** * Destroys PsiIcon. */ PsiIcon::~PsiIcon() { } /** * Creates new icon, that is a copy of \a from. Note, that if one icon will be changed, * other will be changed as well. (that's because image data is shared) */ PsiIcon::PsiIcon(const PsiIcon &from) : QObject(0) , d(from.d) { moveToMainThread(this); d->connectInstance(this); } /** * Creates new icon, that is a copy of \a from. Note, that if one icon will be changed, * other will be changed as well. (that's because image data is shared) */ PsiIcon & PsiIcon::operator= (const PsiIcon &from) { d->disconnectInstance(this); d = from.d; d->connectInstance(this); return *this; } PsiIcon *PsiIcon::copy() const { PsiIcon *icon = new PsiIcon; icon->d = new Private( *this->d.data() ); icon->d->connectInstance(icon); return icon; } void PsiIcon::detach() { d.detach(); } /** * Returns \c true when icon contains animation. */ bool PsiIcon::isAnimated() const { return d->anim != 0; } /** * Returns QPixmap of current frame. */ const QPixmap &PsiIcon::pixmap() const { return d->pixmap(); } /** * Returns QImage of current frame. */ const QImage &PsiIcon::image() const { if ( d->anim ) return d->anim->frameImage(); return d->impix.image(); } /** * Returns Impix of first animation frame. * \sa setImpix() */ const Impix &PsiIcon::impix() const { return d->impix; } /** * Returns Impix of current animation frame. * \sa impix() */ const Impix &PsiIcon::frameImpix() const { if ( d->anim ) return d->anim->frameImpix(); return d->impix; } /** * Returns QIcon of first animation frame. * TODO: Add automatic greyscale icon generation. */ const QIcon &PsiIcon::icon() const { if ( d->icon ) return *d->icon; const_cast(d.data())->icon = new QIcon( d->impix.pixmap() ); return *d->icon; } /** * Sets the PsiIcon impix to \a impix. * \sa impix() */ void PsiIcon::setImpix(const Impix &impix, bool doDetach) { if ( doDetach ) detach(); d->impix = impix; if ( d->icon ) { delete d->icon; d->icon = 0; } emit d->pixmapChanged(); emit d->iconModified(); } /** * Returns pointer to Anim object, or \a 0 if PsiIcon doesn't contain an animation. */ const Anim *PsiIcon::anim() const { return d->anim; } /** * Sets the animation for icon to \a anim. Also sets Impix to be the first frame of animation. * If animation have less than two frames, it is deleted. * \sa anim() */ void PsiIcon::setAnim(const Anim &anim, bool doDetach) { if ( doDetach ) detach(); d->unloadAnim(); d->anim = new Anim(anim); if ( d->anim->numFrames() > 0 ) setImpix( d->anim->frame(0) ); if ( d->anim->numFrames() < 2 ) { delete d->anim; d->anim = 0; } if ( d->anim && d->activatedCount > 0 ) { d->activatedCount = 0; activated(false); // restart the animation, but don't play the sound } emit d->pixmapChanged(); emit d->iconModified(); } /** * Removes animation from icon. * \sa setAnim() */ void PsiIcon::removeAnim(bool doDetach) { if ( doDetach ) detach(); if ( !d->anim ) return; d->activatedCount = 0; stop(); delete d->anim; d->anim = 0; emit d->pixmapChanged(); //emit d->iconModified(); } /** * Returns the number of current animation frame. * \sa setAnim() */ int PsiIcon::frameNumber() const { if ( d->anim ) return d->anim->frameNumber(); return 0; } /** * Returns name of the PsiIcon. * \sa setName() */ const QString &PsiIcon::name() const { return d->name; } /** * Sets the PsiIcon name to \a name * \sa name() */ void PsiIcon::setName(const QString &name) { detach(); d->name = name; } /** * Returns PsiIcon's QRegExp. It is used to store information for emoticons. * \sa setRegExp() */ const QRegExp &PsiIcon::regExp() const { return d->regExp; } /** * Sets the PsiIcon QRegExp to \a regExp. * \sa regExp() * \sa text() */ void PsiIcon::setRegExp(const QRegExp ®Exp) { detach(); d->regExp = regExp; } /** * Returns PsiIcon's text. It is used to store information for emoticons. * \sa setText() * \sa regExp() */ const QList &PsiIcon::text() const { return d->text; } /** * Sets the PsiIcon text to \a t. * \sa text() */ void PsiIcon::setText(const QList &t) { detach(); d->text = t; } /** * Returns default icon text that could be used as a default value * for e.g. emoticon selector. */ QString PsiIcon::defaultText() const { if (text().isEmpty()) return QString(); // first, try to get the text by priorities QStringList lang; lang << QLocale::system().name().section('_', 0, 0); // most prioritent, is the local language lang << ""; // and then the language without name goes (international?) lang << "en"; // then real English QString str; QStringList::Iterator it = lang.begin(); for (; it != lang.end(); ++it) { foreach(IconText t, text()){ if (t.lang == *it) { str = t.text; break; } } } // if all fails, just get the first text if (str.isEmpty()) { foreach(IconText t, text()){ if (!t.text.isEmpty()) { str = t.text; break; } } } return str; } /** * Returns file name of associated sound. * \sa setSound() * \sa activated() */ const QString &PsiIcon::sound() const { return d->sound; } /** * Sets the sound file name to be associated with this PsiIcon. * \sa sound() * \sa activated() */ void PsiIcon::setSound(const QString &sound) { detach(); d->sound = sound; } /** * Blocks the signals. See the Qt documentation for details. */ bool PsiIcon::blockSignals(bool b) { return d->blockSignals(b); } /** * Initializes PsiIcon's Impix (or Anim, if \a isAnim equals \c true). * Iconset::load uses this function. */ bool PsiIcon::loadFromData(const QByteArray &ba, bool isAnim) { detach(); bool ret = false; if ( isAnim ) { Anim *anim = new Anim(ba); setAnim(*anim); ret = anim->numFrames() > 0; delete anim; // shared data rules ;) } if ( !ret && d->impix.loadFromData(ba) ) ret = true; if ( ret ) { emit d->pixmapChanged(); emit d->iconModified(); } Q_ASSERT(ret); return ret; } /** * You need to call this function, when PsiIcon is \e triggered, i.e. it is shown on screen * and it must start animation (if it has not animation, this function will do nothing). * When icon is no longer shown on screen you MUST call stop(). * NOTE: For EACH activated() function call there must be associated stop() call, or the * animation will go crazy. You've been warned. * If \a playSound equals \c true, PsiIcon will play associated sound file. * \sa stop() */ void PsiIcon::activated(bool playSound) { d->activatedCount++; #ifdef ICONSET_SOUND if ( playSound && !d->sound.isNull() ) { if ( !iconSharedObject ) iconSharedObject = new IconSharedObject(); emit iconSharedObject->playSound(d->sound); } #else Q_UNUSED(playSound); Q_UNUSED(iconSharedObject); #endif if ( d->anim ) { d->anim->unpause(); d->anim->disconnectUpdate (d, SLOT(animUpdate())); // ensure, that we're connected to signal exactly one time d->anim->connectUpdate (d, SLOT(animUpdate())); } } /** * You need to call this function when PsiIcon is no more shown on screen. It would save * processor time, if PsiIcon has animation. * NOTE: For EACH activated() function call there must be associated stop() call, or the * animation will go crazy. You've been warned. * \sa activated() */ void PsiIcon::stop() { d->activatedCount--; if ( d->activatedCount <= 0 ) { d->activatedCount = 0; if ( d->anim ) { d->anim->pause(); d->anim->restart(); } } } /** * As the name says, this function removes the first animation frame. This is used to * create system Psi iconsets, where first frame is used separately for menus. */ void PsiIcon::stripFirstAnimFrame() { detach(); if ( d->anim ) d->anim->stripFirstFrame(); } //---------------------------------------------------------------------------- // IconsetFactory //---------------------------------------------------------------------------- /** * \class IconsetFactory * \brief Class for easy application-wide PsiIcon searching * * You can add several Iconsets to IconsetFactory to use multiple Icons * application-wide with ease. * * You can reference Icons by their name from any place from your application. */ //! \if _hide_doc_ class IconsetFactoryPrivate : public QObject { private: IconsetFactoryPrivate() : QObject(QCoreApplication::instance()) , iconsets_(0) , emptyPixmap_(0) { } ~IconsetFactoryPrivate() { if (iconsets_) { while (!iconsets_->empty()) delete iconsets_->takeFirst(); delete iconsets_; iconsets_ = 0; } if (emptyPixmap_) { delete emptyPixmap_; emptyPixmap_ = 0; } } static IconsetFactoryPrivate* instance_; QList* iconsets_; mutable QPixmap* emptyPixmap_; public: const QPixmap& emptyPixmap() const { if (!emptyPixmap_) emptyPixmap_ = new QPixmap(); return *emptyPixmap_; } const QStringList icons() const { QStringList list; Iconset* iconset; foreach(iconset, *iconsets_) { QListIterator it = iconset->iterator(); while (it.hasNext()) list << it.next()->name(); } return list; } void registerIconset(const Iconset *); void unregisterIconset(const Iconset *); public: static IconsetFactoryPrivate* instance() { if (!instance_) { instance_ = new IconsetFactoryPrivate(); } return instance_; } const PsiIcon *icon(const QString &name) const; }; //! \endif IconsetFactoryPrivate* IconsetFactoryPrivate::instance_ = NULL; void IconsetFactoryPrivate::registerIconset(const Iconset *i) { if (!iconsets_) iconsets_ = new QList; if (!iconsets_->contains((Iconset*)i)) iconsets_->append((Iconset*)i); } void IconsetFactoryPrivate::unregisterIconset(const Iconset *i) { if (iconsets_ && iconsets_->contains((Iconset*)i)) iconsets_->removeAll((Iconset*)i); } const PsiIcon *IconsetFactoryPrivate::icon(const QString &name) const { if (!iconsets_) return 0; const PsiIcon *i = 0; Iconset *iconset; foreach (iconset, *iconsets_) { if ( iconset ) i = iconset->icon(name); if ( i ) break; } return i; } /** * Returns pointer to PsiIcon with name \a name, or \a 0 if PsiIcon with that name wasn't * found in IconsetFactory. */ const PsiIcon *IconsetFactory::iconPtr(const QString &name) { if (name.isEmpty()) return 0; const PsiIcon *i = IconsetFactoryPrivate::instance()->icon(name); if ( !i ) { qDebug("WARNING: IconsetFactory::icon(\"%s\"): icon not found", qPrintable(name)); } return i; } /** * Returns PsiIcon with name \a name, or empty PsiIcon if PsiIcon with that name wasn't * found in IconsetFactory. */ PsiIcon IconsetFactory::icon(const QString &name) { const PsiIcon *i = iconPtr(name); if ( i ) return *i; return PsiIcon(); } /** * Returns QPixmap of first animation frame of the specified PsiIcon, or the empty * QPixmap, if that PsiIcon wasn't found in IconsetFactory. * This function is faster than the call to IconsetFactory::icon() and cast to QPixmap, * because the intermediate PsiIcon object is not created and destroyed. */ const QPixmap &IconsetFactory::iconPixmap(const QString &name) { const PsiIcon *i = iconPtr(name); if ( i ) return i->impix().pixmap(); return IconsetFactoryPrivate::instance()->emptyPixmap(); } /** * Returns list of all PsiIcon names that are in IconsetFactory. */ const QStringList IconsetFactory::icons() { return IconsetFactoryPrivate::instance()->icons(); } //---------------------------------------------------------------------------- // Iconset //---------------------------------------------------------------------------- /** * \class Iconset * \brief Class for easy PsiIcon grouping * * This class supports loading Icons from .zip arhives. It also provides additional * information: name(), authors(), version(), description() and creation() date. * * This class is very handy to manage emoticon sets as well as usual application icons. * * \sa IconsetFactory */ //! \if _hide_doc_ class Iconset::Private : public QSharedData { private: void init() { name = "Unnamed"; //version = "1.0"; //description = "No description"; //authors << "I. M. Anonymous"; //creation = "1900-01-01"; homeUrl = QString::null; } public: QString name, version, description, creation, homeUrl, filename; QStringList authors; QHash dict; // unsorted hash for fast search QList list; // sorted list QHash info; public: Private() { init(); } Private(const Private &from) : QSharedData() { init(); setInformation(from); QListIterator it( from.list ); while ( it.hasNext() ) { PsiIcon *icon = new PsiIcon(*it.next()); append(icon->name(), icon); } } ~Private() { clear(); } void append(QString n, PsiIcon *icon) { // all PsiIcon names in Iconset must be unique if ( dict.contains(n) ) remove(n); dict[n] = icon; list.append(icon); } void clear() { dict.clear(); while ( !list.isEmpty() ) delete list.takeFirst(); } void remove(QString name) { if ( dict.contains(name) ) { PsiIcon *i = dict[name]; dict.erase( dict.find(name) ); list.removeAll(i); delete i; } } QByteArray loadData(const QString &fileName, const QString &dir) { QByteArray ba; QFileInfo fi(dir); if ( fi.isDir() ) { QFile file ( dir + '/' + fileName ); if (!file.open(QIODevice::ReadOnly)) return ba; ba = file.readAll(); } #ifdef ICONSET_ZIP else if ( fi.suffix() == "jisp" || fi.suffix() == "zip" ) { UnZip z(dir); if ( !z.open() ) return ba; QString n = fi.completeBaseName() + '/' + fileName; if ( !z.readFile(n, &ba) ) { n = "/" + fileName; z.readFile(n, &ba); } } #endif return ba; } void loadMeta(const QDomElement &i, const QString &dir) { Q_UNUSED(dir); for (QDomNode node = i.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if( e.isNull() ) continue; QString tag = e.tagName(); if ( tag == "name" ) { name = e.text(); } else if ( tag == "version" ) { version = e.text(); } else if ( tag == "description" ) { description = e.text(); } else if ( tag == "author" ) { QString n = e.text(); QString tmp = "
  "; if ( !e.attribute("email").isEmpty() ) { QString s = e.attribute("email"); n += tmp + QString("Email: %2").arg( s ).arg( s ); } if ( !e.attribute("jid").isEmpty() ) { QString s = e.attribute("jid"); n += tmp + QString("JID: %2").arg( s ).arg( s ); } if ( !e.attribute("www").isEmpty() ) { QString s = e.attribute("www"); n += tmp + QString("WWW: %2").arg( s ).arg( s ); } authors += n; } else if ( tag == "creation" ) { creation = e.text(); } else if ( tag == "home" ) { homeUrl = e.text(); } } } static int icon_counter; // used to give unique names to icons // will return 'true' when icon is loaded ok bool loadIcon(const QDomElement &i, const QString &dir) { PsiIcon icon; icon.blockSignals(true); QList text; QHash graphic, sound, object; QString name; name.sprintf("icon_%04d", icon_counter++); bool isAnimated = false; bool isImage = false; for(QDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if ( e.isNull() ) continue; QString tag = e.tagName(); if ( tag == "text" ) { QString lang = e.attribute("xml:lang"); if ( lang.isEmpty() ) lang = ""; // otherwise there would be many warnings :-( QString t = e.text(); if (!t.isEmpty()) { text.append(PsiIcon::IconText(lang, t)); } } else if ( tag == "object" ) { object[e.attribute("mime")] = e.text(); } else if ( tag == "x" ) { QString attr = e.attribute("xmlns"); if ( attr == "name" ) { name = e.text(); } else if ( attr == "type" ) { if ( e.text() == "animation" ) isAnimated = true; else if ( e.text() == "image" ) isImage = true; } } // leaved for compatibility with old JEP else if ( tag == "graphic" ) { graphic[e.attribute("mime")] = e.text(); } else if ( tag == "sound" ) { sound[e.attribute("mime")] = e.text(); } } icon.setText(text); icon.setName(name); QStringList graphicMime, soundMime, animationMime; graphicMime << "image/png"; // first item have higher priority than latter //graphicMime << "video/x-mng"; // due to very serious issue in Qt 4.1.0, this format was disabled graphicMime << "image/gif"; graphicMime << "image/x-xpm"; graphicMime << "image/bmp"; graphicMime << "image/jpeg"; graphicMime << "image/svg+xml"; // TODO: untested soundMime << "audio/x-wav"; soundMime << "audio/x-ogg"; soundMime << "audio/x-mp3"; soundMime << "audio/x-midi"; // MIME-types, that support animations animationMime << "image/gif"; //animationMime << "video/x-mng"; if ( !object.isEmpty() ) { // fill the graphic & sound tables, if there are some // 'object' entries. inspect the supported mimetypes // and copy mime info and file path to 'graphic' and // 'sound' dictonaries. QStringList::Iterator it = graphicMime.begin(); for ( ; it != graphicMime.end(); ++it) if ( object.contains(*it) && !object[*it].isNull() ) graphic[*it] = object[*it]; it = soundMime.begin(); for ( ; it != soundMime.end(); ++it) if ( object.contains(*it) && !object[*it].isNull() ) sound[*it] = object[*it]; } bool loadSuccess = false; { QStringList::Iterator it = graphicMime.begin(); for ( ; it != graphicMime.end(); ++it) { if ( graphic.contains(*it) && !graphic[*it].isNull() ) { // if format supports animations, then load graphic as animation, and // if there is only one frame, then later it would be converted to single Impix if ( !isAnimated && !isImage ) { QStringList::Iterator it2 = animationMime.begin(); for ( ; it2 != animationMime.end(); ++it2) if ( *it == *it2 ) { isAnimated = true; break; } } QByteArray ba = loadData(graphic[*it], dir); if ( icon.loadFromData( ba, isAnimated ) ) { loadSuccess = true; break; } else { qDebug("Iconset::load(): Couldn't load %s (%s) graphic for the %s icon for the %s iconset", qPrintable(*it), qPrintable(graphic[*it]), qPrintable(name), qPrintable(this->name)); loadSuccess = false; } } } } { QFileInfo fi(dir); QStringList::Iterator it = soundMime.begin(); for ( ; it != soundMime.end(); ++it) { if ( sound.contains(*it) && !sound[*it].isNull() ) { if ( !fi.isDir() ) { // it is a .zip file then #ifdef ICONSET_SOUND if ( !iconSharedObject ) iconSharedObject = new IconSharedObject(); QString path = iconSharedObject->unpackPath; if ( path.isEmpty() ) break; QFileInfo ext(sound[*it]); path += "/" + QCA::Hash("sha1").hashToString(QString(fi.absoluteFilePath() + '/' + sound[*it]).toUtf8()) + '.' + ext.suffix(); QFile file ( path ); file.open ( QIODevice::WriteOnly ); QDataStream out ( &file ); QByteArray data = loadData(sound[*it], dir); out.writeRawData (data, data.size()); icon.setSound ( path ); break; #endif } else { icon.setSound ( fi.absoluteFilePath() + '/' + sound[*it] ); break; } } } } // construct RegExp if ( text.count() ) { QStringList regexp; foreach(PsiIcon::IconText t, text) { regexp += QRegExp::escape(t.text); } // make sure there is some form of whitespace on at least one side of the text string //regexp = QString("(\\b(%1))|((%2)\\b)").arg(regexp).arg(regexp); icon.setRegExp ( QRegExp(regexp.join("|")) ); } icon.blockSignals(false); if ( loadSuccess ) { append( name, new PsiIcon(icon) ); } else { qWarning("can't load icon because of unknown type"); } return loadSuccess; } // would return 'true' on success bool load(const QDomDocument &doc, const QString dir) { QDomElement base = doc.documentElement(); if ( base.tagName() != "icondef" ) { qWarning("failed to load iconset invalid toplevel xml element"); return false; } bool success = true; for(QDomNode node = base.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement i = node.toElement(); if( i.isNull() ) continue; QString tag = i.tagName(); if ( tag == "meta" ) { loadMeta (i, dir); } else if ( tag == "icon" ) { bool ret = loadIcon (i, dir); if ( !ret ) success = false; } else if ( tag == "x" ) { info[i.attribute("xmlns")] = i.text(); } } return success; } void setInformation(const Private &from) { name = from.name; version = from.version; description = from.description; creation = from.creation; homeUrl = from.homeUrl; filename = from.filename; authors = from.authors; info = from.info; } }; //! \endif int Iconset::Private::icon_counter = 0; //static int iconset_counter = 0; /** * Creates empty Iconset. */ Iconset::Iconset() { //iconset_counter++; d = new Private; } /** * Creates shared copy of Iconset \a from. */ Iconset::Iconset(const Iconset &from) { //iconset_counter++; d = from.d; } /** * Destroys Iconset, and frees all allocated Icons. */ Iconset::~Iconset() { IconsetFactoryPrivate::instance()->unregisterIconset(this); } /** * Copies all Icons as well as additional information from Iconset \a from. */ Iconset &Iconset::operator=(const Iconset &from) { d = from.d; return *this; } Iconset Iconset::copy() const { Iconset is; is.d = new Private( *this->d.data() ); return is; } void Iconset::detach() { d.detach(); } /** * Appends icons from Iconset \a from to this Iconset. */ Iconset &Iconset::operator+=(const Iconset &i) { detach(); QListIterator it( i.d->list ); while ( it.hasNext() ) { PsiIcon *icon = new PsiIcon(*it.next()); d->append( icon->name(), icon ); } return *this; } /** * Frees all allocated Icons. */ void Iconset::clear() { detach(); d->clear(); } /** * Returns the number of Icons in Iconset. */ int Iconset::count() const { return d->list.count(); } /** * Loads Icons and additional information from directory \a dir. Directory can usual directory, * or a .zip/.jisp archive. There must exist file named \c icondef.xml in that directory. */ bool Iconset::load(const QString &dir) { if (dir.isEmpty()) { return false; } Q_ASSERT(!dir.isEmpty()); detach(); // make it run okay on windows 9.x (where the pixmap memory is limited) //QPixmap::Optimization optimization = QPixmap::defaultOptimization(); //QPixmap::setDefaultOptimization( QPixmap::MemoryOptim ); bool ret = false; QByteArray ba; ba = d->loadData ("icondef.xml", dir); if ( !ba.isEmpty() ) { QDomDocument doc; if ( doc.setContent(ba, false) ) { if ( d->load(doc, dir) ) { d->filename = dir; ret = true; } } else { qWarning("Iconset::load(\"%s\"): Failed to load iconset: icondef.xml is invalid XML", qPrintable(dir)); } } else { qWarning("Iconset::load(\"%s\"): Failed to load iconset.xml", qPrintable(dir)); } //QPixmap::setDefaultOptimization( optimization ); return ret; } /** * Returns pointer to PsiIcon, if PsiIcon with name \a name was found in Iconset, or \a 0 otherwise. * \sa setIcon() */ const PsiIcon *Iconset::icon(const QString &name) const { if ( !d || d->dict.isEmpty() ) return 0; return d->dict[name]; } /** * Appends PsiIcon to Iconset. If the PsiIcon with that name already exists, it is removed. */ void Iconset::setIcon(const QString &name, const PsiIcon &icon) { detach(); PsiIcon *newIcon = new PsiIcon(icon); d->remove(name); d->append( name, newIcon ); } /** * Removes PsiIcon with the name \a name from Iconset. */ void Iconset::removeIcon(const QString &name) { detach(); d->remove(name); } /** * Returns the Iconset name. */ const QString &Iconset::name() const { return d->name; } /** * Returns the Iconset version. */ const QString &Iconset::version() const { return d->version; } /** * Returns the Iconset description string. */ const QString &Iconset::description() const { return d->description; } /** * Returns the Iconset authors list. */ const QStringList &Iconset::authors() const { return d->authors; } /** * Returns the Iconset creation date. */ const QString &Iconset::creation() const { return d->creation; } /** * Returns the Iconsets' home URL. */ const QString &Iconset::homeUrl() const { return d->homeUrl; } QListIterator Iconset::iterator() const { QListIterator it( d->list ); return it; } /** * Returns directory (or .zip/.jisp archive) name from which Iconset was loaded. */ const QString &Iconset::fileName() const { return d->filename; } /** * Sets the Iconset directory (.zip archive) name. */ void Iconset::setFileName(const QString &f) { d->filename = f; } /** * Sets the information (meta-data) of this iconset to the information from the given iconset. */ void Iconset::setInformation(const Iconset &from) { detach(); d->setInformation( *(from.d) ); } /** * Returns additional Iconset information. * \sa setInfo() */ const QHash Iconset::info() const { return d->info; } /** * Sets additional Iconset information. * \sa info() */ void Iconset::setInfo(const QHash &i) { d->info = i; } /** * Adds Iconset to IconsetFactory. */ void Iconset::addToFactory() const { IconsetFactoryPrivate::instance()->registerIconset(this); } /** * Removes Iconset from IconsetFactory. */ void Iconset::removeFromFactory() const { IconsetFactoryPrivate::instance()->unregisterIconset(this); } /** * Use this function before creation of Iconsets and it will enable the * sound playing ability when Icons are activated(). * * \a unpackPath is the path, to where the sound files will be unpacked, if * required (i.e. when sound is stored inside packed iconset.zip file). Unpacked * file name will be unique, and you can empty the unpack directory at the application * exit. Calling application MUST ensure that the \a unpackPath is already created. * If specified \a unpackPath is empty ("" or QString::null) then sounds from archives * will not be unpacked, and only sounds from already unpacked iconsets (that are not * stored in archives) will be played. * \a receiver and \a slot are used to specify the object that will be connected to * the signal 'playSound(QString fileName)'. Slot should play the specified sound * file. */ void Iconset::setSoundPrefs(QString unpackPath, QObject *receiver, const char *slot) { #ifdef ICONSET_SOUND if ( !iconSharedObject ) iconSharedObject = new IconSharedObject(); iconSharedObject->unpackPath = unpackPath; QObject::connect(iconSharedObject, SIGNAL(playSound(QString)), receiver, slot); #else Q_UNUSED(unpackPath); Q_UNUSED(receiver); Q_UNUSED(slot); #endif } #include "iconset.moc" psi-0.14/src/tools/iconset/anim.h0000644000175000017500000000332011305557613015027 0ustar janjan/* * anim.h - class for handling animations * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ANIM_H #define ANIM_H #include #include class QObject; class QPixmap; class QImage; class Impix; class QThread; class Anim { public: Anim(); Anim(const QByteArray &data); Anim(const Anim &anim); ~Anim(); const QPixmap &framePixmap() const; const QImage &frameImage() const; const Impix &frameImpix() const; bool isNull() const; int frameNumber() const; int numFrames() const; const Impix &frame(int n) const; bool paused() const; void unpause(); void pause(); void restart(); void stripFirstFrame(); static QThread *mainThread(); static void setMainThread(QThread *); void connectUpdate(QObject *receiver, const char *member); void disconnectUpdate(QObject *receiver, const char *member = 0); Anim & operator= (const Anim &); Anim copy() const; void detach(); class Private; private: QSharedDataPointer d; }; #endif psi-0.14/src/tools/iconset/anim.cpp0000644000175000017500000001675511305557613015402 0ustar janjan/* * anim.cpp - class for handling animations * Copyright (C) 2003-2006 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "anim.h" #include "iconset.h" #include #include #include //#include #include #include #include /** * \class Anim * \brief Class for handling animations * * Anim is a class that can load animations. Generally, it looks like * QMovie but it loads animations in one pass and stores it in memory. * * Each frame of Anim is stored as Impix. */ static QThread *animMainThread = 0; //! \if _hide_doc_ class Anim::Private : public QObject, public QSharedData { Q_OBJECT public: QTimer *frametimer; bool empty; bool paused; int speed; int lasttimerinterval; int looping, loop; class Frame { public: Impix impix; int period; }; QList frames; int frame; public: void init() { frametimer = new QTimer(); if (animMainThread && animMainThread != QThread::currentThread()) { frametimer->moveToThread(animMainThread); moveToThread(animMainThread); } QObject::connect(frametimer, SIGNAL(timeout()), this, SLOT(refresh())); speed = 120; lasttimerinterval = -1; looping = 0; // MNG movies doesn't have loop flag? loop = 0; frame = 0; paused = true; } Private() { init(); } Private(const Private &from) : QObject(), QSharedData() { init(); speed = from.speed; lasttimerinterval = from.lasttimerinterval; looping = from.looping; loop = from.loop; frame = from.frame; paused = from.paused; frames = from.frames; if ( !paused ) unpause(); } Private(const QByteArray *ba) { init(); QBuffer buffer((QByteArray *)ba); buffer.open(QBuffer::ReadOnly); QImageReader reader(&buffer); while ( reader.canRead() ) { QImage image = reader.read(); if ( !image.isNull() ) { Frame newFrame; frames.append( newFrame ); frames.last().impix = Impix(image); frames.last().period = reader.nextImageDelay(); } else { break; } } looping = reader.loopCount(); if ( !reader.supportsAnimation() && (frames.count() == 1) ) { QImage frame = frames[0].impix.image(); // we're gonna slice the single image we've got if we're absolutely sure // that it's can be cut into multiple frames if ((frame.width() / frame.height() > 0) && !(frame.width() % frame.height())) { int h = frame.height(); QList newFrames; for (int i = 0; i < frame.width() / frame.height(); i++) { Frame newFrame; newFrames.append( newFrame ); newFrames.last().impix = Impix(frame.copy(i * h, 0, h, h)); newFrames.last().period = 120; } frames = newFrames; looping = 0; } } } ~Private() { if ( frametimer ) delete frametimer; } void pause() { paused = true; frametimer->stop(); } void unpause() { paused = false; restartTimer(); } void restart() { frame = 0; if ( !paused ) restartTimer(); } int numFrames() const { return frames.count(); } void restartTimer() { if ( !paused && speed > 0 ) { int frameperiod = frames[frame].period; int i = frameperiod >= 0 ? frameperiod * 100/speed : 0; if ( i != lasttimerinterval || !frametimer->isActive() ) { lasttimerinterval = i; frametimer->start( i ); } } else { frametimer->stop(); } } signals: void areaChanged(); public slots: void refresh() { frame++; if ( frame >= numFrames() ) { frame = 0; loop++; if ( looping && loop >= looping ) { frame = numFrames() - 1; pause(); restart(); } } emit areaChanged(); restartTimer(); } }; //! \endif /** * Creates an empty animation. */ Anim::Anim() { d = new Private(); } /** * Creates animation from QByteArray \a data. */ Anim::Anim(const QByteArray &data) { d = new Private(&data); } /** * Creates shared copy of Anim \a anim. */ Anim::Anim(const Anim &anim) { d = anim.d; } /** * Deletes animation. */ Anim::~Anim() { } /** * Returns QPixmap of current frame. */ const QPixmap &Anim::framePixmap() const { return d->frames[d->frame].impix.pixmap(); } /** * Returns QImage of current frame. */ const QImage &Anim::frameImage() const { return d->frames[d->frame].impix.image(); } /** * Returns Impix of current frame. */ const Impix &Anim::frameImpix() const { return d->frames[d->frame].impix; } /** * Returns total number of frames in animation. */ int Anim::numFrames() const { return d->numFrames(); } /** * Returns the number of current animation frame. */ int Anim::frameNumber() const { return d->frame; } /** * Returns Impix of animation frame number \a n. */ const Impix &Anim::frame(int n) const { return d->frames[n].impix; } /** * Returns \c true if numFrames() == 0 and \c false otherwise. */ bool Anim::isNull() const { return !numFrames(); } /** * Returns \c true when animation is paused. */ bool Anim::paused() const { return d->paused; } /** * Continues the animation playback. */ void Anim::unpause() { if ( !isNull() && paused() ) d->unpause(); } /** * Pauses the animation. */ void Anim::pause() { if ( !isNull() && !paused() ) d->pause(); } /** * Starts animation from the very beginning. */ void Anim::restart() { if ( !isNull() ) d->restart(); } /** * Connects internal signal with specified slot \a member of object \a receiver, which * is emitted when animation changes its frame. * * \code * class MyObject : public QObject { * Q_OBJECT * // ... * Anim *anim; * void initAnim() { * anim = new Anim( QByteArray(someData()) ); * anim->connectUpdate( this, SLOT(animUpdated()) ); * } * public slots: * void animUpdated(); * // ... * } * \endcode * * \sa disconnectUpdate() */ void Anim::connectUpdate(QObject *receiver, const char *member) { QObject::connect(d, SIGNAL(areaChanged()), receiver, member); } /** * Disconnects slot \a member, which was prevously connected with connectUpdate(). * \sa connectUpdate() */ void Anim::disconnectUpdate(QObject *receiver, const char *member) { QObject::disconnect(d, SIGNAL(areaChanged()), receiver, member); } Anim & Anim::operator= (const Anim &from) { d = from.d; return *this; } Anim Anim::copy() const { Anim anim( *this ); anim.d = new Private( *this->d.data() ); return anim; } void Anim::detach() { d.detach(); } /** * Strips the first animation frame, if there is more than one frame. */ void Anim::stripFirstFrame() { detach(); if ( numFrames() > 1 ) { d->frames.takeFirst(); if ( !paused() ) restart(); } } /** * Sets the main thread that will be used to create objects. Useful if you want * to create Anim in non-main thread. */ void Anim::setMainThread(QThread *thread) { animMainThread = thread; } /** * Get the Anim's main thread. */ QThread *Anim::mainThread() { return animMainThread; } #include "anim.moc" psi-0.14/src/tools/iconset/iconset.h0000644000175000017500000001227611305557613015561 0ustar janjan/* * iconset.h - various graphics handling classes * Copyright (C) 2001-2006 Justin Karneges, Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ICONSET_H #define ICONSET_H #include #include #include #include #include #include #include #include #include class QIcon; class Anim; class Impix { public: Impix(); Impix(const QPixmap &); Impix(const QImage &); void unload(); bool isNull() const; const QPixmap & pixmap() const; const QImage & image() const; void setPixmap(const QPixmap &); void setImage(const QImage &); operator const QPixmap &() const { return pixmap(); } operator const QImage &() const { return image(); } Impix & operator=(const QPixmap &from) { setPixmap(from); return *this; } Impix & operator=(const QImage &from) { setImage(from); return *this; } bool loadFromData(const QByteArray &); private: class Private : public QSharedData { public: QPixmap* pixmap; QImage image; Private() { pixmap = 0; } Private(const Private& from) : QSharedData(from) { pixmap = from.pixmap ? new QPixmap(*from.pixmap) : 0; image = from.image; } ~Private() { unload(); } void unload() { if (pixmap) delete pixmap; pixmap = 0; image = QImage(); } }; mutable QSharedDataPointer d; }; class PsiIcon : public QObject { Q_OBJECT public: PsiIcon(); PsiIcon(const PsiIcon &); ~PsiIcon(); PsiIcon & operator= (const PsiIcon &); //! //! Returns impix().pixmap(). // operator const QPixmap &() const { return impix().pixmap(); } //! //! Returns impix().image(). // operator const QImage &() const { return impix().image(); } //! //! see icon(). // operator const QIcon &() const { return icon(); } virtual bool isAnimated() const; virtual const QPixmap &pixmap() const; virtual const QImage &image() const; virtual const QIcon & icon() const; virtual const Impix &impix() const; virtual const Impix &frameImpix() const; void setImpix(const Impix &, bool doDetach = true); const Anim *anim() const; void setAnim(const Anim &, bool doDetach = true); void removeAnim(bool doDetach = true); virtual int frameNumber() const; virtual const QString &name() const; void setName(const QString &); const QRegExp ®Exp() const; void setRegExp(const QRegExp &); struct IconText { IconText(QString _lang, QString _text) : lang(_lang), text(_text) {} QString lang; QString text; }; const QList &text() const; void setText(const QList &); QString defaultText() const; const QString &sound() const; void setSound(const QString &); bool blockSignals(bool); bool loadFromData(const QByteArray &, bool isAnimation); void stripFirstAnimFrame(); virtual PsiIcon *copy() const; void detach(); signals: void pixmapChanged(); void iconModified(); public slots: virtual void activated(bool playSound = true); // it just has been inserted in the text, or now it's being displayed by // some widget. icon should play sound and start animation virtual void stop(); // this icon is no more displaying. stop animation public: class Private; private: QSharedDataPointer d; }; class Iconset { public: Iconset(); Iconset(const Iconset &); ~Iconset(); Iconset &operator=(const Iconset &); Iconset &operator+=(const Iconset &); void clear(); int count() const; bool load(const QString &dir); const PsiIcon *icon(const QString &) const; void setIcon(const QString &, const PsiIcon &); void removeIcon(const QString &); const QString &name() const; const QString &version() const; const QString &description() const; const QStringList &authors() const; const QString &creation() const; const QString &homeUrl() const; const QString &fileName() const; void setFileName(const QString &); void setInformation(const Iconset &from); const QHash info() const; void setInfo(const QHash &); QListIterator iterator() const; void addToFactory() const; void removeFromFactory() const; static void setSoundPrefs(QString unpackPath, QObject *receiver, const char *slot); Iconset copy() const; void detach(); private: class Private; QSharedDataPointer d; }; class IconsetFactory { public: static PsiIcon icon(const QString &name); static const QPixmap &iconPixmap(const QString &name); static const PsiIcon *iconPtr(const QString &name); static const QStringList icons(); }; #endif psi-0.14/src/tools/iconset/ICONSET-HOWTO0000644000175000017500000000645011305557613015666 0ustar janjanIconset-HOWTO ~~~~~~~~~~~~~ Step-by-step guide how to create an iconset. 1. Create a directory, and name it somehow. For example "my-first-iconset". 2. Create a file named "icondef.xml" in that directory. 3. Place all icons and sounds you want to use in iconset, in that directory. 4. Start editind "icondef.xml" with your favourite XML editor. 5. Write the following tags in it: 6. First, add the iconset meta information: Iconset Name Iconset Version Iconset Description 2003-01-25 http://www.myiconsethomepage.com Michail Pishchagin I.M. Anonymous 7. Now, it's time to add some icons: :-) :) :smiley: smiley.png smiley.wav This iconset contains only one icon, that is associated with the following strings: ':-)', ':)', ':smiley:'. When it is shown on screen, it will be displayed as 'smiley.png' image, and will play the 'smiley.wav' sound. Possible mime-types are: 1. For images: image/png -- preferred image format video/x-mng (animated format) image/gif (animated format) image/x-xpm image/bmp image/jpeg image/svg+xml 2. For sounds: audio/x-wav -- preferred sound format, as it can be played on all Psi platforms audio/x-ogg audio/x-mp3 audio/x-midi -- not really supported Multiple graphic mime types, and sound mime types can be specified simultaneously: smiley.png smiley.mng smiley.gif smiley.wav smiley.ogg 8. Advanced Psi icon tags: The following icon specifies its name. It is primately used in system Psi iconsets: smiley.png smiley.wav emoticon/smiley And it can be forced for icon to be animated, or not: connect.png psi/connect animation This way, icon will be animated. Animation frames are laid horizontally in that single .png graphic. connect.png psi/connect image And this way, it will be loaded as single graphic. 9. Packing it all together: Pack your 'my-first-iconset' directory in a my-first-iconset.zip archive using your favourite archiver. Please note, that name of directory and name of archive MUST be the same. Then, you should rename the resulting file to my-first-iconset.jisp and distribute that file. Good Luck! :-) psi-0.14/src/tools/tunecontroller/0000755000175000017500000000000011305557613015347 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/0000755000175000017500000000000011305557613017030 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/xmms/0000755000175000017500000000000011305557613020014 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/xmms/xmmscontroller.cpp0000644000175000017500000000256011305557613023613 0ustar janjan/* * xmmscontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "xmmscontroller.h" /** * \class XMMSController * \brief A controller for XMMS. */ /** * \brief Constructs the controller. */ XMMSController::XMMSController() : PollingTuneController() { } Tune XMMSController::currentTune() { Tune tune; if (xmms_remote_is_running(0) && xmms_remote_is_playing(0)) { int pos = xmms_remote_get_playlist_pos(0); char* c_title = xmms_remote_get_playlist_title(0,pos); if (c_title) { tune.setName(QString(c_title)); free(c_title); } tune.setTime(xmms_remote_get_playlist_time(0,pos) / 1000); } return tune; } psi-0.14/src/tools/tunecontroller/plugins/xmms/xmmscontroller.h0000644000175000017500000000200711305557613023254 0ustar janjan/* * xmmscontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMMSCONTROLLER_H #define XMMSCONTROLLER_H #include "tunecontrollerinterface.h" #include "pollingtunecontroller.h" class XMMSController : public PollingTuneController { public: XMMSController(); virtual Tune currentTune(); }; #endif psi-0.14/src/tools/tunecontroller/plugins/xmms/xmmsplugin.cpp0000644000175000017500000000245111305557613022725 0ustar janjan/* * xmmsplugin.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #define QT_STATICPLUGIN #include #include #include #include "tunecontrollerplugin.h" #include "xmmscontroller.h" class XMMSPlugin : public QObject, public TuneControllerPlugin { Q_OBJECT Q_INTERFACES(TuneControllerPlugin) public: virtual QString name(); virtual TuneController* createController(); }; Q_EXPORT_PLUGIN2(xmmsplugin, XMMSPlugin); QString XMMSPlugin::name() { return "XMMS"; } TuneController* XMMSPlugin::createController() { return new XMMSController(); } #include "xmmsplugin.moc" psi-0.14/src/tools/tunecontroller/plugins/winamp/0000755000175000017500000000000011305557613020323 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/winamp/winampplugin.cpp0000644000175000017500000000174611305557613023551 0ustar janjan/* * winampplugin.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "winampplugin.h" QString WinAmpPlugin::name() { return "WinAmp"; } TuneController* WinAmpPlugin::createController() { return new WinAmpController(); } Q_EXPORT_PLUGIN2(winampplugin, WinAmpPlugin); psi-0.14/src/tools/tunecontroller/plugins/winamp/winampplugin.h0000644000175000017500000000227311305557613023212 0ustar janjan/* * winampplugin.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WINAMPPLUGIN_H #define WINAMPPLUGIN_H #ifndef QT_STATICPLUGIN #define QT_STATICPLUGIN #endif #include #include #include #include "winampcontroller.h" #include "tunecontrollerplugin.h" class WinAmpPlugin : public QObject, public TuneControllerPlugin { Q_OBJECT Q_INTERFACES(TuneControllerPlugin) public: virtual QString name(); virtual TuneController* createController(); }; #endif psi-0.14/src/tools/tunecontroller/plugins/winamp/third-party/0000755000175000017500000000000011305557613022572 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/winamp/third-party/wa_ipc.h0000644000175000017500000010302711305557613024210 0ustar janjan/* ** Copyright (C) 2003 Nullsoft, Inc. ** ** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held ** liable for any damages arising from the use of this software. ** ** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to ** alter it and redistribute it freely, subject to the following restrictions: ** ** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. ** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. ** ** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. ** ** 3. This notice may not be removed or altered from any source distribution. ** */ #ifndef _WA_IPC_H_ #define _WA_IPC_H_ /* ** This is the modern replacement for the classic 'frontend.h'. Most of these ** updates are designed for in-process use, i.e. from a plugin. ** */ /* message used to sent many messages to winamp's main window. ** most all of the IPC_* messages involve sending the message in the form of: ** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*); */ #define WM_WA_IPC WM_USER /* but some of them use WM_COPYDATA. be afraid. */ #define IPC_GETVERSION 0 /* int version = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION); ** ** Version will be 0x20yx for winamp 2.yx. versions previous to Winamp 2.0 ** typically (but not always) use 0x1zyx for 1.zx versions. Weird, I know. */ #define IPC_GETREGISTEREDVERSION 770 typedef struct { char *filename; char *title; int length; } enqueueFileWithMetaStruct; // send this to a IPC_PLAYFILE in a non WM_COPYDATA, // and you get the nice desired result. if title is NULL, it is treated as a "thing", // otherwise it's assumed to be a file (for speed) #define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile #define IPC_ENQUEUEFILE 100 /* sent as a WM_COPYDATA, with IPC_PLAYFILE as the dwData, and the string to play ** as the lpData. Just enqueues, does not clear the playlist or change the playback ** state. */ #define IPC_DELETE 101 #define IPC_DELETE_INT 1101 // don't use this, it's used internally by winamp when // dealing with some lame explorer issues. /* SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE); ** Use IPC_DELETE to clear Winamp's internal playlist. */ #define IPC_STARTPLAY 102 // starts playback. almost like hitting play in Winamp. #define IPC_STARTPLAY_INT 1102 // used internally, don't bother using it (won't be any fun) #define IPC_CHDIR 103 /* sent as a WM_COPYDATA, with IPC_CHDIR as the dwData, and the directory to change to ** as the lpData. */ #define IPC_ISPLAYING 104 /* int res = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING); ** If it returns 1, it is playing. if it returns 3, it is paused, ** if it returns 0, it is not playing. */ #define IPC_GETOUTPUTTIME 105 /* int res = SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME); ** returns the position in milliseconds of the current track (mode = 0), ** or the track length, in seconds (mode = 1). Returns -1 if not playing or error. */ #define IPC_JUMPTOTIME 106 /* (requires Winamp 1.60+) ** SendMessage(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME); ** IPC_JUMPTOTIME sets the position in milliseconds of the ** current song (approximately). ** Returns -1 if not playing, 1 on eof, or 0 if successful */ #define IPC_GETMODULENAME 109 #define IPC_EX_ISRIGHTEXE 666 /* usually shouldnt bother using these, but here goes: ** send a WM_COPYDATA with IPC_GETMODULENAME, and an internal ** flag gets set, which if you send a normal WM_WA_IPC message with ** IPC_EX_ISRIGHTEXE, it returns whether or not that filename ** matches. lame, I know. */ #define IPC_WRITEPLAYLIST 120 /* (requires Winamp 1.666+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST); ** ** IPC_WRITEPLAYLIST writes the current playlist to \\Winamp.m3u, ** and returns the current playlist position. ** Kinda obsoleted by some of the 2.x new stuff, but still good for when ** using a front-end (instead of a plug-in) */ #define IPC_SETPLAYLISTPOS 121 /* (requires Winamp 2.0+) ** SendMessage(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS) ** IPC_SETPLAYLISTPOS sets the playlist position to 'position'. It ** does not change playback or anything, it just sets position, and ** updates the view if necessary */ #define IPC_SETVOLUME 122 /* (requires Winamp 2.0+) ** SendMessage(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME); ** IPC_SETVOLUME sets the volume of Winamp (from 0-255). */ #define IPC_SETPANNING 123 /* (requires Winamp 2.0+) ** SendMessage(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING); ** IPC_SETPANNING sets the panning of Winamp (from 0 (left) to 255 (right)). */ #define IPC_GETLISTLENGTH 124 /* (requires Winamp 2.0+) ** int length = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH); ** IPC_GETLISTLENGTH returns the length of the current playlist, in ** tracks. */ #define IPC_GETLISTPOS 125 /* (requires Winamp 2.05+) ** int pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS); ** IPC_GETLISTPOS returns the playlist position. A lot like IPC_WRITEPLAYLIST ** only faster since it doesn't have to write out the list. Heh, silly me. */ #define IPC_GETINFO 126 /* (requires Winamp 2.05+) ** int inf=SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO); ** IPC_GETINFO returns info about the current playing song. The value ** it returns depends on the value of 'mode'. ** Mode Meaning ** ------------------ ** 0 Samplerate (i.e. 44100) ** 1 Bitrate (i.e. 128) ** 2 Channels (i.e. 2) ** 3 (5+) Video LOWORD=w HIWORD=h ** 4 (5+) > 65536, string (video description) */ #define IPC_GETEQDATA 127 /* (requires Winamp 2.05+) ** int data=SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA); ** IPC_GETEQDATA queries the status of the EQ. ** The value returned depends on what 'pos' is set to: ** Value Meaning ** ------------------ ** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db) ** 10 The preamp value. 0-63 (+20db - -20db) ** 11 Enabled. zero if disabled, nonzero if enabled. ** 12 Autoload. zero if disabled, nonzero if enabled. */ #define IPC_SETEQDATA 128 /* (requires Winamp 2.05+) ** SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA); ** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA); ** IPC_SETEQDATA sets the value of the last position retrieved ** by IPC_GETEQDATA. This is pretty lame, and we should provide ** an extended version that lets you do a MAKELPARAM(pos,value). ** someday... new (2.92+): if the high byte is set to 0xDB, then the third byte specifies which band, and the bottom word specifies the value. */ #define IPC_ADDBOOKMARK 129 /* (requires Winamp 2.4+) ** Sent as a WM_COPYDATA, using IPC_ADDBOOKMARK, adds the specified ** file/url to the Winamp bookmark list. */ /* In winamp 5+, we use this as a normal WM_WA_IPC and the string: "filename\0title\0" to notify the library/bookmark editor that a bookmark was added. Note that using this message in this context does not actually add the bookmark. do not use :) */ #define IPC_INSTALLPLUGIN 130 /* not implemented, but if it was you could do a WM_COPYDATA with ** a path to a .wpz, and it would install it. */ #define IPC_RESTARTWINAMP 135 /* (requires Winamp 2.2+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP); ** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :) */ #define IPC_ISFULLSTOP 400 /* (requires winamp 2.7+ I think) ** ret=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISFULLSTOP); ** useful for when you're an output plugin, and you want to see ** if the stop/close is a full stop, or just between tracks. ** returns nonzero if it's full, zero if it's just a new track. */ #define IPC_INETAVAILABLE 242 /* (requires Winamp 2.05+) ** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE); ** IPC_INETAVAILABLE will return 1 if the Internet connection is available for Winamp. */ #define IPC_UPDTITLE 243 /* (requires Winamp 2.2+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE); ** IPC_UPDTITLE will ask Winamp to update the informations about the current title. */ #define IPC_REFRESHPLCACHE 247 /* (requires Winamp 2.2+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE); ** IPC_REFRESHPLCACHE will flush the playlist cache buffer. ** (send this if you want it to go refetch titles for tracks) */ #define IPC_GET_SHUFFLE 250 /* (requires Winamp 2.4+) ** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE); ** ** IPC_GET_SHUFFLE returns the status of the Shuffle option (1 if set) */ #define IPC_GET_REPEAT 251 /* (requires Winamp 2.4+) ** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT); ** ** IPC_GET_REPEAT returns the status of the Repeat option (1 if set) */ #define IPC_SET_SHUFFLE 252 /* (requires Winamp 2.4+) ** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE); ** ** IPC_SET_SHUFFLE sets the status of the Shuffle option (1 to turn it on) */ #define IPC_SET_REPEAT 253 /* (requires Winamp 2.4+) ** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT); ** ** IPC_SET_REPEAT sets the status of the Repeat option (1 to turn it on) */ #define IPC_ENABLEDISABLE_ALL_WINDOWS 259 // 0xdeadbeef to disable /* (requires Winamp 2.9+) ** SendMessage(hwnd_winamp,WM_WA_IPC,enable?0:0xdeadbeef,IPC_MBOPENREAL); ** sending with 0xdeadbeef as the param disables all winamp windows, ** any other values will enable all winamp windows. */ #define IPC_GETWND 260 /* (requires Winamp 2.9+) ** HWND h=SendMessage(hwnd_winamp,WM_WA_IPC,IPC_GETWND_xxx,IPC_GETWND); ** returns the HWND of the window specified. */ #define IPC_GETWND_EQ 0 // use one of these for the param #define IPC_GETWND_PE 1 #define IPC_GETWND_MB 2 #define IPC_GETWND_VIDEO 3 #define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND /************************************************************************ ***************** in-process only (WE LOVE PLUGINS) ************************************************************************/ #define IPC_SETSKIN 200 /* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN); ** IPC_SETSKIN sets the current skin to "skinname". Note that skinname ** can be the name of a skin, a skin .zip file, with or without path. ** If path isn't specified, the default search path is the winamp skins ** directory. */ #define IPC_GETSKIN 201 /* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN); ** IPC_GETSKIN puts the directory where skin bitmaps can be found ** into skinname_buffer. ** skinname_buffer must be MAX_PATH characters in length. ** When using a .zip'd skin file, it'll return a temporary directory ** where the ZIP was decompressed. */ #define IPC_EXECPLUG 202 /* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG); ** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM. ** the format of this string can be: ** "vis_whatever.dll" ** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir) ** "C:\\dir\\vis_whatever.dll,1" */ #define IPC_GETPLAYLISTFILE 211 /* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) ** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE); ** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index]. ** returns a pointer to it. returns NULL on error. */ #define IPC_GETPLAYLISTTITLE 212 /* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) ** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE); ** ** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index]. ** returns a pointer to it. returns NULL on error. */ #define IPC_GETHTTPGETTER 240 /* retrieves a function pointer to a HTTP retrieval function. ** if this is unsupported, returns 1 or 0. ** the function should be: ** int (*httpRetrieveFile)(HWND hwnd, char *url, char *file, char *dlgtitle); ** if you call this function, with a parent window, a URL, an output file, and a dialog title, ** it will return 0 on successful download, 1 on error. */ #define IPC_MBOPEN 241 /* (requires Winamp 2.05+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN); ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN); ** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window. */ #define IPC_CHANGECURRENTFILE 245 /* (requires Winamp 2.05+) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE); ** IPC_CHANGECURRENTFILE will set the current playlist item. */ #define IPC_GETMBURL 246 /* (requires Winamp 2.2+) ** char buffer[4096]; // Urls can be VERY long ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL); ** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer. ** buffer must be at least 4096 bytes long. */ #define IPC_MBBLOCK 248 /* (requires Winamp 2.4+) ** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK); ** ** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1 */ #define IPC_MBOPENREAL 249 /* (requires Winamp 2.4+) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL); ** ** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if ** IPC_MBBLOCK has been set to 1 */ #define IPC_ADJUST_OPTIONSMENUPOS 280 /* (requires Winamp 2.9+) ** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS); ** moves where winamp expects the Options menu in the main menu. Useful if you wish to insert a ** menu item above the options/skins/vis menus. */ #define IPC_GET_HMENU 281 /* (requires Winamp 2.9+) ** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU); ** values for data: ** 0 : main popup menu ** 1 : main menubar file menu ** 2 : main menubar options menu ** 3 : main menubar windows menu ** 4 : main menubar help menu ** other values will return NULL. */ #define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam #define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296 /* (requires Winamp 2.9+) ** to use, create an extendedFileInfoStruct, point the values filename and metadata to the ** filename and metadata field you wish to query, and ret to a buffer, with retlen to the ** length of that buffer, and then SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_GET_EXTENDED_FILE_INFO); ** the results should be in the buffer pointed to by ret. ** returns 1 if the decoder supports a getExtendedFileInfo method */ typedef struct { char *filename; char *metadata; char *ret; int retlen; } extendedFileInfoStruct; #define IPC_GET_BASIC_FILE_INFO 291 //pass a pointer to the following struct in wParam typedef struct { char *filename; int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used) // filled in by winamp int length; char *title; int titlelen; } basicFileInfoStruct; #define IPC_GET_EXTLIST 292 //returns doublenull delimited. GlobalFree() it when done. if data is 0, returns raw extlist, if 1, returns something suitable for getopenfilename #define IPC_INFOBOX 293 typedef struct { HWND parent; char *filename; } infoBoxParam; #define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam /* (requires Winamp 2.9+) ** to use, create an extendedFileInfoStruct, point the values filename and metadata to the ** filename and metadata field you wish to write in ret. (retlen is not used). and then ** SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO); ** returns 1 if the metadata is supported ** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update */ #define IPC_WRITE_EXTENDED_FILE_INFO 295 /* (requires Winamp 2.9+) ** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file ** returns 1 if the file has been successfully updated, 0 if error */ #define IPC_FORMAT_TITLE 297 typedef struct { char *spec; // NULL=default winamp spec void *p; char *out; int out_len; char * (*TAGFUNC)(char * tag, void * p); //return 0 if not found void (*TAGFREEFUNC)(char * tag,void * p); } waFormatTitle; #define IPC_GETUNCOMPRESSINTERFACE 331 /* returns a function pointer to uncompress(). ** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); ** right out of zlib, useful for decompressing zlibbed data. ** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API. */ typedef struct { int (*inflateReset)(void *strm); int (*inflateInit_)(void *strm,const char *version, int stream_size); int (*inflate)(void *strm, int flush); int (*inflateEnd)(void *strm); unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len); } wa_inflate_struct; #define IPC_ADD_PREFS_DLG 332 #define IPC_REMOVE_PREFS_DLG 333 /* (requires Winamp 2.9+) ** to use, allocate a prefsDlgRec structure (either on the heap or some global ** data, but NOT on the stack), initialze the members: ** hInst to the DLL instance where the resource is located ** dlgID to the ID of the dialog, ** proc to the window procedure for the dialog ** name to the name of the prefs page in the prefs. ** where to 0 (eventually we may add more options) ** then, SendMessage(hwnd_winamp,WM_WA_IPC,&prefsRec,IPC_ADD_PREFS_DLG); ** ** you can also IPC_REMOVE_PREFS_DLG with the address of the same prefsRec, ** but you shouldn't really ever have to. ** */ #define IPC_OPENPREFSTOPAGE 380 // pass an id of a builtin page, or a &prefsDlgRec of prefs page to open typedef struct _prefsDlgRec { HINSTANCE hInst; int dlgID; void *proc; char *name; int where; // 0 for options, 1 for plugins, 2 for skins, 3 for bookmarks, 4 for prefs int _id; struct _prefsDlgRec *next; } prefsDlgRec; #define IPC_GETINIFILE 334 // returns a pointer to winamp.ini #define IPC_GETINIDIRECTORY 335 // returns a pointer to the directory to put config files in (if you dont want to use winamp.ini) #define IPC_SPAWNBUTTONPOPUP 361 // param = // 0 = eject // 1 = previous // 2 = next // 3 = pause // 4 = play // 5 = stop #define IPC_OPENURLBOX 360 // pass a HWND to a parent, returns a HGLOBAL that needs to be freed with GlobalFree(), if successful #define IPC_OPENFILEBOX 362 // pass a HWND to a parent #define IPC_OPENDIRBOX 363 // pass a HWND to a parent // pass an HWND to a parent. call this if you take over the whole UI so that the dialogs are not appearing on the // bottom right of the screen since the main winamp window is at 3000x3000, call again with NULL to reset #define IPC_SETDIALOGBOXPARENT 364 // pass 0 for a copy of the skin HBITMAP // pass 1 for name of font to use for playlist editor likeness // pass 2 for font charset // pass 3 for font size #define IPC_GET_GENSKINBITMAP 503 #define IPC_GET_EMBEDIF 505 // pass an embedWindowState // returns an HWND embedWindow(embedWindowState *); if the data is NULL, otherwise returns the HWND directly typedef struct { HWND me; //hwnd of the window int flags; RECT r; void *user_ptr; // for application use int extra_data[64]; // for internal winamp use } embedWindowState; #define EMBED_FLAGS_NORESIZE 1 // set this bit in embedWindowState.flags to keep window from being resizable #define EMBED_FLAGS_NOTRANSPARENCY 2 // set this bit in embedWindowState.flags to make gen_ff turn transparency off for this wnd #define IPC_EMBED_ENUM 532 typedef struct embedEnumStruct { int (*enumProc)(embedWindowState *ws, struct embedEnumStruct *param); // return 1 to abort int user_data; // or more :) } embedEnumStruct; // pass #define IPC_EMBED_ISVALID 533 #define IPC_CONVERTFILE 506 /* (requires Winamp 2.92+) ** Converts a given file to a different format (PCM, MP3, etc...) ** To use, pass a pointer to a waFileConvertStruct struct ** This struct can be either on the heap or some global ** data, but NOT on the stack. At least, until the conversion is done. ** ** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE); ** ** Return value: ** 0: Can't start the conversion. Look at myConvertStruct->error for details. ** 1: Conversion started. Status messages will be sent to the specified callbackhwnd. ** Be sure to call IPC_CONVERTFILE_END when your callback window receives the ** IPC_CB_CONVERT_DONE message. */ typedef struct { char *sourcefile; // "c:\\source.mp3" char *destfile; // "c:\\dest.pcm" int destformat[8]; // like 'PCM ',srate,nch,bps HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages //filled in by winamp.exe char *error; //if IPC_CONVERTFILE returns 0, the reason will be here int bytes_done; //you can look at both of these values for speed statistics int bytes_total; int bytes_out; int killswitch; // don't set it manually, use IPC_CONVERTFILE_END int extra_data[64]; // for internal winamp use } convertFileStruct; #define IPC_CONVERTFILE_END 507 /* (requires Winamp 2.92+) ** Stop/ends a convert process started from IPC_CONVERTFILE ** You need to call this when you receive the IPC_CB_CONVERTDONE message or when you ** want to abort a conversion process ** ** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE_END); ** ** No return value */ typedef struct { HWND hwndParent; int format; //filled in by winamp.exe HWND hwndConfig; int extra_data[8]; } convertConfigStruct; #define IPC_CONVERT_CONFIG 508 #define IPC_CONVERT_CONFIG_END 509 typedef struct { void (*enumProc)(int user_data, const char *desc, int fourcc); int user_data; } converterEnumFmtStruct; #define IPC_CONVERT_CONFIG_ENUMFMTS 510 /* (requires Winamp 2.92+) */ typedef struct { char cdletter; char *playlist_file; HWND callback_hwnd; //filled in by winamp.exe char *error; } burnCDStruct; #define IPC_BURN_CD 511 /* (requires Winamp 5.0+) */ typedef struct { convertFileStruct *cfs; int priority; } convertSetPriority; #define IPC_CONVERT_SET_PRIORITY 512 typedef struct { char *filename; char *title; // 2048 bytes int length; int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit } waHookTitleStruct; // return TRUE if you hook this #define IPC_HOOK_TITLES 850 #define IPC_GETSADATAFUNC 800 // 0: returns a char *export_sa_get() that returns 150 bytes of data // 1: returns a export_sa_setreq(int want); #define IPC_ISMAINWNDVISIBLE 900 #define IPC_SETPLEDITCOLORS 920 typedef struct { int numElems; int *elems; HBITMAP bm; // set if you want to override } waSetPlColorsStruct; // the following IPC use waSpawnMenuParms as parameter #define IPC_SPAWNEQPRESETMENU 933 #define IPC_SPAWNFILEMENU 934 //menubar #define IPC_SPAWNOPTIONSMENU 935 //menubar #define IPC_SPAWNWINDOWSMENU 936 //menubar #define IPC_SPAWNHELPMENU 937 //menubar #define IPC_SPAWNPLAYMENU 938 //menubar #define IPC_SPAWNPEFILEMENU 939 //menubar #define IPC_SPAWNPEPLAYLISTMENU 940 //menubar #define IPC_SPAWNPESORTMENU 941 //menubar #define IPC_SPAWNPEHELPMENU 942 //menubar #define IPC_SPAWNMLFILEMENU 943 //menubar #define IPC_SPAWNMLVIEWMENU 944 //menubar #define IPC_SPAWNMLHELPMENU 945 //menubar #define IPC_SPAWNPELISTOFPLAYLISTS 946 typedef struct { HWND wnd; int xpos; // in screen coordinates int ypos; } waSpawnMenuParms; // waSpawnMenuParms2 is used by the menubar submenus typedef struct { HWND wnd; int xpos; // in screen coordinates int ypos; int width; int height; } waSpawnMenuParms2; // system tray sends this (you might want to simulate it) #define WM_WA_SYSTRAY WM_USER+1 // input plugins send this when they are done playing back #define WM_WA_MPEG_EOF WM_USER+2 //// video stuff #define IPC_IS_PLAYING_VIDEO 501 // returns >1 if playing, 0 if not, 1 if old version (so who knows):) #define IPC_GET_IVIDEOOUTPUT 500 // see below for IVideoOutput interface #define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24)) #define VIDUSER_SET_INFOSTRING 0x1000 #define VIDUSER_GET_VIDEOHWND 0x1001 #define VIDUSER_SET_VFLIP 0x1002 #ifndef NO_IVIDEO_DECLARE #ifdef __cplusplus class VideoOutput; class SubsItem; typedef struct { unsigned char* baseAddr; long rowBytes; } YV12_PLANE; typedef struct { YV12_PLANE y; YV12_PLANE u; YV12_PLANE v; } YV12_PLANES; class IVideoOutput { public: virtual ~IVideoOutput() { } virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0; virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { } virtual void close()=0; virtual void draw(void *frame)=0; virtual void drawSubtitle(SubsItem *item) { } virtual void showStatusMsg(const char *text) { } virtual int get_latency() { return 0; } virtual void notifyBufferState(int bufferstate) { } /* 0-255*/ virtual int extended(int param1, int param2, int param3) { return 0; } // Dispatchable, eat this! }; #endif //cplusplus #endif//NO_IVIDEO_DECLARE // these messages are callbacks that you can grab by subclassing the winamp window // wParam = #define IPC_CB_WND_EQ 0 // use one of these for the param #define IPC_CB_WND_PE 1 #define IPC_CB_WND_MB 2 #define IPC_CB_WND_VIDEO 3 #define IPC_CB_WND_MAIN 4 #define IPC_CB_ONSHOWWND 600 #define IPC_CB_ONHIDEWND 601 #define IPC_CB_GETTOOLTIP 602 #define IPC_CB_MISC 603 #define IPC_CB_MISC_TITLE 0 #define IPC_CB_MISC_VOLUME 1 // volume/pan #define IPC_CB_MISC_STATUS 2 #define IPC_CB_MISC_EQ 3 #define IPC_CB_MISC_INFO 4 #define IPC_CB_MISC_VIDEOINFO 5 #define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent) #define IPC_CB_CONVERT_DONE 605 #define IPC_ADJUST_FFWINDOWSMENUPOS 606 /* (requires Winamp 2.9+) ** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS); ** moves where winamp expects the freeform windows in the menubar windows main menu. Useful if you wish to insert a ** menu item above extra freeform windows. */ #define IPC_ISDOUBLESIZE 608 #define IPC_ADJUST_FFOPTIONSMENUPOS 609 /* (requires Winamp 2.9+) ** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS); ** moves where winamp expects the freeform preferences item in the menubar windows main menu. Useful if you wish to insert a ** menu item above preferences item. */ #define IPC_GETTIMEDISPLAYMODE 610 // returns 0 if displaying elapsed time or 1 if displaying remaining time #define IPC_SETVISWND 611 // param is hwnd, setting this allows you to receive ID_VIS_NEXT/PREVOUS/RANDOM/FS wm_commands #define ID_VIS_NEXT 40382 #define ID_VIS_PREV 40383 #define ID_VIS_RANDOM 40384 #define ID_VIS_FS 40389 #define ID_VIS_CFG 40390 #define ID_VIS_MENU 40391 #define IPC_GETVISWND 612 // returns the vis cmd handler hwnd #define IPC_ISVISRUNNING 613 #define IPC_CB_VISRANDOM 628 // param is status of random #define IPC_SETIDEALVIDEOSIZE 614 // sent by winamp to winamp, trap it if you need it. width=HIWORD(param), height=LOWORD(param) #define IPC_GETSTOPONVIDEOCLOSE 615 #define IPC_SETSTOPONVIDEOCLOSE 616 typedef struct { HWND hwnd; int uMsg; int wParam; int lParam; } transAccelStruct; #define IPC_TRANSLATEACCELERATOR 617 typedef struct { int cmd; int x; int y; int align; } windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD #define IPC_CB_ONTOGGLEAOT 618 #define IPC_GETPREFSWND 619 #define IPC_SET_PE_WIDTHHEIGHT 620 // data is a pointer to a POINT structure that holds width & height #define IPC_GETLANGUAGEPACKINSTANCE 621 #define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02" #define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config #define IPC_GETOUTPUTPLUGIN 625 #define IPC_SETDRAWBORDERS 626 #define IPC_DISABLESKINCURSORS 627 #define IPC_CB_RESETFONT 629 #define IPC_IS_FULLSCREEN 630 // returns 1 if video or vis is in fullscreen mode #define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode #define IPC_SHOW_NOTIFICATION 632 #define IPC_GETSKININFO 633 // >>>>>>>>>>> Next is 634 #define IPC_PLCMD 1000 #define PLCMD_ADD 0 #define PLCMD_REM 1 #define PLCMD_SEL 2 #define PLCMD_MISC 3 #define PLCMD_LIST 4 #define IPC_MBCMD 1001 #define MBCMD_BACK 0 #define MBCMD_FORWARD 1 #define MBCMD_STOP 2 #define MBCMD_RELOAD 3 #define MBCMD_MISC 4 #define IPC_VIDCMD 1002 #define VIDCMD_FULLSCREEN 0 #define VIDCMD_1X 1 #define VIDCMD_2X 2 #define VIDCMD_LIB 3 #define VIDPOPUP_MISC 4 #define IPC_MBURL 1003 //sets the URL #define IPC_MBGETCURURL 1004 //copies the current URL into wParam (have a 4096 buffer ready) #define IPC_MBGETDESC 1005 //copies the current URL description into wParam (have a 4096 buffer ready) #define IPC_MBCHECKLOCFILE 1006 //checks that the link file is up to date (otherwise updates it). wParam=parent HWND #define IPC_MBREFRESH 1007 //refreshes the "now playing" view in the library #define IPC_MBGETDEFURL 1008 //copies the default URL into wParam (have a 4096 buffer ready) #define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status // IPC 2000-3000 reserved for freeform messages, see gen_ff/ff_ipc.h #define IPC_FF_FIRST 2000 #define IPC_FF_LAST 3000 #define IPC_GETDROPTARGET 3001 #define IPC_PLAYLIST_MODIFIED 3002 // sent to main wnd whenever the playlist is modified #define IPC_PLAYING_FILE 3003 // sent to main wnd with the file as parm whenever a file is played #define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 // sent to main wnd with the file as parm whenever a file tag might be updated #define IPC_ALLOW_PLAYTRACKING 3007 // send nonzero to allow, zero to disallow #define IPC_HOOK_OKTOQUIT 3010 // return 0 to abort a quit, nonzero if quit is OK #define IPC_WRITECONFIG 3011 // pass 2 to write all, 1 to write playlist + common, 0 to write common+less common // pass a string to be the name to register, and returns a value > 65536, which is a unique value you can use // for custom WM_WA_IPC messages. #define IPC_REGISTER_WINAMP_IPCMESSAGE 65536 /**************************************************************************/ /* ** Finally there are some WM_COMMAND messages that you can use to send ** Winamp misc commands. ** ** To send these, use: ** ** SendMessage(hwnd_winamp, WM_COMMAND,command_name,0); */ #define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window #define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window #define WINAMP_VOLUMEUP 40058 // turns the volume up a little #define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little #define WINAMP_FFWD5S 40060 // fast forwards 5 seconds #define WINAMP_REW5S 40061 // rewinds 5 seconds // the following are the five main control buttons, with optionally shift // or control pressed // (for the exact functions of each, just try it out) #define WINAMP_BUTTON1 40044 #define WINAMP_BUTTON2 40045 #define WINAMP_BUTTON3 40046 #define WINAMP_BUTTON4 40047 #define WINAMP_BUTTON5 40048 #define WINAMP_BUTTON1_SHIFT 40144 #define WINAMP_BUTTON2_SHIFT 40145 #define WINAMP_BUTTON3_SHIFT 40146 #define WINAMP_BUTTON4_SHIFT 40147 #define WINAMP_BUTTON5_SHIFT 40148 #define WINAMP_BUTTON1_CTRL 40154 #define WINAMP_BUTTON2_CTRL 40155 #define WINAMP_BUTTON3_CTRL 40156 #define WINAMP_BUTTON4_CTRL 40157 #define WINAMP_BUTTON5_CTRL 40158 #define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box #define WINAMP_FILE_DIR 40187 // pops up the load directory box #define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences #define WINAMP_OPTIONS_AOT 40019 // toggles always on top #define WINAMP_HELP_ABOUT 40041 // pops up the about box :) #define ID_MAIN_PLAY_AUDIOCD1 40323 // starts playing the audio CD in the first CD reader #define ID_MAIN_PLAY_AUDIOCD2 40323 // plays the 2nd #define ID_MAIN_PLAY_AUDIOCD3 40323 // plays the 3nd #define ID_MAIN_PLAY_AUDIOCD4 40323 // plays the 4nd // IDs 42000 to 45000 are reserved for gen_ff // IDs from 45000 to 57000 are reserved for library #endif//_WA_IPC_H_ /* ** EOF.. Enjoy. */ psi-0.14/src/tools/tunecontroller/plugins/winamp/winampcontroller.cpp0000644000175000017500000001144611305557613024434 0ustar janjan/* * winampcontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #ifdef Q_CC_MSVC #pragma warning(push) #pragma warning(disable: 4100) #endif // this file generates eight C4100 warnings, when compiled with MSVC2003 #include "third-party/wa_ipc.h" #ifdef Q_CC_MSVC #pragma warning(pop) #endif #include "winampcontroller.h" /** * \class WinAmpController * \brief A controller for WinAmp. */ /** * \brief Constructs the controller. */ WinAmpController::WinAmpController() : TuneController() { connect(&timer_, SIGNAL(timeout()), SLOT(check())); norminterval_ = 3000; antiscrollinterval_ = 100; antiscrollcounter_ = 0; timer_.start(norminterval_); } template const size_t length (const char_type * begin) { const char_type * end = begin; for (; *end; ++end); return end - begin; } // Returns a title of a track currently being played by WinAmp with given HWND (passed in waWnd) QPair WinAmpController::getTrackTitle(HWND waWnd) { TCHAR waTitle[2048]; QString title; // Get WinAmp window title. It always contains name of the track SendMessage (waWnd, WM_GETTEXT, static_cast (sizeof (waTitle) / sizeof (waTitle[0])), reinterpret_cast (waTitle)); // Now, waTitle contains WinAmp window title title = QString ((const QChar *) waTitle, length ((const TCHAR *) waTitle)); if (title[0] == '*' || (title.length () && title[title.length() - 1] == '*')) { // request to be called again soon. return QPair(false, QString()); } // Check whether there is a need to do the all stuff if (!title.length()) { return QPair(true,title); } QString winamp (" - Winamp ***"); int winampLength = winamp.length(); // Is title scrolling on the taskbar enabled? title += title + title; int waLast = title.indexOf (winamp, -1); if (waLast != -1) { if (title.length()) { title.remove (waLast, title.length () - waLast); } int waFirst; while ((waFirst = title.indexOf (winamp)) != -1) { title.remove (0, waFirst + winampLength); } } else { title = QString ((const QChar *) waTitle, length ((const TCHAR *) waTitle)); // Title is not scrolling } // Remove leading and trailing spaces title = title.trimmed(); // Remove trailing " - Winamp" from title if (title.length ()) { winamp = " - Winamp"; winampLength = winamp.length (); int waFirst = title.indexOf (winamp); if (waFirst != -1) { title.remove (waFirst, waFirst + winampLength); } } // Remove track number from title if (title.length ()) { QString dot(". "); int dotFirst = title.indexOf (dot); if (dotFirst != -1) { // All symbols before the dot are digits? bool allDigits = true; for (int pos = dotFirst; pos > 0; --pos) { allDigits = allDigits && title[pos].isNumber(); } if (allDigits) { title.remove(0, dotFirst + dot.length ()); } } } // Remove leading and trailing spaces if (title.length ()) { while (title.length () && title[0] == ' ') { title.remove (0, 1); } while (title.length () && title[title.length () - 1] == ' ') { title.remove (title.length () - 1, 1); } } return QPair(true,title); } /** * Polls for new song info. */ void WinAmpController::check() { Tune tune; #ifdef UNICODE HWND h = FindWindow(L"Winamp v1.x", NULL); #else HWND h = FindWindow("Winamp v1.x", NULL); #endif if (h && SendMessage(h,WM_WA_IPC,0,IPC_ISPLAYING) == 1) { QPair trackpair(getTrackTitle(h)); if (!trackpair.first) { // getTrackTitle wants us to retry in a few ms... int interval = antiscrollinterval_; if (++antiscrollcounter_ > 10) { antiscrollcounter_ = 0; interval = norminterval_; } timer_.start(interval); return; } antiscrollcounter_ = 0; tune.setName(trackpair.second); tune.setTime(SendMessage(h,WM_WA_IPC,1,IPC_GETOUTPUTTIME)); } if (prev_tune_ != tune) { prev_tune_ = tune; if (tune.isNull()) { emit stopped(); } else { emit playing(tune); } } timer_.start(norminterval_); } Tune WinAmpController::currentTune() { return prev_tune_; } psi-0.14/src/tools/tunecontroller/plugins/winamp/winampcontroller.h0000644000175000017500000000240411305557613024073 0ustar janjan/* * winampcontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef WINAMPCONTROLLER_H #define WINAMPCONTROLLER_H #include "tunecontrollerinterface.h" #include "pollingtunecontroller.h" #include #include class WinAmpController : public TuneController { Q_OBJECT public: WinAmpController(); virtual Tune currentTune(); protected: QPair getTrackTitle(HWND waWnd); protected slots: void check(); private: Tune prev_tune_; QTimer timer_; int norminterval_, antiscrollinterval_; int antiscrollcounter_; }; #endif psi-0.14/src/tools/tunecontroller/plugins/itunes/0000755000175000017500000000000011305557613020337 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/itunes/itunescontroller.h0000644000175000017500000000066111305557613024126 0ustar janjan#ifndef ITUNESCONTROLLER_H #define ITUNESCONTROLLER_H #include #include #include "tunecontrollerinterface.h" class ITunesController : public TuneController { public: ITunesController(); ~ITunesController(); virtual Tune currentTune(); private: static void iTunesCallback(CFNotificationCenterRef,void*,CFStringRef,const void*, CFDictionaryRef info); Tune currentTune_; }; #endif psi-0.14/src/tools/tunecontroller/plugins/itunes/itunesplugin.cpp0000644000175000017500000000253411305557613023575 0ustar janjan/* * itunesplugin.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef QT_STATICPLUGIN #define QT_STATICPLUGIN #endif #include #include #include #include "itunescontroller.h" #include "tunecontrollerplugin.h" class ITunesPlugin : public QObject, public TuneControllerPlugin { Q_OBJECT Q_INTERFACES(TuneControllerPlugin) public: virtual QString name(); virtual TuneController* createController(); }; Q_EXPORT_PLUGIN2(itunesplugin, ITunesPlugin); QString ITunesPlugin::name() { return "iTunes"; } TuneController* ITunesPlugin::createController() { return new ITunesController(); } #include "itunesplugin.moc" psi-0.14/src/tools/tunecontroller/plugins/itunes/itunescontroller.cpp0000644000175000017500000000745311305557613024467 0ustar janjan/* * itunescontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include "itunescontroller.h" /** * \class ITunesController * \brief A controller for the Mac OS X version of iTunes. */ static QString CFStringToQString(CFStringRef s) { QString result; if (s != NULL) { CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s), kCFStringEncodingUTF8) + 1; char* buffer = new char[length]; if (CFStringGetCString(s, buffer, length, kCFStringEncodingUTF8)) { result = QString::fromUtf8(buffer); } else { qWarning("itunesplayer.cpp: CFString conversion failed."); } delete[] buffer; } return result; } ITunesController::ITunesController() { // TODO: Poll iTunes for current playing tune CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterAddObserver(center, this, ITunesController::iTunesCallback, CFSTR("com.apple.iTunes.playerInfo"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); } ITunesController::~ITunesController() { CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterRemoveObserver(center, this, CFSTR("com.apple.iTunes.playerInfo"), NULL); } Tune ITunesController::currentTune() { return currentTune_; } void ITunesController::iTunesCallback(CFNotificationCenterRef,void* observer,CFStringRef,const void*, CFDictionaryRef info) { Tune tune; ITunesController* controller = (ITunesController*) observer; CFStringRef cf_state = (CFStringRef) CFDictionaryGetValue(info, CFSTR("Player State")); if (CFStringCompare(cf_state,CFSTR("Paused"),0) == kCFCompareEqualTo) { //qDebug() << "itunesplayer.cpp: Paused"; emit controller->stopped(); } else if (CFStringCompare(cf_state,CFSTR("Stopped"),0) == kCFCompareEqualTo) { //qDebug() << "itunesplayer.cpp: Stopped"; emit controller->stopped(); } else if (CFStringCompare(cf_state,CFSTR("Playing"),0) == kCFCompareEqualTo) { //qDebug() << "itunesplayer.cpp: Playing"; tune.setArtist(CFStringToQString((CFStringRef) CFDictionaryGetValue(info, CFSTR("Artist")))); tune.setName(CFStringToQString((CFStringRef) CFDictionaryGetValue(info, CFSTR("Name")))); tune.setAlbum(CFStringToQString((CFStringRef) CFDictionaryGetValue(info, CFSTR("Album")))); CFNumberRef cf_track = (CFNumberRef) CFDictionaryGetValue(info, CFSTR("Track Number")); if (cf_track) { int tracknr; if (!CFNumberGetValue(cf_track,kCFNumberIntType,&tracknr)) { qWarning("itunesplayer.cpp: Number value conversion failed."); } tune.setTrack(QString::number(tracknr)); } CFNumberRef cf_time = (CFNumberRef) CFDictionaryGetValue(info, CFSTR("Total Time")); int time = 0; if (cf_time && !CFNumberGetValue(cf_time,kCFNumberIntType,&time)) { qWarning("itunesplayer.cpp: Number value conversion failed."); } tune.setTime((unsigned int) (time / 1000)); controller->currentTune_ = tune; emit controller->playing(tune); } else { qWarning("itunesplayer.cpp: Unknown state."); } } psi-0.14/src/tools/tunecontroller/plugins/psifile/0000755000175000017500000000000011305557613020463 5ustar janjanpsi-0.14/src/tools/tunecontroller/plugins/psifile/psifileplugin.h0000644000175000017500000000241111305557613023504 0ustar janjan/* * psifileplugin.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIFILEPLUGIN_H #define PSIFILEPLUGIN_H #ifndef QT_STATICPLUGIN #define QT_STATICPLUGIN #endif #include #include #include #include "tunecontrollerplugin.h" #include "psifilecontroller.h" /** * \brief A TuneController plugin for the Psi file controller. */ class PsiFilePlugin : public QObject, public TuneControllerPlugin { Q_OBJECT Q_INTERFACES(TuneControllerPlugin) public: virtual QString name(); virtual TuneController* createController(); }; #endif psi-0.14/src/tools/tunecontroller/plugins/psifile/psifilecontroller.h0000644000175000017500000000176111305557613024400 0ustar janjan/* * psifilecontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIFILECONTROLLER_H #define PSIFILECONTROLLER_H #include "tunecontrollerinterface.h" #include "filetunecontroller.h" class PsiFileController : public FileTuneController { public: PsiFileController(); }; #endif psi-0.14/src/tools/tunecontroller/plugins/psifile/psifilecontroller.cpp0000644000175000017500000000214511305557613024730 0ustar janjan/* * psifilecontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psifilecontroller.h" #include "applicationinfo.h" /** * \class PsiFileController * \brief A controller which checks 'tune' in the Psi config dir. */ /** * \brief Constructs the controller. */ PsiFileController::PsiFileController() : FileTuneController(ApplicationInfo::homeDir() + "/tune") { setInterval(10000); } psi-0.14/src/tools/tunecontroller/plugins/psifile/psifileplugin.cpp0000644000175000017500000000175611305557613024052 0ustar janjan/* * psifileplugin.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psifileplugin.h" QString PsiFilePlugin::name() { return "Psi File"; } TuneController* PsiFilePlugin::createController() { return new PsiFileController(); } Q_EXPORT_PLUGIN2(psifileplugin, PsiFilePlugin); psi-0.14/src/tools/tunecontroller/tunecontrollermanager.h0000644000175000017500000000254411305557613022137 0ustar janjan/* * turencontrollermanager.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TUNECONTROLLERMANAGER_H #define TUNECONTROLLERMANAGER_H #include #include #include class TuneControllerPlugin; class TuneController; class TuneControllerManager : public QObject { public: static TuneControllerManager* instance(); QList controllerNames() const; TuneController* createController(const QString&) const; bool loadPlugin(const QString&); protected: bool loadPlugin(QObject* plugin); private: TuneControllerManager(); static TuneControllerManager* instance_; QMap plugins_; }; #endif psi-0.14/src/tools/tunecontroller/filetunecontroller.cpp0000644000175000017500000000403211305557613021771 0ustar janjan/* * filetunecontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "tune.h" #include "filetunecontroller.h" #define CHECK_INTERVAL 5000 /** * \class FileTuneController * \brief A player-independent class for controlling any player through files. * This class reads the current playing song from a file, and notifies if * the song changed. Therefore, this class can be used if specific support for * a certain player isn't implemented yet. * * A song file has to contain one line per record, with the records in the * following order: track name, track artist, track album, track number, track * time. */ /** * \brief Constructs the controller. * \param songFile the filename from which the currently playing song is * read. */ FileTuneController::FileTuneController(const QString& songFile) : PollingTuneController(), songFile_(songFile) { } Tune FileTuneController::currentTune() { Tune tune; QFile file(songFile_); if (file.open(QIODevice::ReadOnly)) { QTextStream stream( &file ); stream.setCodec("UTF-8"); stream.setAutoDetectUnicode(true); tune.setName(stream.readLine()); tune.setArtist(stream.readLine()); tune.setAlbum(stream.readLine()); tune.setTrack(stream.readLine()); tune.setTime(stream.readLine().toUInt()); } return tune; } psi-0.14/src/tools/tunecontroller/tunecontrollerplugin.h0000644000175000017500000000247611305557613022027 0ustar janjan/* * turencontrollerplugin.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TUNECONTROLLERPLUGIN_H #define TUNECONTROLLERPLUGIN_H #include #include class TuneController; /** * \brief Base class for TuneController plugins. */ class TuneControllerPlugin { public: virtual ~TuneControllerPlugin() { } /** * \brief Returns the name of the tune controller. */ virtual QString name() = 0; /** * \brief Creates a new controller. */ virtual TuneController* createController() = 0; }; Q_DECLARE_INTERFACE(TuneControllerPlugin, "be.el-tramo.TuneController/0.0-20060129"); #endif psi-0.14/src/tools/tunecontroller/pollingtunecontroller.h0000644000175000017500000000216611305557613022171 0ustar janjan/* * pollingtunecontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef POLLINGTUNECONTROLLER_H #define POLLINGTUNECONTROLLER_H #include #include "tune.h" #include "tunecontroller.h" class PollingTuneController : public TuneController { Q_OBJECT public: PollingTuneController(); void setInterval(int interval); protected slots: void check(); private: Tune prev_tune_; QTimer timer_; }; #endif psi-0.14/src/tools/tunecontroller/src.pro0000644000175000017500000000041111305557613016654 0ustar janjanTEMPLATE = lib TARGET = tunecontroller DESTDIR = ../lib VERSION = 1 QT -= gui CONFIG += dll MOC_DIR = .moc OBJECTS_DIR = .obj unix { include(../conf.pri) } mac { CONFIG += tc_itunes } TUNECONTROLLER_PATH = . include($$TUNECONTROLLER_PATH/tunecontroller.pri) psi-0.14/src/tools/tunecontroller/combinedtunecontroller.cpp0000644000175000017500000000316711305557613022642 0ustar janjan/* * combinedtunecontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "tune.h" #include "combinedtunecontroller.h" #include "tunecontrollermanager.h" /** * \class CombinedTuneController * \brief Combines all supported controllers into one controller. */ CombinedTuneController::CombinedTuneController() { foreach(QString name, TuneControllerManager::instance()->controllerNames()) { TuneController* c = TuneControllerManager::instance()->createController(name); connect(c,SIGNAL(stopped()),SIGNAL(stopped())); connect(c,SIGNAL(playing(const Tune&)),SIGNAL(playing(const Tune&))); controllers_ += c; } } CombinedTuneController::~CombinedTuneController() { while (!controllers_.isEmpty()) { delete controllers_.takeFirst(); } } Tune CombinedTuneController::currentTune() { foreach(TuneController* c, controllers_) { Tune t = c->currentTune(); if (!t.isNull()) return t; } return Tune(); } psi-0.14/src/tools/tunecontroller/tunecontroller.pri0000644000175000017500000000332411305557613021144 0ustar janjanINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += \ $$PWD/tune.h \ $$PWD/tunecontroller.h \ $$PWD/pollingtunecontroller.h \ $$PWD/filetunecontroller.h \ $$PWD/combinedtunecontroller.h \ $$PWD/tunecontrollerplugin.h \ $$PWD/tunecontrollermanager.h \ $$PWD/tunecontrollerinterface.h SOURCES += \ $$PWD/pollingtunecontroller.cpp \ $$PWD/filetunecontroller.cpp \ $$PWD/combinedtunecontroller.cpp \ $$PWD/tunecontrollermanager.cpp # XMMS tc_xmms { DEFINES += TC_XMMS XMMS_PLUGIN_PATH = $$PWD/plugins/xmms INCLUDEPATH += $$XMMS_PLUGIN_PATH HEADERS += \ $$XMMS_PLUGIN_PATH/xmmscontroller.h SOURCES += \ $$XMMS_PLUGIN_PATH/xmmscontroller.cpp \ $$XMMS_PLUGIN_PATH/xmmsplugin.cpp } # iTunes tc_itunes { mac { DEFINES += TC_ITUNES ITUNES_PLUGIN_PATH = $$PWD/plugins/itunes INCLUDEPATH += $$ITUNES_PLUGIN_PATH HEADERS += \ $$ITUNES_PLUGIN_PATH/itunescontroller.h SOURCES += \ $$ITUNES_PLUGIN_PATH/itunescontroller.cpp \ $$ITUNES_PLUGIN_PATH/itunesplugin.cpp QMAKE_LFLAGS += -framework CoreFoundation } } # WinAmp tc_winamp { DEFINES += TC_WINAMP WINAMP_PLUGIN_PATH = $$PWD/plugins/winamp INCLUDEPATH += $$WINAMP_PLUGIN_PATH HEADERS += \ $$WINAMP_PLUGIN_PATH/winampcontroller.h \ $$WINAMP_PLUGIN_PATH/winampplugin.h SOURCES += \ $$WINAMP_PLUGIN_PATH/winampcontroller.cpp \ $$WINAMP_PLUGIN_PATH/winampplugin.cpp LIBS += -lUser32 } # Psi File tc_psifile { DEFINES += TC_PSIFILE PSIFILE_PLUGIN_PATH = $$PWD/plugins/psifile INCLUDEPATH += $$PSIFILE_PLUGIN_PATH HEADERS += \ $$PSIFILE_PLUGIN_PATH/psifilecontroller.h \ $$PSIFILE_PLUGIN_PATH/psifileplugin.h SOURCES += \ $$PSIFILE_PLUGIN_PATH/psifilecontroller.cpp \ $$PSIFILE_PLUGIN_PATH/psifileplugin.cpp } psi-0.14/src/tools/tunecontroller/tunecontroller.h0000644000175000017500000000244611305557613020605 0ustar janjan/* * tunecontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TUNECONTROLLER_H #define TUNECONTROLLER_H #include #include #include "tune.h" /** * \brief Base class for representing a media player. */ class TuneController : public QObject { Q_OBJECT public: virtual Tune currentTune() = 0; signals: /** * This signal is emitted when the media player started playing a tune. * \param tune the playing tune */ void playing(const Tune& tune); /** * This signal is emitted when the media player stopped playing tunes. */ void stopped(); }; #endif psi-0.14/src/tools/tunecontroller/tune.h0000644000175000017500000000442511305557613016500 0ustar janjan/* * tune.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TUNE_H #define TUNE_H #include /** * \brief A class represinting a tune. */ class Tune { public: /** * \brief Constructs an empty tune */ Tune() : time_(0) { } const QString& name() const { return name_; } const QString& artist() const { return artist_; } const QString& album() const { return album_; } const QString& track() const { return track_; } unsigned int time() const { return time_; } /** * \brief Returns a string representation of the tune's playing time. */ QString timeString() const { return QString("%1:%2").arg(time_ / 60).arg(time_ % 60, 2, 10, QChar('0')); } /** * \brief Checks whether this is a null tune. */ bool isNull() const { return name_.isEmpty() && artist_.isEmpty() && album_.isEmpty() && track_.isEmpty() && time_ == 0; } /** * \brief Compares this tune with another tune for equality. */ bool operator==(const Tune& t) const { return name_ == t.name_ && artist_ == t.artist_ && album_ == t.album_ && track_ == t.track_ && time_ == t.time_; } /** * \brief Compares this tune with another tune for inequality. */ bool operator!=(const Tune& t) const { return !((*this) == t); } void setName(const QString& name) { name_ = name; } void setArtist(const QString& artist) { artist_ = artist; } void setAlbum(const QString& album) { album_ = album; } void setTrack(const QString& track) { track_ = track; } void setTime(unsigned int time) { time_ = time; } private: QString name_, artist_, album_, track_; unsigned int time_; }; #endif psi-0.14/src/tools/tunecontroller/pollingtunecontroller.cpp0000644000175000017500000000331311305557613022517 0ustar janjan/* * pollingtunecontroller.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "tune.h" #include "pollingtunecontroller.h" /** * \class PollingTuneController * \brief A base class for a controller that uses polling to retrieve the currently playing song. * * An implementing class only has to implement currentTune(), and the correct * signals will be emitted. */ /** * \brief Constructs the controller. */ PollingTuneController::PollingTuneController() { connect(&timer_, SIGNAL(timeout()), SLOT(check())); timer_.start(3000); } /** * \brief Sets the polling interval. If interval is 0, no polling is * done. */ void PollingTuneController::setInterval(int interval) { if (interval > 0) timer_.start(interval); else timer_.stop(); } /** * Polls for new song info. */ void PollingTuneController::check() { Tune tune = currentTune(); if (prev_tune_ != tune) { prev_tune_ = tune; if (tune.isNull()) { emit stopped(); } else { emit playing(tune); } } } psi-0.14/src/tools/tunecontroller/filetunecontroller.h0000644000175000017500000000211711305557613021440 0ustar janjan/* * filetunecontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef FILEPLAYERCONTROLLER_H #define FILEPLAYERCONTROLLER_H #include #include "tune.h" #include "pollingtunecontroller.h" class FileTuneController : public PollingTuneController { public: FileTuneController(const QString& file); virtual Tune currentTune(); private: QString songFile_; }; #endif psi-0.14/src/tools/tunecontroller/tunecontrollermanager.cpp0000644000175000017500000000533611305557613022474 0ustar janjan/* * turencontrollermanager.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef QT_STATICPLUGIN #define QT_STATICPLUGIN #endif #include #include #include #include #include "tunecontrollermanager.h" #include "tunecontrollerplugin.h" /** * \class TuneControllerManager * \brief A manager for all tune controller plugins. */ TuneControllerManager::TuneControllerManager() : QObject(QCoreApplication::instance()) { foreach(QObject* plugin,QPluginLoader::staticInstances()) { loadPlugin(plugin); } } /** * \brief Returns a list of all the supported controllers. */ QList TuneControllerManager::controllerNames() const { return plugins_.keys(); } /** * \brief Creates a new controller. */ TuneController* TuneControllerManager::createController(const QString& name) const { return plugins_[name]->createController(); } /** * \brief Loads a TuneControllerPlugin from a file. */ bool TuneControllerManager::loadPlugin(const QString& file) { //return QPluginLoader(file).load(); return loadPlugin(QPluginLoader(file).instance()); } bool TuneControllerManager::loadPlugin(QObject* plugin) { if (!plugin) return false; TuneControllerPlugin* tcplugin = qobject_cast(plugin); if (tcplugin) { if(!plugins_.contains(tcplugin->name())) { //qDebug() << "Registering plugin " << tcplugin->name(); plugins_[tcplugin->name()] = tcplugin; } return true; } return false; } /** * \brief Retrieves the global plugin manager. */ TuneControllerManager* TuneControllerManager::instance() { if (!instance_) instance_ = new TuneControllerManager(); return instance_; } TuneControllerManager* TuneControllerManager::instance_ = 0; // ---------------------------------------------------------------------------- #ifdef TC_ITUNES Q_IMPORT_PLUGIN(itunesplugin) #endif #ifdef TC_XMMS Q_IMPORT_PLUGIN(xmmsplugin); #endif #ifdef TC_WINAMP Q_IMPORT_PLUGIN(winampplugin); #endif #ifdef TC_PSIFILE Q_IMPORT_PLUGIN(psifileplugin); #endif psi-0.14/src/tools/tunecontroller/tunecontrollerinterface.h0000644000175000017500000000174511305557613022467 0ustar janjan/* * turencontrollerinterface.h: The file to load from plugin implementations * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TUNECONTROLLERINTERFACE_H #define TUNECONTROLLERINTERFACE_H #include "tune.h" #include "tunecontroller.h" #include "tunecontrollerplugin.h" #endif psi-0.14/src/tools/tunecontroller/combinedtunecontroller.h0000644000175000017500000000215411305557613022302 0ustar janjan/* * combinedtunecontroller.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef COMBINEDTUNECONTROLLER_H #define COMBINEDTUNECONTROLLER_H #include #include "tune.h" #include "tunecontroller.h" class CombinedTuneController : public TuneController { public: CombinedTuneController(); ~CombinedTuneController(); virtual Tune currentTune(); private: QList controllers_; }; #endif psi-0.14/src/tools/advwidget/0000755000175000017500000000000011305557613014246 5ustar janjanpsi-0.14/src/tools/advwidget/advwidget.pri0000644000175000017500000000014611305557613016741 0ustar janjanHEADERS += $$PWD/advwidget.h SOURCES += $$PWD/advwidget.cpp INCLUDEPATH += $$PWD DEPENDPATH += $$PWD psi-0.14/src/tools/advwidget/advwidget.h0000644000175000017500000000701711305557613016402 0ustar janjan/* * advwidget.h - AdvancedWidget template class * Copyright (C) 2005-2007 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ADVWIDGET_H #define ADVWIDGET_H #include class GAdvancedWidget : public QObject { Q_OBJECT public: GAdvancedWidget(QWidget *parent); static bool stickEnabled(); static void setStickEnabled(bool val); static int stickAt(); static void setStickAt(int val); static bool stickToWindows(); static void setStickToWindows(bool val); QString geometryOptionPath() const; void setGeometryOptionPath(const QString& optionPath); void showWithoutActivation(); bool flashing() const; void doFlash(bool on); #ifdef Q_OS_WIN bool winEvent(MSG* msg, long* result); #endif void moveEvent(QMoveEvent *e); void changeEvent(QEvent *event); public: class Private; private: Private *d; }; template class AdvancedWidget : public BaseClass { private: GAdvancedWidget *gAdvWidget; public: AdvancedWidget(QWidget *parent = 0, Qt::WindowFlags f = 0) : BaseClass(parent) , gAdvWidget(0) { if (f != 0) BaseClass::setWindowFlags(f); gAdvWidget = new GAdvancedWidget( this ); } void setWindowIcon(const QIcon& icon) { #ifdef Q_WS_MAC Q_UNUSED(icon); #else BaseClass::setWindowIcon(icon); #endif } static bool stickEnabled() { return GAdvancedWidget::stickEnabled(); } static void setStickEnabled( bool val ) { GAdvancedWidget::setStickEnabled( val ); } static int stickAt() { return GAdvancedWidget::stickAt(); } static void setStickAt( int val ) { GAdvancedWidget::setStickAt( val ); } static bool stickToWindows() { return GAdvancedWidget::stickToWindows(); } static void setStickToWindows( bool val ) { GAdvancedWidget::setStickToWindows( val ); } QString geometryOptionPath() const { if (gAdvWidget) return gAdvWidget->geometryOptionPath(); return QString(); } void setGeometryOptionPath(const QString& optionPath) { if (gAdvWidget) gAdvWidget->setGeometryOptionPath(optionPath); } bool flashing() const { if (gAdvWidget) return gAdvWidget->flashing(); return false; } void showWithoutActivation() { if (gAdvWidget) gAdvWidget->showWithoutActivation(); } virtual void doFlash( bool on ) { if (gAdvWidget) gAdvWidget->doFlash( on ); } #ifdef Q_OS_WIN bool winEvent(MSG* msg, long* result) { if (gAdvWidget) return gAdvWidget->winEvent(msg, result); return BaseClass::winEvent(msg, result); } #endif void moveEvent( QMoveEvent *e ) { if (gAdvWidget) gAdvWidget->moveEvent(e); } void setWindowTitle( const QString &c ) { BaseClass::setWindowTitle( c ); windowTitleChanged(); } protected: virtual void windowTitleChanged() { doFlash(flashing()); } protected: void changeEvent(QEvent *event) { if (gAdvWidget) { gAdvWidget->changeEvent(event); } BaseClass::changeEvent(event); } }; #endif psi-0.14/src/tools/advwidget/advwidget.cpp0000644000175000017500000004113011305557613016727 0ustar janjan/* * advwidget.cpp - AdvancedWidget template class * Copyright (C) 2005-2007 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #ifdef Q_OS_WIN #if __GNUC__ >= 3 # define WINVER 0x0500 #endif #include #include #endif #include "advwidget.h" #include #include #include #include #include #include "psioptions.h" #ifdef Q_WS_X11 #include #include #include #endif // TODO: Make use of KDE taskbar flashing support //---------------------------------------------------------------------------- // AdvancedWidgetShared //---------------------------------------------------------------------------- class AdvancedWidgetShared : public QObject { Q_OBJECT public: AdvancedWidgetShared(); ~AdvancedWidgetShared(); }; AdvancedWidgetShared::AdvancedWidgetShared() : QObject(qApp) { } AdvancedWidgetShared::~AdvancedWidgetShared() { } static AdvancedWidgetShared *advancedWidgetShared = 0; //---------------------------------------------------------------------------- // GAdvancedWidget::Private //---------------------------------------------------------------------------- class GAdvancedWidget::Private : public QObject { Q_OBJECT public: Private(QWidget *parent); static int stickAt; static bool stickToWindows; static bool stickEnabled; QWidget* parentWidget_; bool flashing_; QString geometryOptionPath_; bool flashing() const; void doFlash(bool on); void posChanging(int *x, int *y, int *width, int *height); void moveEvent(QMoveEvent *e); protected: // reimplemented bool eventFilter(QObject* obj, QEvent* e); private: QTimer* saveGeometryTimer_; QRect newGeometry_; public slots: void saveGeometry(); void restoreGeometry(); private slots: void updateGeometry(); void restoreGeometry(QRect savedGeometry); }; int GAdvancedWidget::Private::stickAt = 5; bool GAdvancedWidget::Private::stickToWindows = true; bool GAdvancedWidget::Private::stickEnabled = true; GAdvancedWidget::Private::Private(QWidget *parent) : QObject(parent) , parentWidget_(parent) , flashing_(false) { if (!advancedWidgetShared) advancedWidgetShared = new AdvancedWidgetShared(); parentWidget_ = parent; saveGeometryTimer_ = new QTimer(this); saveGeometryTimer_->setInterval(100); saveGeometryTimer_->setSingleShot(true); connect(saveGeometryTimer_, SIGNAL(timeout()), SLOT(saveGeometry())); } void GAdvancedWidget::Private::posChanging(int *x, int *y, int *width, int *height) { if ( stickAt <= 0 || !stickEnabled || !parentWidget_->isTopLevel() || parentWidget_->isMaximized() || !parentWidget_->updatesEnabled() ) { return; } QWidget *p = parentWidget_; if ( p->pos() == QPoint(*x, *y) && p->frameSize() == QSize(*width, *height) ) return; bool resizing = p->frameSize() != QSize(*width, *height); QDesktopWidget *desktop = qApp->desktop(); QWidgetList list; if ( stickToWindows ) list = QApplication::topLevelWidgets(); foreach(QWidget *w, list) { QRect rect; bool dockWidget = false; if ( w->windowType() == Qt::Desktop ) rect = ((QDesktopWidget *)w)->availableGeometry((QWidget *)parent()); else { if ( w == p || desktop->screenNumber(p) != desktop->screenNumber(w) ) continue; if ( !w->isVisible() ) continue; // we want for widget to stick to outer edges of another widget, so // we'll change the rect to what it'll snap rect = QRect(w->frameGeometry().bottomRight(), w->frameGeometry().topLeft()); dockWidget = true; } if ( *x != p->x() ) if ( *x <= rect.left() + stickAt && *x > rect.left() - stickAt ) { if ( !dockWidget || (p->frameGeometry().bottom() >= rect.bottom() && p->frameGeometry().top() <= rect.top()) ) { *x = rect.left(); if ( resizing ) *width = p->frameSize().width() + p->x() - *x; } } if ( *x + *width >= rect.right() - stickAt && *x + *width <= rect.right() + stickAt ) { if ( !dockWidget || (p->frameGeometry().bottom() >= rect.bottom() && p->frameGeometry().top() <= rect.top()) ) { if ( resizing ) *width = rect.right() - *x + 1; else *x = rect.right() - *width + 1; } } if ( *y != p->y() ) if ( *y <= rect.top() + stickAt && *y > rect.top() - stickAt ) { if ( !dockWidget || (p->frameGeometry().right() >= rect.right() && p->frameGeometry().left() <= rect.left()) ) { *y = rect.top(); if ( resizing ) *height = p->frameSize().height() + p->y() - *y; } } if ( *y + *height >= rect.bottom() - stickAt && *y + *height <= rect.bottom() + stickAt ) { if ( !dockWidget || (p->frameGeometry().right() >= rect.right() && p->frameGeometry().left() <= rect.left()) ) { if ( resizing ) *height = rect.bottom() - *y + 1; else *y = rect.bottom() - *height + 1; } } } } bool GAdvancedWidget::Private::flashing() const { return flashing_; } void GAdvancedWidget::Private::doFlash(bool yes) { flashing_ = yes; if (parentWidget_->window() != parentWidget_) return; #ifdef Q_WS_WIN FLASHWINFO fwi; fwi.cbSize = sizeof(fwi); fwi.hwnd = parentWidget_->winId(); if (yes) { fwi.dwFlags = FLASHW_ALL | FLASHW_TIMER; fwi.dwTimeout = 0; fwi.uCount = 5; } else { fwi.dwFlags = FLASHW_STOP; fwi.uCount = 0; } FlashWindowEx(&fwi); #elif defined( Q_WS_X11 ) static Atom demandsAttention = None; static Atom wmState = None; /* Xlib-based solution */ // adopted from http://www.qtforum.org/article/12334/Taskbar-flashing.html // public domain by Marcin Jakubowski Display *xdisplay = QX11Info::display(); Window rootwin = QX11Info::appRootWindow(); if (demandsAttention == None) demandsAttention = XInternAtom(xdisplay, "_NET_WM_STATE_DEMANDS_ATTENTION", true); if (wmState == None) wmState = XInternAtom(xdisplay, "_NET_WM_STATE", true); XEvent e; e.xclient.type = ClientMessage; e.xclient.message_type = wmState; e.xclient.display = xdisplay; e.xclient.window = parentWidget_->winId(); e.xclient.format = 32; e.xclient.data.l[1] = demandsAttention; e.xclient.data.l[2] = 0l; e.xclient.data.l[3] = 0l; e.xclient.data.l[4] = 0l; if (yes) { e.xclient.data.l[0] = 1; } else { e.xclient.data.l[0] = 0; } XSendEvent(xdisplay, rootwin, False, (SubstructureRedirectMask | SubstructureNotifyMask), &e); #else Q_UNUSED(yes) #endif } void GAdvancedWidget::Private::moveEvent(QMoveEvent *) { if (!parentWidget_->isTopLevel()) return; #ifdef Q_WS_MAC QRect r = qApp->desktop()->availableGeometry(parentWidget_); QRect g = parentWidget_->frameGeometry(); int margin = 5; if (g.top() < r.top()) g.moveTo(g.x(), r.top()); if (g.right() < r.left() + margin) g.moveTo(r.left() + margin - g.width(), g.y()); if (g.left() > r.right() - margin) g.moveTo(r.right() - margin, g.y()); if (g.top() > r.bottom() - margin) g.moveTo(g.x(), r.bottom() - margin); newGeometry_ = g; QTimer::singleShot(0, this, SLOT(updateGeometry())); #endif } void GAdvancedWidget::Private::updateGeometry() { QWidget *w = (QWidget *)parent(); w->move(newGeometry_.topLeft()); } void GAdvancedWidget::Private::saveGeometry() { PsiOptions::instance()->setOption(geometryOptionPath_, parentWidget_->normalGeometry()); PsiOptions::instance()->setOption(geometryOptionPath_ + "-frame", parentWidget_->frameGeometry()); PsiOptions::instance()->setOption(geometryOptionPath_ + "-screen", QApplication::desktop()->screenNumber(parentWidget_)); PsiOptions::instance()->setOption(geometryOptionPath_ + "-maximized", (parentWidget_->windowState() & Qt::WindowMaximized) != 0); PsiOptions::instance()->setOption(geometryOptionPath_ + "-fullscreen", (parentWidget_->windowState() & Qt::WindowFullScreen) != 0); } void GAdvancedWidget::Private::restoreGeometry() { PsiOptions *o = PsiOptions::instance(); QVariant v(o->getOption(geometryOptionPath_)); if (v.type() == QVariant::ByteArray) { // migrate options back from format used for a short time before // 0.12-RC2. This can be removed later. parentWidget_->restoreGeometry(v.toByteArray()); } else if (o->getOption(geometryOptionPath_ + "-frame").toRect() != QRect(0,0,0,0)) { // this is at least as safe as saving this kind of binary blob into the options file. // if future Qt versions drop support for restoring from this format old options files // would break anyway. If we want to (e.g. to add other features) we can also reimplement // restoring any other way without breaking the options format at all. // and this way we are sure no Qt version the user happens to have installed writes some // newer version of the format that older Qts can't restore from. QByteArray array; QDataStream stream(&array, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_4_0); const quint32 magicNumber = 0x1D9D0CB; quint16 majorVersion = 1; quint16 minorVersion = 0; QRect restoredFrameGeometry = o->getOption(geometryOptionPath_ + "-frame").toRect(); QRect restoredNormalGeometry = o->getOption(geometryOptionPath_).toRect(); stream << magicNumber << majorVersion << minorVersion << restoredFrameGeometry << restoredNormalGeometry << qint32(o->getOption(geometryOptionPath_ + "-screen").toInt()) << quint8(o->getOption(geometryOptionPath_ + "-maximized").toBool()) << quint8(o->getOption(geometryOptionPath_ + "-fullscreen").toBool()); parentWidget_->restoreGeometry(array); return; } else { // used for bootstrapping and for pre 0.12-RC1 options files. QRect savedGeometry = o->getOption(geometryOptionPath_).toRect(); if (!savedGeometry.isEmpty()) { restoreGeometry(savedGeometry); } } } // FIXME: should use frameGeometry void GAdvancedWidget::Private::restoreGeometry(QRect savedGeometry) { QRect geom = savedGeometry; QDesktopWidget *pdesktop = QApplication::desktop(); int nscreen = pdesktop->screenNumber(geom.topLeft()); QRect r = pdesktop->screenGeometry(nscreen); // if the coordinates are out of the desktop bounds, reset to the top left int pad = 10; if (geom.left() < r.left()) geom.moveLeft(r.left()); if (geom.right() >= r.right()) geom.moveRight(r.right() - 1); if (geom.top() < r.top()) geom.moveTop(r.top()); if (geom.bottom() >= r.bottom()) geom.moveBottom(r.bottom() - 1); if ((geom.width() + pad * 2) > r.width()) geom.setWidth(r.width() - pad * 2); if ((geom.height() + pad * 2) > r.height()) geom.setHeight(r.height() - pad * 2); parentWidget_->move(geom.topLeft()); parentWidget_->resize(geom.size()); } bool GAdvancedWidget::Private::eventFilter(QObject* obj, QEvent* e) { if (obj == parentWidget_) { if (e->type() == QEvent::Move || e->type() == QEvent::Resize) { saveGeometryTimer_->start(); } return false; } return QObject::eventFilter(obj, e); } //---------------------------------------------------------------------------- // GAdvancedWidget //---------------------------------------------------------------------------- GAdvancedWidget::GAdvancedWidget(QWidget *parent) : QObject(parent) { d = new Private(parent); } #ifdef Q_OS_WIN bool GAdvancedWidget::winEvent(MSG* msg, long* result) { if ( msg->message == WM_WINDOWPOSCHANGING ) { WINDOWPOS *wpos = (WINDOWPOS *)msg->lParam; d->posChanging(&wpos->x, &wpos->y, &wpos->cx, &wpos->cy); result = 0; return true; } return false; } #endif QString GAdvancedWidget::geometryOptionPath() const { return d->geometryOptionPath_; } void GAdvancedWidget::setGeometryOptionPath(const QString& optionPath) { Q_ASSERT(d->geometryOptionPath_.isEmpty()); Q_ASSERT(!optionPath.isEmpty()); d->geometryOptionPath_ = optionPath; d->restoreGeometry(); d->parentWidget_->installEventFilter(d); } bool GAdvancedWidget::flashing() const { return d->flashing(); } void GAdvancedWidget::doFlash(bool on) { d->doFlash( on ); } #ifdef Q_WS_WIN // http://groups.google.ru/group/borland.public.cppbuilder.winapi/msg/6eb6f1832d68686d?hl=ru& bool ForceForegroundWindow(HWND hwnd) { // Code from Thomas Stutz @ delphi3000.com // Converted to Borland C++ Builder Code by Wolfgang Frisch bool Result; // #define SPI_GETFOREGROUNDLOCKTIMEOUT (0x2000); // #define SPI_SETFOREGROUNDLOCKTIMEOUT (0x2001); DWORD nullvalue = 0; DWORD ForegroundThreadID; DWORD ThisThreadID; DWORD timeout; if (IsIconic(hwnd)) { ShowWindow(hwnd, SW_RESTORE); } if (GetForegroundWindow() == hwnd) { return true; } else { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); // Windows 98/2000 doesn't want to foreground a window when some other // window has keyboard focus if (((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osvi.dwMajorVersion > 4)) || ((osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && ((osvi.dwMajorVersion > 4) || ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0))))) { // Code from Karl E. Peterson, www.mvps.org/vb/sample.htm // Converted to Delphi by Ray Lischner // Published in The Delphi Magazine 55, page 16 Result = false; ForegroundThreadID = GetWindowThreadProcessId(GetForegroundWindow(), NULL); ThisThreadID = GetWindowThreadProcessId(hwnd, NULL); if (AttachThreadInput(ThisThreadID, ForegroundThreadID, true)) { BringWindowToTop(hwnd); // IE 5.5 related hack SetForegroundWindow(hwnd); AttachThreadInput(ThisThreadID, ForegroundThreadID, false); Result = (GetForegroundWindow() == hwnd); } if (!Result) { // Code by Daniel P. Stasinski SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, &nullvalue, SPIF_SENDCHANGE); BringWindowToTop(hwnd); // IE 5.5 related hack SetForegroundWindow(hwnd); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, &timeout, SPIF_SENDCHANGE); } } else { BringWindowToTop(hwnd); // IE 5.5 related hack SetForegroundWindow(hwnd); } Result = (GetForegroundWindow() == hwnd); } return Result; } #endif /** * http://trolltech.com/developer/task-tracker/index_html?id=202971&method=entry * There's a bug in Qt that prevents us to show a window on Windows * without it being activated in the process. This is not good in some cases. * We try our best to work-around this on Windows. */ void GAdvancedWidget::showWithoutActivation() { if (d->parentWidget_->isVisible()) return; // TODO: look at Qt::WA_ShowWithoutActivating that was introduced // in Qt 4.4.0, maybe it'll provide a simpler alternative to this // windows-specific code #ifdef Q_WS_WIN HWND foregroundWindow = GetForegroundWindow(); #endif #if QT_VERSION >= 0x040400 bool showWithoutActivating = d->parentWidget_->testAttribute(Qt::WA_ShowWithoutActivating); d->parentWidget_->setAttribute(Qt::WA_ShowWithoutActivating, true); #endif d->parentWidget_->show(); #if QT_VERSION >= 0x040400 d->parentWidget_->setAttribute(Qt::WA_ShowWithoutActivating, showWithoutActivating); #endif #ifdef Q_WS_WIN if (foregroundWindow) { // the first step is to make sure we're the topmost window // otherwise step two doesn't seem to have any effect at all ForceForegroundWindow(d->parentWidget_->winId()); ForceForegroundWindow(foregroundWindow); } #endif } void GAdvancedWidget::changeEvent(QEvent *event) { if (event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowStateChange) { if (d->parentWidget_->isActiveWindow()) { doFlash(false); } } } int GAdvancedWidget::stickAt() { return Private::stickAt; } void GAdvancedWidget::setStickAt(int val) { Private::stickAt = val; } bool GAdvancedWidget::stickToWindows() { return Private::stickToWindows; } void GAdvancedWidget::setStickToWindows(bool val) { Private::stickToWindows = val; } bool GAdvancedWidget::stickEnabled() { return Private::stickEnabled; } void GAdvancedWidget::setStickEnabled(bool val) { Private::stickEnabled = val; } void GAdvancedWidget::moveEvent(QMoveEvent *e) { d->moveEvent(e); } #include "advwidget.moc" psi-0.14/src/tools/advwidget/movetest/0000755000175000017500000000000011305557613016114 5ustar janjanpsi-0.14/src/tools/advwidget/movetest/main.cpp0000644000175000017500000000132011305557613017540 0ustar janjan#include #include #include #include #include "../advwidget.h" class MyWidget : public AdvancedWidget { Q_OBJECT public: MyWidget() { mouseDown = false; } void mousePressEvent(QMouseEvent *e) { mouseDown = true; oldPos = e->globalPos(); } void mouseReleaseEvent(QMouseEvent *) { mouseDown = false; } void mouseMoveEvent(QMouseEvent *e) { if (mouseDown) { QPoint dp = e->globalPos() - oldPos; oldPos = e->globalPos(); move(pos() + dp); } } QPoint oldPos; bool mouseDown; }; int main (int argc, char *argv[]) { QApplication app(argc, argv); MyWidget mw; mw.show(); return app.exec(); } #include "main.moc" psi-0.14/src/tools/advwidget/movetest/test.pro0000644000175000017500000000017511305557613017620 0ustar janjanTEMPLATE = app CONFIG += qt advwidget QT += gui SOURCES += main.cpp ADVWIDGET_CPP = .. include($$ADVWIDGET_CPP/advwidget.pri)psi-0.14/src/accountlabel.h0000644000175000017500000000250011305557613013732 0ustar janjan/* * accountlabel.h - simple label to display account name currently in use * Copyright (C) 2006-2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACCOUNTLABEL_H #define ACCOUNTLABEL_H #include #include class PsiAccount; class AccountLabel : public QLabel { Q_OBJECT Q_PROPERTY(bool showJid READ showJid WRITE setShowJid) public: AccountLabel(QWidget* parent); ~AccountLabel(); PsiAccount* account() const; bool showJid() const; void setAccount(PsiAccount* account); void setShowJid(bool showJid); private slots: void updateName(); private: QPointer account_; bool showJid_; }; #endif psi-0.14/src/changepwdlg.h0000644000175000017500000000247311305557613013572 0ustar janjan/* * changepwdlg.h - dialog for changing password * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CHANGEPWDLG_H #define CHANGEPWDLG_H #include "ui_changepw.h" class PsiAccount; class ChangePasswordDlg : public QDialog { Q_OBJECT public: ChangePasswordDlg(PsiAccount *, QWidget *parent=0); ~ChangePasswordDlg(); protected: //void closeEvent(QCloseEvent *e); public slots: void done(int); private slots: void apply(); void finished(); void disc(); private: void blockWidgets(); void restoreWidgets(); void setWidgetsEnabled(bool enabled); Ui::ChangePassword ui_; PsiAccount* pa; }; #endif psi-0.14/src/showtextdlg.cpp0000644000175000017500000000455211305557613014216 0ustar janjan/* * showtextdlg.cpp - dialog for displaying a text file * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include "showtextdlg.h" // FIXME: combine to common init function ShowTextDlg::ShowTextDlg(const QString &fname, bool rich, QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); QString text; QFile f(fname); if(f.open(QIODevice::ReadOnly)) { QTextStream t(&f); while(!t.atEnd()) text += t.readLine() + '\n'; f.close(); } QVBoxLayout *vb1 = new QVBoxLayout(this); vb1->setMargin(8); QTextEdit *te = new QTextEdit(this); te->setReadOnly(true); te->setAcceptRichText(rich); te->setText(text); vb1->addWidget(te); QHBoxLayout *hb1 = new QHBoxLayout; vb1->addLayout(hb1); hb1->addStretch(1); QPushButton *pb = new QPushButton(tr("&OK"), this); connect(pb, SIGNAL(clicked()), SLOT(accept())); hb1->addWidget(pb); hb1->addStretch(1); resize(560, 384); } ShowTextDlg::ShowTextDlg(const QString &text, bool nonfile, bool rich, QWidget *parent) : QDialog(parent) { Q_UNUSED(nonfile); setAttribute(Qt::WA_DeleteOnClose); QVBoxLayout *vb1 = new QVBoxLayout(this); vb1->setMargin(8); QTextEdit *te = new QTextEdit(this); te->setReadOnly(true); te->setAcceptRichText(rich); te->setText(text); vb1->addWidget(te); QHBoxLayout *hb1 = new QHBoxLayout; vb1->addLayout(hb1); hb1->addStretch(1); QPushButton *pb = new QPushButton(tr("&OK"), this); connect(pb, SIGNAL(clicked()), SLOT(accept())); hb1->addWidget(pb); hb1->addStretch(1); resize(560, 384); } psi-0.14/src/ahcservermanager.cpp0000644000175000017500000001716511305557613015163 0ustar janjan/* * ahcservermanager.cpp - Server implementation of JEP-50 (Ad-Hoc Commands) * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include "ahcservermanager.h" #include "ahcommandserver.h" #include "psiaccount.h" #include "xmpp_xmlcommon.h" #include "xmpp_tasks.h" #include "xmpp_xdata.h" #include "xdata_widget.h" #include "ahcommand.h" using namespace XMPP; #define AHC_NS "http://jabber.org/protocol/commands" // -------------------------------------------------------------------------- // JT_AHCServer: Task to handle ad-hoc command requests // -------------------------------------------------------------------------- class JT_AHCServer : public Task { Q_OBJECT public: JT_AHCServer(Task*, AHCServerManager*); bool take(const QDomElement& e); void sendReply(const AHCommand&, const Jid& to, const QString& id); protected: bool commandListQuery(const QDomElement& e); bool commandExecuteQuery(const QDomElement& e); void sendCommandList(const QString& to, const QString& from, const QString& id); private: AHCServerManager* manager_; }; JT_AHCServer::JT_AHCServer(Task* t, AHCServerManager* manager) : Task(t), manager_(manager) { } bool JT_AHCServer::take(const QDomElement& e) { // Check if it's a query if (e.tagName() != "iq") return false; return (commandListQuery(e) || commandExecuteQuery(e)); } bool JT_AHCServer::commandListQuery(const QDomElement& e) { if (e.attribute("type") == "get") { bool found; QDomElement q = findSubTag(e, "query", &found); if (!found) return false; // Disco replies to the AdHoc node if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#items" && q.attribute("node") == AHC_NS) { sendCommandList(e.attribute("from"),e.attribute("to"),e.attribute("id")); return true; } else if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#info" && q.attribute("node") == AHC_NS) { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); iq.appendChild(query); send(iq); return true; } // Disco replies to specific adhoc nodes else if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#items" && manager_->hasServer(q.attribute("node"), Jid(e.attribute("from")))) { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); query.setAttribute("node",q.attribute("node")); iq.appendChild(query); send(iq); return true; } else if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#info" && manager_->hasServer(q.attribute("node"), Jid(e.attribute("from")))) { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); query.setAttribute("node",q.attribute("node")); iq.appendChild(query); QDomElement identity; identity = doc()->createElement("identity"); identity.setAttribute("category", "automation"); identity.setAttribute("type", "command-node"); query.appendChild(identity); QDomElement feature; feature = doc()->createElement("feature"); feature.setAttribute("var", AHC_NS); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "jabber:x:data"); query.appendChild(feature); send(iq); return true; } } return false; } bool JT_AHCServer::commandExecuteQuery(const QDomElement& e) { if (e.attribute("type") == "set") { bool found; QDomElement q = findSubTag(e, "command", &found); if (found && q.attribute("xmlns") == AHC_NS && manager_->hasServer(q.attribute("node"), Jid(e.attribute("from")))) { AHCommand command(q); manager_->execute(command, Jid(e.attribute("from")), e.attribute("id")); return true; } else return false; } return false; } void JT_AHCServer::sendCommandList(const QString& to, const QString& from, const QString& id) { // Create query element QDomElement iq = createIQ(doc(), "result", to, id); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); query.setAttribute("node", AHC_NS); iq.appendChild(query); // Add all commands foreach(AHCommandServer* c, manager_->commands(Jid(to))) { QDomElement command = doc()->createElement("item"); command.setAttribute("jid",from); command.setAttribute("name",c->name()); command.setAttribute("node",c->node()); query.appendChild(command); } // Send the message send(iq); } void JT_AHCServer::sendReply(const AHCommand& c, const Jid& to, const QString& id) { // if (c.error().type() != AHCError::None) { QDomElement iq = createIQ(doc(), "result", to.full(), id); QDomElement command = c.toXml(doc(), false); iq.appendChild(command); send(iq); // } // else { // } } // -------------------------------------------------------------------------- AHCServerManager::AHCServerManager(PsiAccount *pa) : pa_(pa) { server_task_ = new JT_AHCServer(pa_->client()->rootTask(), this); } void AHCServerManager::addServer(AHCommandServer* server) { servers_.append(server); } void AHCServerManager::removeServer(AHCommandServer* server) { servers_.removeAll(server); } AHCServerManager::ServerList AHCServerManager::commands(const Jid& j) const { ServerList list; for (ServerList::ConstIterator it = servers_.begin(); it != servers_.end(); ++it) { if ((*it)->isAllowed(j)) list.append(*it); } return list; } void AHCServerManager::execute(const AHCommand& command, const Jid& requester, QString id) { AHCommandServer* c = findServer(command.node()); // Check if the command is provided if (!c) { //server_task_->sendReply(AHCommand::errorReply(command,AHCError(AHCError::ItemNotFound)), requester, id); return; } // Check if the requester is allowed to execute the command if (c->isAllowed(requester)) { if (command.action() == AHCommand::Cancel) { c->cancel(command); server_task_->sendReply(AHCommand::canceledReply(command), requester, id); } else // Execute the command & send back the response server_task_->sendReply(c->execute(command, requester), requester, id); } else { //server_task_->sendReply(AHCommand::errorReply(command,AHCError(AHCError::Forbidden)), requester, id); return; } } bool AHCServerManager::hasServer(const QString& node, const Jid& requester) const { AHCommandServer* c = findServer(node); return c && c->isAllowed(requester); } AHCommandServer* AHCServerManager::findServer(const QString& node) const { for (ServerList::ConstIterator it = servers_.begin(); it != servers_.end(); ++it) { if ((*it)->node() == node) return (*it); } return 0; } #include "ahcservermanager.moc" psi-0.14/src/mood.ui0000644000175000017500000000470611305557613012434 0ustar janjan Mood 0 0 241 120 Set Mood 9 6 0 6 Type: Text: Qt::Vertical 20 31 0 6 Qt::Horizontal 131 31 OK Cancel psi-0.14/src/adduserdlg.h0000644000175000017500000000350711305557613013424 0ustar janjan/* * adduserdlg.h - dialog for adding contacts * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ADDUSERDLG_H #define ADDUSERDLG_H #include "ui_adduser.h" class QString; class QStringList; class PsiAccount; namespace XMPP { class Jid; } class AddUserDlg : public QDialog, public Ui::AddUser { Q_OBJECT public: AddUserDlg(const QStringList &services, const QStringList &names, const QStringList &groups, PsiAccount *); AddUserDlg(const XMPP::Jid &jid, const QString &nick, const QString &group, const QStringList &groups, PsiAccount *); ~AddUserDlg(); signals: void add(const XMPP::Jid &, const QString &, const QStringList &, bool authReq); private slots: void ok(); void cancel(); void serviceActivated(int); void getTransID(); void jt_getFinished(); void jt_setFinished(); void le_transPromptChanged(const QString &); void getVCardActivated(); void resolveNickActivated(); void resolveNickFinished(); void jid_Changed(); private: void init(const QStringList &groups, PsiAccount *); class Private; Private *d; XMPP::Jid jid() const; void errorGateway(const QString &str, const QString &err); }; #endif psi-0.14/src/mainwin_p.cpp0000644000175000017500000003424311305557613013623 0ustar janjan/* * mainwin_p.cpp - classes used privately by the main window. * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "mainwin_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psiaccount.h" #include "stretchwidget.h" #include "iconwidget.h" #include "icontoolbutton.h" #include "alerticon.h" #include "psicontactlist.h" //---------------------------------------------------------------------------- // PopupActionButton //---------------------------------------------------------------------------- class PopupActionButton : public QPushButton { Q_OBJECT public: PopupActionButton(QWidget *parent = 0, const char *name = 0); ~PopupActionButton(); void setIcon(PsiIcon *, bool showText); void setLabel(QString); // reimplemented QSize sizeHint() const; QSize minimumSizeHint() const; private slots: void pixmapUpdated(); private: void update(); void paintEvent(QPaintEvent *); bool hasToolTip; PsiIcon *icon; bool showText; QString label; }; PopupActionButton::PopupActionButton(QWidget *parent, const char *name) : QPushButton(parent), hasToolTip(false), icon(0), showText(true) { setObjectName(name); } PopupActionButton::~PopupActionButton() { if (icon) icon->stop(); } QSize PopupActionButton::sizeHint() const { // hack to prevent QToolBar's extender button from displaying if (sizePolicy().horizontalPolicy() == QSizePolicy::Expanding) return QSize(16, 16); return QPushButton::sizeHint(); } QSize PopupActionButton::minimumSizeHint() const { return QSize(16, 16); } void PopupActionButton::setIcon(PsiIcon *i, bool st) { if ( icon ) { icon->stop(); disconnect (icon, 0, this, 0); icon = 0; } icon = i; showText = st; if ( icon ) { pixmapUpdated(); connect(icon, SIGNAL(pixmapChanged()), SLOT(pixmapUpdated())); icon->activated(); } } void PopupActionButton::setLabel(QString lbl) { label = lbl; update(); } void PopupActionButton::update() { if(qVersionInt() >= 0x040300) { if((showText && !label.isEmpty()) && styleSheet().isEmpty()) { setStyleSheet("text-align: left"); } else if((!showText || label.isEmpty()) && styleSheet() == "text-align: left") { setStyleSheet(QString()); } } if (showText) { QPushButton::setText(label); } else { QPushButton::setText(""); } } void PopupActionButton::pixmapUpdated() { QPixmap pix = icon ? icon->pixmap() : QPixmap(); QPushButton::setIcon(pix); QPushButton::setIconSize(pix.size()); update(); } void PopupActionButton::paintEvent(QPaintEvent *p) { // crazy code ahead! watch out for potholes and deer. // this gets us the width of the "text area" on the button. // adapted from qt/src/styles/qcommonstyle.cpp and qt/src/widgets/qpushbutton.cpp if (showText) { QStyleOptionButton style_option; style_option.init(this); QRect r = style()->subElementRect(QStyle::SE_PushButtonContents, &style_option, this); if(menu()) r.setWidth(r.width() - style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &style_option, this)); // if(!QPushButton::icon().isNull()) // r.setWidth(r.width() - (QPushButton::icon().pixmap(QIcon::Small, QIcon::Normal, QIcon::Off).width())); // font metrics QFontMetrics fm(font()); // w1 = width of button text, w2 = width of text area int w1 = fm.width(label); int w2 = r.width(); // backup original text QString oldtext = label; // button text larger than what will fit? if(w1 > w2) { if( !hasToolTip ) { setToolTip(label); hasToolTip = true; } // make a string that fits bool found = false; QString newtext; int n; for(n = oldtext.length(); n > 0; --n) { if(fm.width(oldtext, n) < w2) { found = true; break; } } if(found) newtext = oldtext.mid(0, n); else newtext = ""; // set the new text that fits. updates must be off, or we recurse. if (newtext != text()) { setUpdatesEnabled(false); QPushButton::setText(newtext); setUpdatesEnabled(true); } } else { if (oldtext != text()) { setUpdatesEnabled(false); QPushButton::setText(oldtext); setUpdatesEnabled(true); } if( hasToolTip ) { setToolTip(""); hasToolTip = false; } } } QPushButton::paintEvent(p); } //---------------------------------------------------------------------------- // PopupAction -- the IconButton with popup or QPopupMenu //---------------------------------------------------------------------------- class PopupAction::Private : public QObject { public: QSizePolicy size; QList buttons; PsiIcon *icon; bool showText; Private (QObject *parent) : QObject (parent) { icon = 0; showText = true; } ~Private() { qDeleteAll(buttons); buttons.clear(); if (icon) delete icon; } }; PopupAction::PopupAction (const QString &label, QMenu *_menu, QObject *parent, const char *name) : IconAction (label, label, 0, parent, name) { d = new Private (this); setMenu( _menu ); } void PopupAction::setSizePolicy (const QSizePolicy &p) { d->size = p; } void PopupAction::setAlert (const PsiIcon *icon) { setIcon(icon, d->showText, true); } void PopupAction::setIcon (const PsiIcon *icon, bool showText, bool alert) { PsiIcon *oldIcon = 0; if ( d->icon ) { oldIcon = d->icon; d->icon = 0; } d->showText = showText; if ( icon ) { if ( !alert ) d->icon = new PsiIcon(*icon); else d->icon = new AlertIcon(icon); IconAction::setIcon(icon->icon()); } else { d->icon = 0; IconAction::setIcon(QIcon()); } foreach(PopupActionButton* btn, d->buttons) { btn->setIcon (d->icon, showText); } if ( oldIcon ) { delete oldIcon; } } void PopupAction::setText (const QString &text) { IconAction::setText (text); foreach(PopupActionButton* btn, d->buttons) { btn->setLabel (text); } } bool PopupAction::addTo(QWidget *w) { QToolBar* toolbar = dynamic_cast(w); if (toolbar) { PopupActionButton *btn = new PopupActionButton(w); btn->setObjectName(objectName() + QString("_action_button")); d->buttons.append(btn); btn->setMenu(menu()); btn->setLabel(text()); btn->setIcon(d->icon, d->showText); btn->setSizePolicy(d->size); btn->setEnabled(isEnabled()); toolbar->addWidget(btn); connect(btn, SIGNAL(destroyed()), SLOT(objectDestroyed())); } else { return IconAction::addTo(w); } return true; } void PopupAction::objectDestroyed () { const QObject *obj = sender(); d->buttons.removeAll( (PopupActionButton *) obj ); } void PopupAction::setEnabled (bool e) { IconAction::setEnabled (e); foreach(PopupActionButton* btn, d->buttons) { btn->setEnabled (e); } } IconAction *PopupAction::copy() const { PopupAction *act = new PopupAction(text(), menu(), 0, objectName().toLatin1()); *act = *this; return act; } PopupAction &PopupAction::operator=( const PopupAction &from ) { *( (IconAction *)this ) = from; d->size = from.d->size; setIcon( from.d->icon ); d->showText = from.d->showText; return *this; } //---------------------------------------------------------------------------- // MLabel -- a clickable label //---------------------------------------------------------------------------- MLabel::MLabel(QWidget *parent, const char *name) :QLabel(parent) { setObjectName(name); setMinimumWidth(48); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); setFrameStyle(QFrame::Panel | QFrame::Sunken); } void MLabel::mouseReleaseEvent(QMouseEvent *e) { emit clicked(e->button()); e->ignore(); } void MLabel::mouseDoubleClickEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) emit doubleClicked(); e->ignore(); } //---------------------------------------------------------------------------- // MAction //---------------------------------------------------------------------------- MAction::MAction(PsiIcon i, const QString& s, int id, PsiCon* psi, QObject* parent) : IconActionGroup(parent) { init(s, i, id, psi); } MAction::MAction(const QString& s, int id, PsiCon* psi, QObject* parent) : IconActionGroup(parent) { init(s, PsiIcon(), id, psi); } void MAction::init(const QString& name, PsiIcon i, int id, PsiCon* psi) { id_ = id; controller_ = psi; setText(name); setStatusTip(name); setPsiIcon(&i); connect(controller_, SIGNAL(accountCountChanged()), SLOT(numAccountsChanged())); connect(this, SIGNAL(triggered()), SLOT(slotActivated())); numAccountsChanged(); } bool MAction::addTo(QWidget* widget) { widget->addAction(this); return true; } QList MAction::accounts() const { return controller_->contactList()->enabledAccounts(); } void MAction::slotActivated() { if (accounts().count() > 0) { emit activated(accounts().first(), id_); } } void MAction::actionActivated() { QAction* action = static_cast(sender()); int num = action->property("id").toInt(); if (num >= 0 && num < accounts().count()) { emit activated(accounts().at(num), id_); } } void MAction::numAccountsChanged() { setEnabled(accounts().count() > 0); qDeleteAll(findChildren()); foreach(PsiAccount* account, accounts()) { QAction* act = new QAction(account->name(), this); act->setProperty("id", accounts().indexOf(account)); connect(act, SIGNAL(triggered()), SLOT(actionActivated())); } } IconAction *MAction::copy() const { MAction *act = new MAction(text(), id_, controller_, 0); *act = *this; return act; } MAction &MAction::operator=( const MAction &from ) { *( (IconAction *)this ) = from; return *this; } void MAction::doSetMenu(QMenu* menu) { IconActionGroup::doSetMenu(findChildren().count() > 1 ? menu : 0); } //---------------------------------------------------------------------------- // SpacerAction //---------------------------------------------------------------------------- SpacerAction::SpacerAction(QObject *parent, const char *name) : IconAction(parent) { setObjectName(name); setText(tr("")); setText(tr("")); setWhatsThis(tr("Spacer provides spacing to separate actions")); } SpacerAction::~SpacerAction() { } bool SpacerAction::addTo(QWidget *w) { QToolBar* toolbar = dynamic_cast(w); if (toolbar) { StretchWidget* stretch = new StretchWidget(w); toolbar->addWidget(stretch); return true; } return false; } IconAction *SpacerAction::copy() const { return new SpacerAction( 0 ); } //---------------------------------------------------------------------------- // SeparatorAction //---------------------------------------------------------------------------- SeparatorAction::SeparatorAction( QObject *parent, const char *name ) : IconAction( tr(""), tr(""), 0, parent, name ) { setSeparator(true); setWhatsThis (tr("Separator")); } SeparatorAction::~SeparatorAction() { } // we don't want QToolButtons when adding this action // on toolbar bool SeparatorAction::addTo(QWidget *w) { w->addAction(this); return true; } IconAction *SeparatorAction::copy() const { return new SeparatorAction(0); } //---------------------------------------------------------------------------- // EventNotifierAction //---------------------------------------------------------------------------- class EventNotifierAction::Private { public: Private() { } QList labels; bool hide; QString message; }; EventNotifierAction::EventNotifierAction(QObject *parent, const char *name) : IconAction(parent, name) { d = new Private; setText(tr("")); d->hide = true; } EventNotifierAction::~EventNotifierAction() { delete d; } bool EventNotifierAction::addTo(QWidget *w) { if (w) { MLabel *label = new MLabel(w, "EventNotifierAction::MLabel"); label->setText(d->message); d->labels.append(label); connect(label, SIGNAL(destroyed()), SLOT(objectDestroyed())); connect(label, SIGNAL(doubleClicked()), SIGNAL(triggered())); connect(label, SIGNAL(clicked(int)), SIGNAL(clicked(int))); QToolBar* toolbar = dynamic_cast(w); if (!toolbar) { QLayout* layout = w->layout(); if (layout) layout->addWidget(label); } else { toolbar->addWidget(label); } if (d->hide) hide(); return true; } return false; } void EventNotifierAction::setMessage(const QString &m) { d->message = m; foreach(MLabel* label, d->labels) { label->setText(d->message); } } void EventNotifierAction::objectDestroyed() { MLabel *label = (MLabel *)sender(); d->labels.removeAll(label); } void EventNotifierAction::hide() { d->hide = true; foreach(MLabel* label, d->labels) { label->hide(); QToolBar *toolBar = dynamic_cast(label->parent()); if (toolBar) { int found = 0; foreach(QWidget* widget, toolBar->findChildren()) { if (!widget->objectName().startsWith("qt_") && !QString(widget->metaObject()->className()).startsWith("QToolBar")) { found++; } } if (found == 1) // only MLabel is on ToolBar toolBar->hide(); } } } void EventNotifierAction::show() { d->hide = false; foreach(MLabel* label, d->labels) { label->show(); QToolBar *toolBar = dynamic_cast(label->parent()); if (toolBar) toolBar->show(); } } void EventNotifierAction::updateVisibility() { if (d->hide) hide(); else show(); } IconAction *EventNotifierAction::copy() const { EventNotifierAction *act = new EventNotifierAction( 0 ); *act = *this; return act; } EventNotifierAction &EventNotifierAction::operator=( const EventNotifierAction &from ) { *( (IconAction *)this ) = from; d->hide = from.d->hide; return *this; } #include "mainwin_p.moc" psi-0.14/src/statuscombobox.h0000644000175000017500000000247711305557613014367 0ustar janjan/* * statuscombobox.h - helper class that displays available statuses using QComboBox * Copyright (C) 2008 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef STATUSCOMBOBOX_H #define STATUSCOMBOBOX_H #include #include "xmpp_status.h" class StatusComboBox : public QComboBox { Q_OBJECT public: StatusComboBox(QWidget* parent, XMPP::Status::Type type = XMPP::Status::Offline); void setStatus(XMPP::Status::Type type); XMPP::Status::Type status() const; signals: void statusChanged(XMPP::Status::Type type); private: void addStatus(XMPP::Status::Type type); private slots: void onCurrentIndexChanged(int); }; #endif psi-0.14/src/main.cpp0000644000175000017500000003240211305557613012561 0ustar janjan/* * main.cpp - initialization and profile/settings handling * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "psiapplication.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "profiledlg.h" #include "activeprofiles.h" #include "psicli.h" #include "psioptions.h" #include "eventdlg.h" #include "psicon.h" #include "psiiconset.h" #include "translationmanager.h" #include "applicationinfo.h" #include "chatdlg.h" #ifdef USE_CRASH # include"crash.h" #endif #ifdef Q_WS_MAC #include "CocoaUtilities/CocoaInitializer.h" #endif #ifdef Q_OS_WIN # include // for RegDeleteKey #endif #ifdef Q_OS_WIN #define URI_RESTART #endif /** \mainpage Psi API Documentation * * \section intro_sec Indroduction * Let's write an introduction to go here * * \section Installation * For installation details, please see the INSTALL file * * \section Contact Details * And here we might put our contact details */ using namespace XMPP; PsiMain::PsiMain(const QMap& commandline, QObject *par) : QObject(par) , cmdline(commandline) { pcon = 0; // migrate old (pre 0.11) registry settings... QSettings sUser(QSettings::UserScope, "psi-im.org", "Psi"); lastProfile = sUser.value("last_profile").toString(); lastLang = sUser.value("last_lang").toString(); autoOpen = sUser.value("auto_open", QVariant(false)).toBool(); QSettings s(ApplicationInfo::homeDir() + "/psirc", QSettings::IniFormat); lastProfile = s.value("last_profile", lastProfile).toString(); lastLang = s.value("last_lang", lastLang).toString(); autoOpen = s.value("auto_open", autoOpen).toBool(); if(lastLang.isEmpty()) { lastLang = QLocale::system().name().section('_', 0, 0); //printf("guessing locale: [%s]\n", lastLang.latin1()); } TranslationManager::instance()->loadTranslation(lastLang); if (cmdline.contains("help")) { PsiCli().showHelp(); QTimer::singleShot(0, this, SLOT(bail())); } else if(cmdline.contains("version")) { PsiCli().showVersion(); QTimer::singleShot(0, this, SLOT(bail())); } else if(cmdline.contains("choose-profile")) { // Select a profile QTimer::singleShot(0, this, SLOT(chooseProfile())); } else if(cmdline.contains("profile") && profileExists(cmdline["profile"])) { // Open profile from commandline activeProfile = lastProfile = cmdline["profile"]; QTimer::singleShot(0, this, SLOT(sessionStart())); } else if(autoOpen && !lastProfile.isEmpty() && profileExists(lastProfile)) { // Auto-open the last profile activeProfile = lastProfile; QTimer::singleShot(0, this, SLOT(sessionStart())); } else if (!lastProfile.isEmpty() && !getProfilesList().isEmpty()) { // Select a profile QTimer::singleShot(0, this, SLOT(chooseProfile())); } else if (getProfilesList().count() == 1) { // Open the (only) profile activeProfile = getProfilesList()[0]; QTimer::singleShot(0, this, SLOT(sessionStart())); } else if (!getProfilesList().isEmpty()) { // Select a profile QTimer::singleShot(0, this, SLOT(chooseProfile())); } else { // Create & open the default profile if (!profileExists("default") && !profileNew("default")) { QMessageBox::critical(0, tr("Error"), tr("There was an error creating the default profile.")); QTimer::singleShot(0, this, SLOT(bail())); } else { // options.xml will be created by PsiCon::init lastProfile = activeProfile = "default"; autoOpen = true; QTimer::singleShot(0, this, SLOT(sessionStart())); } } } PsiMain::~PsiMain() { delete pcon; QSettings s(ApplicationInfo::homeDir() + "/psirc", QSettings::IniFormat); s.setValue("last_profile", lastProfile); s.setValue("last_lang", lastLang); s.setValue("auto_open", autoOpen); } void PsiMain::chooseProfile() { if(pcon) { delete pcon; pcon = 0; } QString str = ""; // dirty, dirty, dirty hack PsiIconset::instance()->loadSystem(); while(1) { ProfileOpenDlg *w = new ProfileOpenDlg(lastProfile, TranslationManager::instance()->availableTranslations(), TranslationManager::instance()->currentLanguage()); w->ck_auto->setChecked(autoOpen); int r = w->exec(); // lang change if(r == 10) { TranslationManager::instance()->loadTranslation(w->newLang); lastLang = TranslationManager::instance()->currentLanguage(); delete w; continue; } else { bool again = false; autoOpen = w->ck_auto->isChecked(); if(r == QDialog::Accepted) { str = w->cb_profile->currentText(); again = !ActiveProfiles::instance()->setThisProfile(str); if (again) { QMessageBox mb(QMessageBox::Question, CAP(tr("Profile already in use")), QString(tr("The \"%1\" profile is already in use.\nWould you like to activate that session now?")).arg(str), QMessageBox::Cancel); QPushButton *activate = mb.addButton(tr("Activate"), QMessageBox::AcceptRole); mb.exec(); if (mb.clickedButton() == activate) { ActiveProfiles::instance()->raise(str, true); quit(); return; } } } delete w; if (again) { str = ""; continue; } break; } } if(str.isEmpty()) { quit(); return; } // only set lastProfile if the user opened it lastProfile = str; activeProfile = str; sessionStart(); } void PsiMain::sessionStart() { if (!ActiveProfiles::instance()->setThisProfile(activeProfile)) { // already running if (!ActiveProfiles::instance()->raise(activeProfile, true)) { QMessageBox::critical(0, tr("Error"), tr("Cannot open this profile - it is already running, but not responding")); } quit(); return; } // make sure we have clean PsiOptions PsiOptions::reset(); // get a PsiCon pcon = new PsiCon(); if (!pcon->init()) { delete pcon; pcon = 0; quit(); return; } connect(pcon, SIGNAL(quit(int)), SLOT(sessionQuit(int))); if (cmdline.contains("uri")) { ActiveProfiles::instance()->openUriRequested(cmdline.value("uri")); cmdline.remove("uri"); } if (cmdline.contains("status") || cmdline.contains("status-message")) { ActiveProfiles::instance()->setStatusRequested(cmdline.value("status"), cmdline.value("status-message")); cmdline.remove("status"); cmdline.remove("status-message"); } } void PsiMain::sessionQuit(int x) { if(x == PsiCon::QuitProgram) { QTimer::singleShot(0, this, SLOT(bail())); } else if(x == PsiCon::QuitProfile) { QTimer::singleShot(0, this, SLOT(chooseProfile())); } } void PsiMain::bail() { if(pcon) { delete pcon; pcon = 0; } quit(); } #ifdef URI_RESTART // all printable chars except for space, dash, and double-quote are // backslash-escaped. static QByteArray encodeUri(const QByteArray &in) { QByteArray out; for(int n = 0; n < in.size(); ++n) { unsigned char c = (unsigned char)in[n]; if(c == '\\') { out += "\\\\"; } else if(c >= 0x21 && c < 0x7f && c != '-' && c != '\"') { out += in[n]; } else { char hex[5]; qsnprintf(hex, 5, "\\x%02x", c); out += QByteArray::fromRawData(hex, 4); } } return out; } static QString decodeUri(const QString &in) { // note that the input is an 8-bit text encoding which is then escaped, // and the result is a latin1-compatible string. to decode this, we // need to first unescape back to 8-bit, and then decode the 8-bit // into unicode QByteArray dec; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') { if(n + 1 < in.length()) { ++n; if(in[n] == '\\') { dec += '\\'; } else if(in[n] == 'x') { if(n + 2 < in.length()) { ++n; QString xs = in.mid(n, 2); ++n; bool ok = false; int x = xs.toInt(&ok, 16); if(ok) { unsigned char c = (unsigned char)x; dec += c; } } } } } else dec += in[n].toLatin1(); } return QString::fromLocal8Bit(dec); } // NOTE: this function is called without qapp existing static int restart_process(int argc, char **argv, const QByteArray &uri) { // FIXME: in the future we should use CreateProcess instead, but for // now it is easier to use qprocess, and it should be safe if // qcoreapp is used instead of qapp which i believe does not read // args /*BOOL ret; QT_WA( ret = CreateProcessW(); , ret = CreateProcessA(); )*/ // re-run ourself, with encoded uri QCoreApplication qapp(argc, argv); QString selfExe = QCoreApplication::applicationFilePath(); // don't use QCoreApplication::arguments(), because that calls // GetCommandLine which is not clipped. instead, use the provided // argc/argv. QStringList args; for(int n = 1; n < argc; ++n) { args += QString::fromLocal8Bit(argv[n]); } if(!uri.isEmpty()) { args += QString("--encuri=") + QString::fromLatin1(encodeUri(uri)); } if(QProcess::startDetached(selfExe, args)) { return 0; } else { return 1; } } #endif int main(int argc, char *argv[]) { // If Psi runs as uri handler the commandline might contain // almost arbitary network supplied data after the "--uri" argument. // To prevent any potentially dangerous options in Psi or // Qt to be triggered by this, filter out the uri and any following // data as early as possible. We even filter before qca init, just in // case qca ever decides to check commandline arguments in a future // version. // see http://www.mozilla.org/security/announce/2007/mfsa2007-23.html // for how this problem affected firefox on windows. PsiCli cli; QMap cmdline = cli.parse(argc, argv, QStringList() << "uri", &argc); if (cmdline.contains("uri")) { #ifdef URI_RESTART // for windows, we have to restart the process return restart_process(argc, argv, cmdline["uri"].toLocal8Bit()); #else // otherwise, it should enough to modify argc/argv argv[argc] = 0; #endif } // NOTE: Qt 4.5 compatibility note: please don't move this call. // instead, upgrade to QCA 2.0.2, which fixes the bug in the right // place. QCA::Initializer init; // END NOTE #ifdef Q_WS_MAC CocoaInitializer cocoaInitializer; #endif // it must be initialized first in order for ApplicationInfo::resourcesDir() to work PsiApplication app(argc, argv); QApplication::addLibraryPath(ApplicationInfo::resourcesDir()); QApplication::addLibraryPath(ApplicationInfo::homeDir()); QApplication::setQuitOnLastWindowClosed(false); #ifdef Q_WS_MAC QDir dir(QApplication::applicationDirPath()); dir.cdUp(); dir.cd("Plugins"); QApplication::addLibraryPath(dir.absolutePath()); #endif // Initialize QCA QCA::setProperty("pgp-always-trust", true); QCA::KeyStoreManager keystoremgr; QCA::KeyStoreManager::start(); keystoremgr.waitForBusyFinished(); // FIXME get rid of this #ifdef USE_CRASH int useCrash = !cmdline.contains("nocrash"); if ( useCrash ) Crash::registerSigsegvHandler(argv[0]); #endif // seed the random number generator srand(time(NULL)); //dtcp_port = 8000; #ifdef URI_RESTART if (cmdline.contains("encuri")) { cmdline["uri"] = decodeUri(cmdline["encuri"].toLocal8Bit()); cmdline.remove("encuri"); } #endif // check if we want to remote-control other psi instance if (!cmdline.contains("help") && !cmdline.contains("version") && !cmdline.contains("choose-profile") && ActiveProfiles::instance()->isAnyActive() && ((cmdline.contains("profile") && ActiveProfiles::instance()->isActive(cmdline["profile"])) || !cmdline.contains("profile"))) { bool raise = true; if (cmdline.contains("uri")) { ActiveProfiles::instance()->openUri(cmdline.value("profile"), cmdline.value("uri")); raise = false; } if (cmdline.contains("status")) { ActiveProfiles::instance()->setStatus(cmdline.value("profile"), cmdline.value("status"), cmdline.value("status-message")); raise = false; } if (raise) { ActiveProfiles::instance()->raise(cmdline.value("profile"), true); } return 0; } if (cmdline.contains("remote")) { return 0; } //if(link_test) // printf("Link test enabled\n"); // silly winsock workaround //QSocketDevice *d = new QSocketDevice; //delete d; // Initialize translations TranslationManager::instance(); // need SHA1 for Iconset sound //if(!QCA::isSupported(QCA::CAP_SHA1)) // QCA::insertProvider(XMPP::createProviderHash()); PsiMain *psi = new PsiMain(cmdline); QObject::connect(psi, SIGNAL(quit()), &app, SLOT(quit())); int returnValue = app.exec(); delete psi; return returnValue; } #ifdef QCA_STATIC #include #ifdef HAVE_OPENSSL Q_IMPORT_PLUGIN(qca_ossl) #endif #ifdef HAVE_CYRUSSASL Q_IMPORT_PLUGIN(qca_cyrus_sasl) #endif Q_IMPORT_PLUGIN(qca_gnupg) #endif //#if defined(Q_WS_WIN) && defined(QT_STATICPLUGIN) //Q_IMPORT_PLUGIN(qjpeg) //Q_IMPORT_PLUGIN(qgif) //#endif psi-0.14/src/mucmanager.cpp0000644000175000017500000004073311305557613013762 0ustar janjan/* * mucmanager.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // TODO: // The MUCManager should listen to Client::messageReceived, and update the // role and affiliation of the user, maybe even keep its own list of // participants. This should make all the 'can*' functions a lot simpler, // and take more weight of the groupchat dialog. // The MUCManager should also signal things such as 'room destroyed' etc. // In the most extreme case, the MUC manager also broadcasts status changes, // taking all the protocol responsibilities from the groupchat. #include #include "mucmanager.h" #include "xmpp_xdata.h" #include "xmpp_xmlcommon.h" #include "xmpp_task.h" #include "xmpp_client.h" using namespace XMPP; // ----------------------------------------------------------------------------- class MUCItemsTask : public Task { public: MUCItemsTask(const Jid& room, Task* parent) : Task(parent), room_(room) { } void set(const QList& items, MUCManager::Action action = MUCManager::Unknown) { action_ = action; iq_ = createIQ(doc(), "set", room_.full(), id()); QDomElement muc = doc()->createElement("query"); muc.setAttribute("xmlns", "http://jabber.org/protocol/muc#admin"); iq_.appendChild(muc); foreach(MUCItem item, items) { muc.appendChild(item.toXml(*doc())); } } void getByAffiliation(MUCItem::Affiliation affiliation) { affiliation_ = affiliation; iq_ = createIQ(doc(), "get", room_.full(), id()); QDomElement muc = doc()->createElement("query"); muc.setAttribute("xmlns", "http://jabber.org/protocol/muc#admin"); muc.appendChild(MUCItem(MUCItem::UnknownRole, affiliation).toXml(*doc())); iq_.appendChild(muc); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, room_, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (!e.isNull() && e.tagName() == "item") { items_ += MUCItem(e); } } setSuccess(); } else { setError(x); } return true; } const QList& items() const { return items_; } MUCManager::Action action() const { return action_; } MUCItem::Affiliation affiliation() const { return affiliation_; } private: QDomElement iq_; Jid room_; MUCManager::Action action_; MUCItem::Affiliation affiliation_; QList items_; }; // ----------------------------------------------------------------------------- class MUCConfigurationTask : public Task { public: MUCConfigurationTask(const Jid& room, Task* parent) : Task(parent), room_(room) { } void set(const XData& data) { iq_ = createIQ(doc(), "set", room_.full(), id()); QDomElement muc = doc()->createElement("query"); muc.setAttribute("xmlns", "http://jabber.org/protocol/muc#owner"); iq_.appendChild(muc); muc.appendChild(data.toXml(doc())); } void get() { iq_ = createIQ(doc(), "get", room_.full(), id()); QDomElement muc = doc()->createElement("query"); muc.setAttribute("xmlns", "http://jabber.org/protocol/muc#owner"); iq_.appendChild(muc); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, room_, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (!e.isNull() && e.tagName() == "x" && e.attribute("xmlns") == "jabber:x:data") { data_.fromXml(e); } } setSuccess(); } else { setError(x); } return true; } const XData& data() const { return data_; } private: QDomElement iq_; Jid room_; XData data_; }; // ----------------------------------------------------------------------------- class MUCDestroyTask : public Task { public: MUCDestroyTask(const Jid& room, const QString& reason, const Jid& venue, Task* parent) : Task(parent), room_(room) { iq_ = createIQ(doc(), "set", room.full(), id()); QDomElement muc = doc()->createElement("query"); muc.setAttribute("xmlns", "http://jabber.org/protocol/muc#owner"); iq_.appendChild(muc); MUCDestroy d; d.setJid(venue); d.setReason(reason); muc.appendChild(d.toXml(*doc())); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, room_, id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } private: Jid room_; QDomElement iq_; }; // ----------------------------------------------------------------------------- MUCManager::MUCManager(Client* client, const Jid& room) : client_(client), room_(room) { } const Jid& MUCManager::room() const { return room_; } void MUCManager::getConfiguration() { MUCConfigurationTask* t = new MUCConfigurationTask(room_, client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(getConfiguration_finished())); t->get(); t->go(true); } void MUCManager::setConfiguration(const XMPP::XData& c) { MUCConfigurationTask* t = new MUCConfigurationTask(room_, client_->rootTask()); XData config = c; config.setType(XData::Data_Submit); connect(t,SIGNAL(finished()),SLOT(setConfiguration_finished())); t->set(config); t->go(true); } void MUCManager::setDefaultConfiguration() { setConfiguration(XData()); } void MUCManager::destroy(const QString& reason, const Jid& venue) { MUCDestroyTask* t = new MUCDestroyTask(room_, reason, venue, client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(destroy_finished())); t->go(true); } void MUCManager::setItems(const QList& items) { MUCItemsTask* t = new MUCItemsTask(room_, client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(setItems_finished())); t->set(items); t->go(true); } void MUCManager::getItemsByAffiliation(MUCItem::Affiliation affiliation) { MUCItemsTask* t = new MUCItemsTask(room_, client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(getItemsByAffiliation_finished())); t->getByAffiliation(affiliation); t->go(true); } void MUCManager::kick(const QString& nick, const QString& reason) { setRole(nick, MUCItem::NoRole, reason, Kick); } void MUCManager::grantVoice(const QString& nick, const QString& reason) { setRole(nick, MUCItem::Participant, reason, GrantVoice); } void MUCManager::revokeVoice(const QString& nick, const QString& reason) { setRole(nick, MUCItem::Visitor, reason, RevokeVoice); } void MUCManager::grantModerator(const QString& nick, const QString& reason) { setRole(nick, MUCItem::Moderator, reason, GrantModerator); } void MUCManager::revokeModerator(const QString& nick, const QString& reason) { setRole(nick, MUCItem::Participant, reason, RevokeModerator); } void MUCManager::ban(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::Outcast, reason, Ban); } void MUCManager::grantMember(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::Member, reason, GrantMember); } void MUCManager::revokeMember(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::NoAffiliation, reason, RevokeMember); } void MUCManager::grantOwner(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::Owner, reason, GrantOwner); } void MUCManager::revokeOwner(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::Member, reason, RevokeOwner); } void MUCManager::grantAdmin(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::Admin, reason, GrantAdmin); } void MUCManager::revokeAdmin(const Jid& user, const QString& reason) { setAffiliation(user, MUCItem::Member, reason, RevokeAdmin); } void MUCManager::setRole(const QString& nick, MUCItem::Role role, const QString& reason, Action action) { QList items; MUCItem item(role,MUCItem::UnknownAffiliation); item.setNick(nick); if (!reason.isEmpty()) item.setReason(reason); items.push_back(item); MUCItemsTask* t = new MUCItemsTask(room_, client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(action_finished())); t->set(items,action); t->go(true); } void MUCManager::setAffiliation(const Jid& user, MUCItem::Affiliation affiliation, const QString& reason, Action action) { QList items; MUCItem item(MUCItem::UnknownRole,affiliation); item.setJid(user.bare()); if (!reason.isEmpty()) item.setReason(reason); items.push_back(item); MUCItemsTask* t = new MUCItemsTask(room_, client_->rootTask()); connect(t,SIGNAL(finished()),SLOT(action_finished())); t->set(items,action); t->go(true); } QString MUCManager::roleToString(MUCItem::Role r, bool p) { QString s; switch (r) { case MUCItem::Moderator: s = (p ? QObject::tr("a moderator") : QObject::tr("moderator")); break; case MUCItem::Participant: s = (p ? QObject::tr("a participant") : QObject::tr("participant")); break; case MUCItem::Visitor: s = (p ? QObject::tr("a visitor") : QObject::tr("visitor")); break; default: s = ""; } return s; } QString MUCManager::affiliationToString(MUCItem::Affiliation a, bool p) { QString s; switch (a) { case MUCItem::Owner: s = (p ? QObject::tr("an owner") : QObject::tr("owner")); break; case MUCItem::Admin: s = (p ? QObject::tr("an administrator") : QObject::tr("administrator")); break; case MUCItem::Member: s = (p ? QObject::tr("a member") : QObject::tr("member")); break; case MUCItem::Outcast: s = (p ? QObject::tr("an outcast") : QObject::tr("outcast")); break; case MUCItem::NoAffiliation: s = QObject::tr("unaffiliated"); default: break; } return s; } bool MUCManager::canKick(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.role() == MUCItem::Moderator && i1.affiliation() >= i2.affiliation(); } bool MUCManager::canGrantVoice(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.role() == MUCItem::Moderator && i2.role() < MUCItem::Participant; } bool MUCManager::canRevokeVoice(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.role() == MUCItem::Moderator && i1.affiliation() >= i2.affiliation() && i2.affiliation() < MUCItem::Owner && i2.role() >= MUCItem::Participant; } bool MUCManager::canGrantModerator(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Admin && i2.role() < MUCItem::Moderator; } bool MUCManager::canRevokeModerator(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Admin && i2.affiliation() < MUCItem::Admin && i2.role() >= MUCItem::Moderator; } bool MUCManager::canBan(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Admin && i1.affiliation() >= i2.affiliation() && !i2.jid().isEmpty(); } bool MUCManager::canGrantMember(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Admin && i2.affiliation() < MUCItem::Member && !i2.jid().isEmpty(); } bool MUCManager::canRevokeMember(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Admin && i2.affiliation() >= MUCItem::Member && !i2.jid().isEmpty(); } bool MUCManager::canGrantOwner(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() == MUCItem::Owner && i2.affiliation() < MUCItem::Owner && !i2.jid().isEmpty(); } bool MUCManager::canRevokeOwner(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Owner && i2.affiliation() == MUCItem::Owner && !i2.jid().isEmpty(); } bool MUCManager::canGrantAdmin(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() == MUCItem::Owner && i2.affiliation() < MUCItem::Admin && !i2.jid().isEmpty(); } bool MUCManager::canRevokeAdmin(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2) { return i1.affiliation() >= MUCItem::Owner && i2.affiliation() == MUCItem::Admin && !i2.jid().isEmpty(); } void MUCManager::getConfiguration_finished() { MUCConfigurationTask* t = (MUCConfigurationTask*) sender(); if (t->success()) { emit getConfiguration_success(t->data()); } else { emit getConfiguration_error(t->statusCode(), t->statusString()); } } bool MUCManager::canSetRole(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2, XMPP::MUCItem::Role r) { if (i2.role() == r) return true; if (r == MUCItem::Visitor) { return (i2.role() == MUCItem::Moderator ? canRevokeModerator(i1,i2) : canRevokeVoice(i1,i2)); } else if (r == MUCItem::Participant) { return (i2.role() < r ? canGrantVoice(i1,i2) : canRevokeModerator(i1,i2)); } else if (r == MUCItem::Moderator) { return canGrantModerator(i1,i2); } return false; } bool MUCManager::canSetAffiliation(const XMPP::MUCItem& i1, const XMPP::MUCItem& i2, XMPP::MUCItem::Affiliation a) { if (i2.affiliation() == a) return true; if (!i2.jid().isValid()) return false; if (a == MUCItem::Outcast) { return canBan(i1,i2); } else if (a == MUCItem::NoAffiliation) { return (i2.affiliation() >= MUCItem::Admin ? canRevokeAdmin(i1,i2) : canRevokeMember(i1,i2)); } else if (a == MUCItem::Member) { return (i2.affiliation() >= MUCItem::Admin ? canRevokeAdmin(i1,i2) : canGrantMember(i1,i2)); } else if (a == MUCItem::Admin) { return (i2.affiliation() == MUCItem::Owner ? canRevokeOwner(i1,i2) : canGrantAdmin(i1,i2)); } else if (a == MUCItem::Owner) { return canGrantOwner(i1,i2); } return false; } void MUCManager::setConfiguration_finished() { MUCConfigurationTask* t = (MUCConfigurationTask*) sender(); if (t->success()) { emit setConfiguration_success(); } else { emit setConfiguration_error(t->statusCode(), t->statusString()); } } void MUCManager::action_finished() { MUCItemsTask* t = (MUCItemsTask*) sender(); if (t->success()) { emit action_success(t->action()); } else { QString text; Action action = t->action(); if (t->statusCode() == 405) { if (action == Kick) text = tr("You are not allowed to kick this user."); else if (action == Ban) text = tr("You are not allowed to ban this user."); else if (action == GrantVoice) text = tr("You are not allowed to grant voice to this user."); else if (action == RevokeVoice) text = tr("You are not allowed to revoke voice from this user."); else if (action == GrantMember) text = tr("You are not allowed to grant membership to this user."); else if (action == RevokeMember) text = tr("You are not allowed to revoke membership from this user."); else if (action == GrantModerator) text = tr("You are not allowed to grant moderator privileges to this user."); else if (action == RevokeModerator) text = tr("You are not allowed to revoke moderator privileges from this user."); else if (action == GrantAdmin) text = tr("You are not allowed to grant administrative privileges to this user."); else if (action == RevokeAdmin) text = tr("You are not allowed to revoke administrative privileges from this user."); else if (action == GrantOwner) text = tr("You are not allowed to grant ownership privileges to this user."); else if (action == RevokeOwner) text = tr("You are not allowed to revoke ownership privileges from this user."); else text = tr("You are not allowed to perform this operation."); } else { text = tr("Failed to perform operation: ") + t->statusString(); } emit action_error(t->action(), t->statusCode(), text); } } void MUCManager::getItemsByAffiliation_finished() { MUCItemsTask* t = (MUCItemsTask*) sender(); if (t->success()) { emit getItemsByAffiliation_success(t->affiliation(), t->items()); } else { emit getItemsByAffiliation_error(t->affiliation(), t->statusCode(), t->statusString()); } } void MUCManager::setItems_finished() { MUCItemsTask* t = (MUCItemsTask*) sender(); if (t->success()) { emit setItems_success(); } else { emit setItems_error(t->statusCode(), t->statusString()); } } void MUCManager::destroy_finished() { MUCDestroyTask* t = (MUCDestroyTask*) sender(); if (t->success()) { emit destroy_success(); } else { emit destroy_error(t->statusCode(), t->statusString()); } } psi-0.14/src/activeprofiles.h0000644000175000017500000000340111305557613014316 0ustar janjan/* * activeprofiles.h - Class for interacting with other psi instances * Copyright (C) 2006 Maciej Niedzielski * Copyright (C) 2006-2007 Martin Hostettler * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACTIVEPSIPROFILES_H #define ACTIVEPSIPROFILES_H #include class ActiveProfiles: public QObject { Q_OBJECT public: static ActiveProfiles* instance(); bool setThisProfile(const QString &profile); void unsetThisProfile(); QString thisProfile() const; bool isActive(const QString &profile) const; bool isAnyActive() const; bool setStatus(const QString &profile, const QString &status, const QString &message) const; bool openUri(const QString &profile, const QString &uri) const; bool raise(const QString &profile, bool withUI) const; ~ActiveProfiles(); signals: void setStatusRequested(const QString &status, const QString &message); void openUriRequested(const QString &uri); void raiseRequested(); protected: static ActiveProfiles *instance_; private: class Private; Private *d; ActiveProfiles(); friend class PsiConAdapter; friend class PsiMain; }; #endif psi-0.14/src/alertable.cpp0000644000175000017500000000354211305557613013573 0ustar janjan/* * alertable.cpp - simplify alert icon plumbing * Copyright (C) 2006 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "alertable.h" #include #include "alerticon.h" /** * Class to simplify alert icon plumbing. You'll have to re-implement * alertFrameUpdated() in your subclass. */ Alertable::Alertable(QObject* parent) : QObject(parent) { alert_ = 0; } /** * Destroys alert icon along with itself; */ Alertable::~Alertable() { setAlert(0); } /** * Returns true if alert is set, and false otherwise. */ bool Alertable::alerting() const { return alert_ != 0; } /** * Returns current animation frame of alert, or null QIcon, if * there is no alert. */ QIcon Alertable::currentAlertFrame() const { if (!alert_) return QIcon(); return alert_->impix().pixmap(); } /** * Creates new AlertIcon based on provided \param icon. If 0 is passed, * alert is cleared. */ void Alertable::setAlert(const PsiIcon* icon) { if (alert_) { alert_->stop(); delete alert_; alert_ = 0; } if (icon) { alert_ = new AlertIcon(icon); alert_->activated(false); connect(alert_, SIGNAL(pixmapChanged()), SLOT(alertFrameUpdated())); alertFrameUpdated(); } } psi-0.14/src/accountadddlg.cpp0000644000175000017500000000622111305557613014431 0ustar janjan/* * accountadddlg.cpp - dialogs for manipulating PsiAccounts * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "accountadddlg.h" #include "psicon.h" #include "psioptions.h" #include "psiaccount.h" #include "accountregdlg.h" #include "psicontactlist.h" AccountAddDlg::AccountAddDlg(PsiCon *_psi, QWidget *parent) :QDialog(parent) { setupUi(this); setModal(false); psi = _psi; psi->dialogRegister(this); setWindowTitle(CAP(windowTitle())); connect(pb_close, SIGNAL(clicked()), SLOT(close())); connect(pb_add, SIGNAL(clicked()), SLOT(add())); connect(le_name, SIGNAL(textChanged(const QString &)), SLOT(setAddButton(const QString &))); ck_reg->setWhatsThis( tr("Check this option if you don't yet have a Jabber account " "and you want to register one. Note that this will only work " "on servers that allow anonymous registration.")); QString aname = createNewAccountName(tr("Default")); if (PsiOptions::instance()->getOption("options.ui.account.single").toBool()) { le_name->setText("account"); lb_name->hide(); le_name->hide(); } else { le_name->setText(aname); le_name->setFocus(); } } AccountAddDlg::~AccountAddDlg() { psi->dialogUnregister(this); } QString AccountAddDlg::createNewAccountName(QString def) { QString aname = def; int n = 0; while(1) { bool taken = false; foreach(PsiAccount* pa, psi->contactList()->accounts()) { if(aname == pa->name()) { taken = true; break; } } if(!taken) break; aname = def + '_' + QString::number(++n); } return aname; } void AccountAddDlg::add() { QString aname = createNewAccountName(le_name->text()); le_name->setText( aname ); if(ck_reg->isChecked()) { AccountRegDlg *w = new AccountRegDlg(psi->proxy(), this); int n = w->exec(); if(n != QDialog::Accepted) { delete w; return; } Jid jid = w->jid(); QString pass = w->pass(); bool opt_host = w->useHost(); QString host = w->host(); int port = w->port(); bool legacy_ssl_probe = w->legacySSLProbe(); UserAccount::SSLFlag ssl = w->ssl(); QString proxy = w->proxy(); QString tlsOverrideDomain = w->tlsOverrideDomain(); QByteArray tlsOverrideCert = w->tlsOverrideCert(); delete w; psi->createAccount(le_name->text(), jid, pass, opt_host, host, port, legacy_ssl_probe, ssl, proxy, tlsOverrideDomain, tlsOverrideCert); } else { psi->createAccount(le_name->text()); } close(); } void AccountAddDlg::setAddButton(const QString &s) { pb_add->setEnabled(!s.isEmpty()); } psi-0.14/src/proxy.cpp0000644000175000017500000003617411305557613013030 0ustar janjan/* * proxy.cpp - classes for handling proxy profiles * Copyright (C) 2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "proxy.h" #include #include #include #include #include #include #include #include #include //Added by qt3to4: #include #include #include "common.h" #include "iconwidget.h" #include "psioptions.h" #include "xmpp_xmlcommon.h" //---------------------------------------------------------------------------- // ProxySettings //---------------------------------------------------------------------------- ProxySettings::ProxySettings() { port = 0; useAuth = false; } #define PASSWORDKEY "Cae1voo:ea}fae2OCai|f1il" void ProxySettings::toOptions(OptionsTree* o, QString base) const { o->setOption(base + ".host", host); o->setOption(base + ".port", port); o->setOption(base + ".url", url); o->setOption(base + ".useAuth", useAuth); o->setOption(base + ".user", user); o->setOption(base + ".pass", encodePassword(pass, PASSWORDKEY)); } void ProxySettings::fromOptions(OptionsTree* o, QString base) { host = o->getOption(base + ".host").toString(); port = o->getOption(base + ".port").toInt(); url = o->getOption(base + ".url").toString(); useAuth = o->getOption(base + ".useAuth").toBool(); user = o->getOption(base + ".user").toString(); pass = decodePassword(o->getOption(base + ".pass").toString(), PASSWORDKEY); } QDomElement ProxySettings::toXml(QDomDocument *doc) const { QDomElement e = doc->createElement("proxySettings"); e.appendChild(XMLHelper::textTag(*doc, "host", host)); e.appendChild(XMLHelper::textTag(*doc, "port", QString::number(port))); e.appendChild(XMLHelper::textTag(*doc, "url", url)); e.appendChild(XMLHelper::textTag(*doc, "useAuth", useAuth)); e.appendChild(XMLHelper::textTag(*doc, "user", user)); e.appendChild(XMLHelper::textTag(*doc, "pass", pass)); return e; } bool ProxySettings::fromXml(const QDomElement &e) { host = findSubTag(e, "host", 0).text(); port = findSubTag(e, "port", 0).text().toInt(); url = findSubTag(e, "url", 0).text(); useAuth = (findSubTag(e, "useAuth", 0).text() == "true") ? true: false; user = findSubTag(e, "user", 0).text(); pass = findSubTag(e, "pass", 0).text(); return true; } //---------------------------------------------------------------------------- // ProxyDlg //---------------------------------------------------------------------------- class ProxyDlg::Private : public QObject { Q_OBJECT public: enum Data { HostRole = Qt::UserRole + 1, PortRole = Qt::UserRole + 2, UrlRole = Qt::UserRole + 3, AuthRole = Qt::UserRole + 4, UserRole = Qt::UserRole + 5, PassRole = Qt::UserRole + 6, IdRole = Qt::UserRole + 7, TypeRole = Qt::UserRole + 8 }; ProxyDlg* q; ProxyItemList list; Private(ProxyDlg* dialog) : QObject(dialog) , q(dialog) { Q_ASSERT(q); connect(q->ui_.lbx_proxy, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(currentItemChanged(QListWidgetItem*, QListWidgetItem*))); connect(q->ui_.pb_new, SIGNAL(clicked()), SLOT(addProxy())); connect(q->ui_.pb_remove, SIGNAL(clicked()), SLOT(removeProxy())); connect(q->ui_.buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(accept())); connect(q->ui_.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), q, SLOT(reject())); q->ui_.buttonBox->button(QDialogButtonBox::Save)->setDefault(true); connect(q->ui_.lbx_proxy->itemDelegate(), SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)), SLOT(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint))); connect(q->ui_.le_host, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(q->ui_.le_port, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(q->ui_.le_url, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(q->ui_.le_user, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(q->ui_.le_pass, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(q->ui_.gr_auth, SIGNAL(toggled(bool)), SLOT(updateCurrentItem())); connect(q->ui_.cb_type, SIGNAL(activated (int)), SLOT(updateCurrentItem())); } public slots: void loadProxies(const QString& currentProxy) { q->ui_.lbx_proxy->clear(); QListWidgetItem* firstItem = 0; QListWidgetItem* currentItem = 0; foreach(ProxyItem i, list) { QListWidgetItem* item = new QListWidgetItem(i.name); addItem(item); item->setData(IdRole, QVariant(i.id)); item->setData(TypeRole, QVariant(i.type)); item->setData(HostRole, QVariant(i.settings.host)); item->setData(PortRole, QVariant(i.settings.port)); item->setData(UserRole, QVariant(i.settings.user)); item->setData(PassRole, QVariant(i.settings.pass)); item->setData(AuthRole, QVariant(i.settings.useAuth)); item->setData(UrlRole, QVariant(i.settings.url)); if (!firstItem) { firstItem = item; } if (i.id == currentProxy) { currentItem = item; } } if (currentItem) { firstItem = currentItem; } if (firstItem) { q->ui_.lbx_proxy->setCurrentItem(firstItem); q->ui_.lbx_proxy->scrollToItem(firstItem); } } void saveProxies() { list.clear(); for (int i = 0; i < q->ui_.lbx_proxy->count(); ++i) { QListWidgetItem* item = q->ui_.lbx_proxy->item(i); ProxyItem pi; pi.name = item->data(Qt::DisplayRole).toString(); pi.id = item->data(IdRole).toString(); pi.type = item->data(TypeRole).toString(); pi.settings.host = item->data(HostRole).toString(); pi.settings.port = item->data(PortRole).toInt(); pi.settings.user = item->data(UserRole).toString(); pi.settings.pass = item->data(PassRole).toString(); pi.settings.useAuth = item->data(AuthRole).toBool(); pi.settings.url = item->data(UrlRole).toString(); list << pi; } } void accept() { saveProxies(); emit q->applyList(list, q->ui_.lbx_proxy->currentRow()); q->accept(); } void currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous) { Q_UNUSED(previous); q->ui_.pb_remove->setEnabled(current); QList editors = QList() << q->ui_.cb_type << q->ui_.le_host << q->ui_.le_port << q->ui_.le_user << q->ui_.le_pass << q->ui_.le_url << q->ui_.gr_auth; foreach(QWidget* w, editors) { w->blockSignals(true); w->setEnabled(current); if (!current) { if (dynamic_cast(w)) dynamic_cast(w)->setText(QString()); } } if (current) { int type = q->ui_.cb_type->findData(current->data(TypeRole).toString()); q->ui_.cb_type->setCurrentIndex(type == -1 ? 0 : type); q->ui_.le_host->setText(current->data(HostRole).toString()); q->ui_.le_port->setText(current->data(PortRole).toString()); q->ui_.le_user->setText(current->data(UserRole).toString()); q->ui_.le_pass->setText(current->data(PassRole).toString()); q->ui_.le_url->setText(current->data(UrlRole).toString()); q->ui_.gr_auth->setChecked(true); // make sure gr_auth disables its children if AuthRole is false q->ui_.gr_auth->setChecked(current->data(AuthRole).toBool()); } foreach(QWidget* w, editors) { w->blockSignals(false); } updateCurrentItem(); } void updateCurrentItem() { QListWidgetItem* item = q->ui_.lbx_proxy->currentItem(); if (!item) return; QString type = q->ui_.cb_type->itemData(q->ui_.cb_type->currentIndex()).toString(); item->setData(TypeRole, type); item->setData(HostRole, q->ui_.le_host->text()); item->setData(PortRole, q->ui_.le_port->text()); item->setData(UserRole, q->ui_.le_user->text()); item->setData(PassRole, q->ui_.le_pass->text()); item->setData(UrlRole, q->ui_.le_url->text()); item->setData(AuthRole, q->ui_.gr_auth->isChecked()); q->ui_.le_url->setEnabled(type == "poll"); } void closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint) { Q_UNUSED(editor); if (hint == QAbstractItemDelegate::SubmitModelCache) { q->ui_.cb_type->setFocus(); } } void addItem(QListWidgetItem* item) { Q_ASSERT(item); item->setFlags(item->flags() | Qt::ItemIsEditable); q->ui_.lbx_proxy->addItem(item); } void addProxy() { QListWidgetItem* item = new QListWidgetItem(tr("Unnamed")); addItem(item); q->ui_.lbx_proxy->reset(); // ensure that open editors won't get in our way q->ui_.lbx_proxy->setCurrentItem(item); q->ui_.lbx_proxy->editItem(item); } void removeProxy() { QListWidgetItem* item = q->ui_.lbx_proxy->takeItem(q->ui_.lbx_proxy->currentRow()); delete item; } }; ProxyDlg::ProxyDlg(const ProxyItemList &list, const QString &def, QWidget *parent) : QDialog(parent) { ui_.setupUi(this); setAttribute(Qt::WA_DeleteOnClose); d = new Private(this); d->list = list; setWindowTitle(CAP(windowTitle())); setModal(true); ui_.cb_type->addItem("HTTP \"Connect\"", "http"); ui_.cb_type->addItem("SOCKS Version 5", "socks"); ui_.cb_type->addItem("HTTP Polling", "poll"); ui_.le_host->setWhatsThis( tr("Enter the hostname and port of your proxy server.") + " " + tr("Consult your network administrator if necessary.")); ui_.le_port->setWhatsThis(ui_.le_host->whatsThis()); ui_.le_user->setWhatsThis( tr("Enter your proxy server login (username) " "or leave this field blank if the proxy server does not require it.") + " " + tr("Consult your network administrator if necessary.")); ui_.le_pass->setWhatsThis( tr("Enter your proxy server password " "or leave this field blank if the proxy server does not require it.") + " " + tr("Consult your network administrator if necessary.")); ui_.cb_type->setWhatsThis( tr("If you require a proxy server to connect, select the type of proxy here.") + " " + tr("Consult your network administrator if necessary.")); d->loadProxies(def); } ProxyDlg::~ProxyDlg() { delete d; } //---------------------------------------------------------------------------- // ProxyChooser //---------------------------------------------------------------------------- class ProxyChooser::Private { public: Private() {} QComboBox *cb_proxy; QPushButton *pb_edit; ProxyManager *m; }; ProxyChooser::ProxyChooser(ProxyManager* m, QWidget* parent) : QWidget(parent) { d = new Private; d->m = m; connect(m, SIGNAL(settingsChanged()), SLOT(pm_settingsChanged())); QHBoxLayout *hb = new QHBoxLayout(this); hb->setMargin(0); hb->setSpacing(4); d->cb_proxy = new QComboBox(this); QSizePolicy sp = d->cb_proxy->sizePolicy(); d->cb_proxy->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, d->cb_proxy->sizePolicy().verticalPolicy()) ); hb->addWidget(d->cb_proxy); d->pb_edit = new QPushButton(tr("Edit..."), this); connect(d->pb_edit, SIGNAL(clicked()), SLOT(doOpen())); hb->addWidget(d->pb_edit); buildComboBox(); } ProxyChooser::~ProxyChooser() { delete d; } QString ProxyChooser::currentItem() const { return d->cb_proxy->itemData(d->cb_proxy->currentIndex()).toString(); } void ProxyChooser::setCurrentItem(const QString &id) { int index = d->cb_proxy->findData(id); d->cb_proxy->setCurrentIndex(index == -1 ? 0 : index); } void ProxyChooser::pm_settingsChangedApply() { disconnect(d->m, SIGNAL(settingsChanged()), this, SLOT(pm_settingsChangedApply())); QString prev = currentItem(); buildComboBox(); prev = d->m->lastEdited(); int x = d->cb_proxy->findData(prev); d->cb_proxy->setCurrentIndex(x == -1 ? 0 : x); } void ProxyChooser::pm_settingsChanged() { QString prev = currentItem(); buildComboBox(); int x = d->cb_proxy->findData(prev); if(x == -1) { d->cb_proxy->setCurrentIndex(0); } else { d->cb_proxy->setCurrentIndex(x); } } void ProxyChooser::buildComboBox() { d->cb_proxy->clear(); d->cb_proxy->addItem(tr("None"), ""); ProxyItemList list = d->m->itemList(); foreach(ProxyItem pi, list) { d->cb_proxy->addItem(pi.name, pi.id); } } void ProxyChooser::doOpen() { QString x = d->cb_proxy->itemData(d->cb_proxy->currentIndex()).toString(); connect(d->m, SIGNAL(settingsChanged()), SLOT(pm_settingsChangedApply())); d->m->openDialog(x); } //---------------------------------------------------------------------------- // ProxyManager //---------------------------------------------------------------------------- class ProxyManager::Private { public: Private() {} QPointer pd; QList prevMap; QString lastEdited; OptionsTree *o; void itemToOptions(ProxyItem pi) { QString base = "proxies." + pi.id; pi.settings.toOptions( o, base); o->setOption(base + ".name", pi.name); o->setOption(base + ".type", pi.type); } }; ProxyManager::ProxyManager(OptionsTree *opt, QObject *parent) : QObject(parent) { d = new Private; d->o = opt; } ProxyManager::~ProxyManager() { delete d; } ProxyChooser *ProxyManager::createProxyChooser(QWidget *parent) { return new ProxyChooser(this, parent); } ProxyItemList ProxyManager::itemList() const { QList proxies; QString opt = "proxies"; QStringList keys = d->o->getChildOptionNames(opt, true, true); foreach(QString key, keys) { proxies += getItem(key.mid(opt.length()+1)); } return proxies; } ProxyItem ProxyManager::getItem(const QString &x) const { QString base = "proxies." + x; ProxyItem pi; pi.settings.fromOptions( d->o, base); pi.name = d->o->getOption(base + ".name").toString(); pi.type = d->o->getOption(base + ".type").toString(); pi.id = x; return pi; } QString ProxyManager::lastEdited() const { return d->lastEdited; } void ProxyManager::migrateItemList(const ProxyItemList &list) { foreach(ProxyItem pi, list) { d->itemToOptions(pi); } } void ProxyManager::openDialog(QString def) { if(d->pd) bringToFront(d->pd); else { d->pd = new ProxyDlg(itemList(), def, 0); connect(d->pd, SIGNAL(applyList(const ProxyItemList &, int)), SLOT(pd_applyList(const ProxyItemList &, int))); d->pd->show(); } } void ProxyManager::pd_applyList(const ProxyItemList &list, int x) { QSet current; QString opt = "proxies"; QStringList old = d->o->getChildOptionNames(opt, true, true); for (int i=0; i < old.size(); i++) { old[i] = old[i].mid(opt.length()+1); } // Update all int idx = 0; int i = 0; foreach(ProxyItem pi, list) { if (pi.id.isEmpty()) { do { pi.id = "a"+QString::number(idx++); } while (old.contains(pi.id) || current.contains(pi.id)); } d->itemToOptions(pi); current += pi.id; if (i++ == x) d->lastEdited = pi.id; } // and remove removed foreach(QString key, old.toSet() - current) { d->o->removeOption("proxies." + key, true); emit proxyRemoved(key); } settingsChanged(); } #include "proxy.moc" psi-0.14/src/msgmle.h0000644000175000017500000000500311305557613012563 0ustar janjan/* * msgmle.h - subclass of PsiTextView to handle various hotkeys * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MSGMLE_H #define MSGMLE_H #include #include "psitextview.h" class ChatEdit; class QEvent; class QKeyEvent; class QResizeEvent; class QTimer; class SpellHighlighter; class ChatView : public PsiTextView { Q_OBJECT public: ChatView(QWidget* parent); ~ChatView(); void setDialog(QWidget* dialog); // reimplemented QSize sizeHint() const; void appendText(const QString &text); bool handleCopyEvent(QObject *object, QEvent *event, ChatEdit *chatEdit); QString formatTimeStamp(const QDateTime &time); protected: // override the tab/esc behavior bool focusNextPrevChild(bool next); void keyPressEvent(QKeyEvent *); protected slots: void autoCopy(); private: QWidget* dialog_; }; class ChatEdit : public QTextEdit { Q_OBJECT public: ChatEdit(QWidget* parent); ~ChatEdit(); void setDialog(QWidget* dialog); // reimplemented QSize sizeHint() const; static bool checkSpellingGloballyEnabled(); void setCheckSpelling(bool); protected slots: void applySuggestion(); void addToDictionary(); void optionsChanged(); protected: // override the tab/esc behavior bool focusNextPrevChild(bool next); void keyPressEvent(QKeyEvent *); bool event(QEvent * event); void contextMenuEvent(QContextMenuEvent *e); private: QWidget *dialog_; bool check_spelling_; SpellHighlighter* spellhighlighter_; QPoint last_click_; int previous_position_; }; class LineEdit : public ChatEdit { Q_OBJECT public: LineEdit(QWidget* parent); ~LineEdit(); // reimplemented QSize minimumSizeHint() const; QSize sizeHint() const; protected: // reimplemented void resizeEvent(QResizeEvent*); private slots: void recalculateSize(); void updateScrollBar(); }; #endif psi-0.14/src/psiactionlist.cpp0000644000175000017500000004072111305557613014525 0ustar janjan/* * psiactionlist.cpp - the customizeable action list for Psi * Copyright (C) 2004 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psiactionlist.h" #include #include #include "iconset.h" #include "psioptions.h" #include "mainwin_p.h" //---------------------------------------------------------------------------- // PsiActionList::Private //---------------------------------------------------------------------------- class PsiActionList::Private : public QObject { Q_OBJECT public: Private(PsiActionList *_list, PsiCon *_psi); ~Private(); private: PsiActionList *list; PsiCon *psi; QPointer statusActionList; void createCommon(); void createMainWin(); void createMessageChatGroupchat(); void createMessageChat(); void createChatGroupchat(); void createMessage(); void createChat(); void createGroupchat(); struct ActionNames { const char *name; IconAction *action; }; ActionList* createActionList( QString name, int id, ActionNames * ); private slots: void optionsChanged(); }; PsiActionList::Private::Private(PsiActionList *_list, PsiCon *_psi) { list = _list; psi = _psi; createCommon(); createMainWin(); createMessageChatGroupchat(); createMessageChat(); createChatGroupchat(); createMessage(); createChat(); createGroupchat(); connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionsChanged())); optionsChanged(); } PsiActionList::Private::~Private() { list->clear(); } ActionList* PsiActionList::Private::createActionList( QString name, int id, ActionNames *actionlist ) { ActionList *actions = new ActionList( name, id, false ); QString aName; for ( int i = 0; !(aName = QString(actionlist[i].name)).isEmpty(); i++ ) { IconAction *action = actionlist[i].action; if (action) actions->addAction( aName, action ); } list->addList( actions ); return actions; } void PsiActionList::Private::createCommon() { IconAction *separatorAction = new SeparatorAction(this); IconAction *spacerAction = new SpacerAction(this); ActionNames actions[] = { { "separator", separatorAction }, { "spacer", spacerAction }, { "", 0 } }; createActionList( tr( "Common Actions" ), Actions_Common, actions ); } void PsiActionList::Private::createMainWin() { { IconActionGroup *viewGroups = new IconActionGroup(this); viewGroups->setText(tr("View Groups")); viewGroups->setWhatsThis(tr("Toggle visibility of special roster groups")); viewGroups->setUsesDropDown(true); viewGroups->setExclusive(false); IconAction *showOffline = new IconAction(tr("Show Offline Contacts"), "psi/show_offline", tr("Show Offline Contacts"), 0, viewGroups, 0, true); showOffline->setWhatsThis(tr("Toggles visibility of offline contacts in roster")); IconAction *showAway = new IconAction(tr("Show Away/XA/DnD Contacts"), "psi/show_away", tr("Show Away/XA/DnD Contacts"), 0, PsiOptions::instance()->getOption("options.ui.menu.view.show-away").toBool() ? (QObject*)viewGroups : (QObject*)this, 0, true); showAway->setWhatsThis(tr("Toggles visibility of away/xa/dnd contacts in roster")); IconAction *showHidden = new IconAction(tr("Show Hidden Contacts"), "psi/show_hidden", tr("Show Hidden Contacts"), 0, viewGroups, 0, true); showHidden->setWhatsThis(tr("Toggles visibility of hidden contacts in roster")); IconAction *showAgents = new IconAction(tr("Show Agents/Transports"), "psi/disco", tr("Show Agents/Transports"), 0, viewGroups, 0, true); showAgents->setWhatsThis(tr("Toggles visibility of agents/transports in roster")); IconAction *showSelf = new IconAction(tr("Show Self Contact"), "psi/show_self", tr("Show Self Contact"), 0, viewGroups, 0, true); showSelf->setWhatsThis(tr("Toggles visibility of self contact in roster")); IconAction *showStatusMsg = new IconAction(tr("Show Status Messages"), "psi/statusmsg", tr("Show Status Messages"), 0, viewGroups, 0, true); showSelf->setWhatsThis(tr("Toggles visibility of status messages of contacts")); ActionNames actions[] = { { "view_groups", viewGroups }, { "show_offline", showOffline }, { "show_away", showAway }, { "show_hidden", showHidden }, { "show_agents", showAgents }, { "show_self", showSelf }, { "show_statusmsg", showStatusMsg }, { "", 0 } }; createActionList(tr("Show Contacts"), Actions_MainWin, actions); } { PopupAction *optionsButton = new PopupAction (tr("&Psi"), 0, this, "optionsButton"); optionsButton->setWhatsThis (tr("The main Psi button, that provides access to many actions")); optionsButton->setSizePolicy ( QSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred ) ); optionsButton->setIcon ( IconsetFactory::iconPtr("psi/main"), false ); PopupAction *statusButton = new PopupAction (tr("&Status"), 0, this, "statusButton"); statusButton->setWhatsThis (tr("Provides a convenient way to change and to get information about current status")); statusButton->setSizePolicy ( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); IconAction *eventNotifier = new EventNotifierAction(this, "EventNotifierAction"); eventNotifier->setWhatsThis (tr("Special item that displays number of pending events")); ActionNames actions[] = { { "button_options", optionsButton }, { "button_status", statusButton }, { "event_notifier", eventNotifier }, { "", 0 } }; createActionList( tr( "Buttons" ), Actions_MainWin, actions ); } { IconAction *add_act = 0; if (!PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) add_act = new MAction(IconsetFactory::icon("psi/addContact"), tr("&Add a Contact"), 0, psi, this); IconAction *lw_act = new MAction(IconsetFactory::icon("psi/xml"), tr("&XML Console"), 2, psi, this); IconAction *actDisco = 0; if(!PsiOptions::instance()->getOption("options.ui.contactlist.disable-service-discovery").toBool()) actDisco = new MAction(IconsetFactory::icon("psi/disco"), tr("Service &Discovery"), 3, psi, this); // IconAction *actReadme = new IconAction (tr("ReadMe"), tr("&ReadMe"), 0, this); // actReadme->setWhatsThis (tr("Show ReadMe file")); // // IconAction *actOnlineHelp = new IconAction (tr("User Guide (Online)"), tr("User Guide (Online)"), 0, this); // actOnlineHelp->setWhatsThis (tr("User Guide (Online)")); // // IconAction *actOnlineWiki = new IconAction (tr("Wiki (Online)"), tr("Wiki (Online)"), 0, this); // actOnlineWiki->setWhatsThis (tr("Wiki (Online)")); // // IconAction *actOnlineHome = new IconAction (tr("Home Page (Online)"), tr("Home Page (Online)"), 0, this); // actOnlineHome->setWhatsThis (tr("Home Page (Online)")); // // IconAction *actBugReport = new IconAction (tr("Report a Bug"), tr("Report a &Bug"), 0, this); // actBugReport->setWhatsThis (tr("Report a Bug")); IconAction *actNewMessage = new IconAction (tr("New Blank Message"), "psi/sendMessage", tr("New &Blank Message"), 0, this); IconAction *actJoinGroupchat = new IconAction (tr("Join Groupchat"), "psi/groupChat", tr("Join &Groupchat"), 0, this); IconAction *actAccountSetup = new IconAction (tr("Account Setup"), "psi/account", tr("Acc&ount Setup"), 0, this); IconAction *actOptions = new IconAction (tr("Options"), "psi/options", tr("&Options"), 0, this); actOptions->setMenuRole(QAction::PreferencesRole); IconAction *actToolbars = new IconAction(tr("Configure Toolbars"), "psi/toolbars", tr("Configure Tool&bars"), 0, this); IconAction *actChangeProfile = new IconAction (tr("Change Profile"), "psi/profile", tr("&Change Profile"), 0, this); IconAction *actPlaySounds = new IconAction (tr("Play Sounds"), "psi/playSounds", tr("Play &Sounds"), 0, this, 0, true); actPlaySounds->setWhatsThis (tr("Toggles whether sound should be played or not")); IconAction *actQuit = new IconAction (tr("Quit"), "psi/quit", tr("&Quit"), 0, this); actQuit->setMenuRole(QAction::QuitRole); actQuit->setWhatsThis (tr("Quits Psi")); IconAction *actTip = new IconAction (tr("Tip of the Day"), "psi/tip", tr("&Tip of the Day"), 0, this); actTip->setWhatsThis (tr("See many useful tips")); // TODO: probably we want to lock down filetransfer, right? IconAction *actFileTrans = new IconAction (tr("Transfer Manager"), "psi/filemanager", tr("Trans&fer Manager"), 0, this); actFileTrans->setWhatsThis (tr("Opens the transfer manager dialog")); ActionNames actions[] = { { "menu_disco", actDisco }, { "menu_add_contact", add_act }, { "menu_new_message", actNewMessage }, { "menu_join_groupchat", actJoinGroupchat }, { "menu_account_setup", actAccountSetup }, { "menu_options", actOptions }, { "menu_file_transfer", actFileTrans }, { "menu_toolbars", actToolbars }, { "menu_xml_console", lw_act }, { "menu_change_profile", actChangeProfile }, { "menu_play_sounds", actPlaySounds }, { "menu_quit", actQuit }, { "", 0 } }; createActionList( tr( "Menu Items" ), Actions_MainWin, actions ); } #ifdef USE_PEP { IconAction *actPublishTune = new IconAction (tr("Publish Tune"), "psi/publishTune", tr("Publish &Tune"), 0, this, 0, true); actPublishTune->setWhatsThis (tr("Toggles whether the currently playing tune should be published or not")); ActionNames actions[] = { { "publish_tune", actPublishTune }, { "", 0 } }; createActionList( tr( "Publish" ), Actions_MainWin, actions ); } #endif { // status actions IconActionGroup *statusGroup = new IconActionGroup ( this ); statusGroup->setText (tr("Set Status")); statusGroup->setWhatsThis (tr("Smaller alternative to the Status button")); statusGroup->setExclusive(false); statusGroup->setUsesDropDown (true); QString setStatusStr = tr("Changes your global status to '%1'"); bool statusExl = true; IconAction *statusOnline = new IconAction (status2txt(STATUS_ONLINE), "status/online", status2txt(STATUS_ONLINE), 0, statusGroup, QString::number(STATUS_ONLINE), statusExl); statusOnline->setWhatsThis (setStatusStr.arg(tr("Online"))); IconAction *statusChat = new IconAction (status2txt(STATUS_CHAT), "status/chat", status2txt(STATUS_CHAT), 0, statusGroup, QString::number(STATUS_CHAT), true); statusChat->setWhatsThis (setStatusStr.arg(tr("Free for Chat"))); statusGroup->addSeparator(); IconAction *statusAway = new IconAction (status2txt(STATUS_AWAY), "status/away", status2txt(STATUS_AWAY), 0, statusGroup, QString::number(STATUS_AWAY), statusExl); statusAway->setWhatsThis (setStatusStr.arg(tr("Away"))); IconAction *statusXa = new IconAction (status2txt(STATUS_XA), "status/xa", status2txt(STATUS_XA), 0, statusGroup, QString::number(STATUS_XA), statusExl); statusXa->setWhatsThis (setStatusStr.arg(tr("XA"))); IconAction *statusDnd = new IconAction (status2txt(STATUS_DND), "status/dnd", status2txt(STATUS_DND), 0, statusGroup, QString::number(STATUS_DND), statusExl); statusDnd->setWhatsThis (setStatusStr.arg(tr("DND"))); statusGroup->addSeparator(); IconAction *statusInvisible = new IconAction (status2txt(STATUS_INVISIBLE), "status/invisible", status2txt(STATUS_INVISIBLE), 0, statusGroup, QString::number(STATUS_INVISIBLE), statusExl); statusInvisible->setWhatsThis (setStatusStr.arg(tr("Invisible"))); statusGroup->addSeparator(); IconAction *statusOffline = new IconAction (status2txt(STATUS_OFFLINE), "status/offline", status2txt(STATUS_OFFLINE), 0, statusGroup, QString::number(STATUS_OFFLINE), statusExl); statusOffline->setWhatsThis (setStatusStr.arg(tr("Offline"))); ActionNames actions[] = { { "status_all", statusGroup }, { "status_chat", statusChat }, { "status_online", statusOnline }, { "status_away", statusAway }, { "status_xa", statusXa }, { "status_dnd", statusDnd }, { "status_invisible", statusInvisible }, { "status_offline", statusOffline }, { "", 0 } }; statusActionList = createActionList( tr( "Status" ), Actions_MainWin, actions ); } { IconAction *actReadme = new IconAction (tr("ReadMe"), tr("&ReadMe"), 0, this); actReadme->setWhatsThis (tr("Show ReadMe file")); IconAction *actTip = new IconAction (tr("Tip of the Day"), "psi/tip", tr("&Tip of the Day"), 0, this); actTip->setWhatsThis (tr("See many useful tips")); IconAction *actOnlineHelp = new IconAction (tr("User Guide (Online)"), tr("&User Guide (Online)"), 0, this); actOnlineHelp->setWhatsThis (tr("User Guide (Online)")); IconAction *actOnlineWiki = new IconAction (tr("Wiki (Online)"), tr("&Wiki (Online)"), 0, this); actOnlineWiki->setWhatsThis (tr("Wiki (Online)")); IconAction *actOnlineHome = new IconAction (tr("Home Page (Online)"), tr("&Home Page (Online)"), 0, this); actOnlineHome->setWhatsThis (tr("Home Page (Online)")); IconAction *actOnlineForum = new IconAction (tr("Psi Forum (Online)"), tr("Psi &Forum (Online)"), 0, this); actOnlineForum->setWhatsThis (tr("Psi Forum (Online)")); IconAction *actPsiMUC = new IconAction (tr("Join Psi Discussion Room (Online)"), tr("&Join Psi Discussion Room (Online)"), 0, this); actOnlineHome->setWhatsThis (tr("Join Psi Discussion Room (Online)")); IconAction *actBugReport = new IconAction (tr("Report a Bug (Online)"), tr("Report a &Bug (Online)"), 0, this); actBugReport->setWhatsThis (tr("Report a Bug (Online)")); IconAction *actAbout = new IconAction (tr("About"), "psi/logo_16", tr("&About"), 0, this); actAbout->setMenuRole(QAction::AboutRole); IconAction *actAboutQt = new IconAction (tr("About Qt"), tr("About &Qt"), 0, this); actAboutQt->setMenuRole(QAction::AboutQtRole); IconAction *actAboutPsiMedia = new IconAction (tr("About GStreamer"), tr("About &GStreamer"), 0, this); // no role otherwise it may conflict with About Psi actAboutPsiMedia->setMenuRole(QAction::NoRole); IconAction *actDiagQCAPlugin = new IconAction (tr("Security Plugins"), tr("Security &Plugins"), 0, this); IconAction *actDiagQCAKeyStore = new IconAction (tr("Key Storage"), tr("&Key Storage"), 0, this); ActionNames actions[] = { { "help_readme", actReadme }, { "help_tip", actTip }, { "help_online_help", actOnlineHelp }, { "help_online_wiki", actOnlineWiki }, { "help_online_home", actOnlineHome }, { "help_online_forum", actOnlineForum }, { "help_psi_muc", actPsiMUC }, { "help_report_bug", actBugReport }, { "help_about", actAbout }, { "help_about_qt", actAboutQt }, { "help_about_psimedia", actAboutPsiMedia }, { "help_diag_qcaplugin", actDiagQCAPlugin }, { "help_diag_qcakeystore", actDiagQCAKeyStore }, { "", 0 } }; createActionList( tr( "Help" ), Actions_MainWin, actions ); } } void PsiActionList::Private::createMessageChatGroupchat() { } void PsiActionList::Private::createMessageChat() { } void PsiActionList::Private::createChatGroupchat() { } void PsiActionList::Private::createMessage() { } void PsiActionList::Private::createChat() { } void PsiActionList::Private::createGroupchat() { } void PsiActionList::Private::optionsChanged() { Q_ASSERT(!statusActionList.isNull()); if (statusActionList.isNull()) return; statusActionList->action("status_chat")->setVisible(PsiOptions::instance()->getOption("options.ui.menu.status.chat").toBool()); statusActionList->action("status_xa")->setVisible(PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()); statusActionList->action("status_invisible")->setVisible(PsiOptions::instance()->getOption("options.ui.menu.status.invisible").toBool()); } //---------------------------------------------------------------------------- // PsiActionList //---------------------------------------------------------------------------- PsiActionList::PsiActionList( PsiCon *psi ) { d = new Private( this, psi ); } PsiActionList::~PsiActionList() { delete d; } #include "psiactionlist.moc" psi-0.14/src/profilemanage.ui0000644000175000017500000000601211305557613014277 0ustar janjan ProfileManage 0 0 330 254 Manage Profiles 11 &Add psi/addContact &Rename Rem&ove psi/remove Qt::Vertical QSizePolicy::Expanding 20 47 QFrame::HLine QFrame::Sunken QDialogButtonBox::Close qPixmapFromMimeSource IconButton QWidget
iconbutton.h
buttonBox rejected() ProfileManage reject() 286 229 229 211
psi-0.14/src/activeprofiles_win.cpp0000644000175000017500000001775411305557613015546 0ustar janjan/* * activeprofiles_win.cpp - Class for interacting with other app instances * Copyright (C) 2006 Maciej Niedzielski * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "activeprofiles.h" #include "applicationinfo.h" #include "psicon.h" #include #include #include #include /* Implementor notes: This file uses WinAPI a lot. It is important to remember that we still want to support Win9x family. For that reason, we have to use QT_WA macro for functions that exist in two versions. Also note that writing QString("x").toLocal8Bit().constData() is a bad idea and must not be done. */ class ActiveProfiles::Private : public QWidget { public: Private(ActiveProfiles *aprof) : app(ApplicationInfo::IPCName()), home(ApplicationInfo::homeDir()), profile(""), ap(aprof), mutex(0), changesMutex(0) { app.replace('\\', '/'); // '\\' has a special meaning in mutex name home.replace('\\', '/'); const QString m = QString("%1 ChangesMutex {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app); const QString c = QString("%1 IPC Command {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app); QT_WA( changesMutex = CreateMutex(0, FALSE, (LPCWSTR)m.utf16()); psiIpcCommand = RegisterWindowMessage((LPCWSTR)c.utf16()); , QByteArray a = m.toLocal8Bit(); // must not call constData() of a temp object changesMutex = CreateMutexA(0, FALSE, (LPCSTR)a.constData()); a = c.toLocal8Bit(); psiIpcCommand = RegisterWindowMessageA((LPCSTR)a.constData()); ) if (!changesMutex) { qWarning("Couldn't create IPC mutex"); } if (!psiIpcCommand) { qWarning("Couldn't register IPC WM_message"); } } QString app, home, profile; ActiveProfiles * const ap; HANDLE mutex, changesMutex; QString mutexName(const QString &profile) const { return "ProfileMutex\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}"; } QString windowName(const QString &profile) const { return "ProfileWindow\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}"; } void startChanges() { WaitForSingleObject(changesMutex, INFINITE); } void endChanges() { ReleaseMutex(changesMutex); } void setWindowText(const QString &text) { QT_WA( SetWindowTextW(winId(), (LPCWSTR)text.utf16()); , QByteArray a = text.toLocal8Bit(); SetWindowTextA(winId(), (LPCSTR)a.constData()); ) } // WM_PSICOMMAND static UINT psiIpcCommand; // = RegisterWindowMessage() static WPARAM raiseCommand; // = 1 // WM_COPYDATA static const DWORD stringListMessage = 1; bool sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const; bool winEvent(MSG *msg, long *result); bool sendStringList(const QString &to, const QStringList &list) const; QString pickProfile() const; }; UINT ActiveProfiles::Private::psiIpcCommand = 0; WPARAM ActiveProfiles::Private::raiseCommand = 1; QString ActiveProfiles::Private::pickProfile() const { QStringList profiles = getProfilesList(); foreach (QString p, profiles) { if (ap->isActive(p)) { return p; } } return QString(); } bool ActiveProfiles::Private::sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const { QString profile = to; if (profile.isEmpty()) { profile = pickProfile(); } if (profile.isEmpty()) { return false; } HWND hwnd; QT_WA( hwnd = FindWindowW(0, (LPCWSTR)windowName(to).utf16()); , QByteArray a = windowName(to).toLocal8Bit(); hwnd = FindWindowA(0, (LPCSTR)a.constData()); ) if (!hwnd) return false; SendMessageA(hwnd, message, wParam, lParam); return true; } bool ActiveProfiles::Private::sendStringList(const QString &to, const QStringList &list) const { if (to.isEmpty()) return false; QByteArray ba; ba.append(list[0].toUtf8()); for (int i = 1; i < list.size(); ++i) { const int z = ba.size(); ba.append(" " + list[i].toUtf8()); ba[z] = '\0'; } COPYDATASTRUCT cd; cd.dwData = stringListMessage; cd.cbData = ba.size()+1; cd.lpData = (void*)ba.data(); return sendMessage(to, WM_COPYDATA, (WPARAM)winId(), (LPARAM)(LPVOID)&cd); } bool ActiveProfiles::Private::winEvent(MSG *msg, long *result) { if (msg->message == WM_COPYDATA) { *result = FALSE; COPYDATASTRUCT *cd = (COPYDATASTRUCT *)msg->lParam; if (cd->dwData == stringListMessage) { char *data = (char*)cd->lpData; const char *end = data + cd->cbData - 1; // handle this error here, not to worry later if (*end != '\0') { return true; } QStringList list; while (data < end) { QString s = QString::fromUtf8(data); list << s; data += strlen(data) + 1; } if (list.count() > 1) { if (list[0] == "openUri") { emit ap->openUriRequested(list.value(1)); *result = TRUE; } else if (list[0] == "setStatus") { emit ap->setStatusRequested(list.value(1), list.value(2)); *result = TRUE; } } } return true; } else if (msg->message == psiIpcCommand) { *result = FALSE; if (msg->wParam == raiseCommand) { emit ap->raiseRequested(); *result = TRUE; } return true; } return false; } ActiveProfiles::ActiveProfiles() : QObject(QCoreApplication::instance()) { d = new ActiveProfiles::Private(this); } ActiveProfiles::~ActiveProfiles() { delete d; d = 0; } bool ActiveProfiles::setThisProfile(const QString &profile) { if (profile == d->profile) return true; if (profile.isEmpty()) { unsetThisProfile(); return true; } d->startChanges(); HANDLE m; QT_WA( m = CreateMutexW(0, TRUE, (LPCWSTR)d->mutexName(profile).utf16()); , QByteArray a = d->mutexName(profile).toLocal8Bit(); m = CreateMutexA(0, TRUE, (LPCSTR)a.constData()); ) if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(m); d->endChanges(); return false; } else { if (d->mutex) { CloseHandle(d->mutex); } d->mutex = m; d->profile = profile; d->setWindowText(d->windowName(profile)); d->endChanges(); return true; } } void ActiveProfiles::unsetThisProfile() { d->startChanges(); CloseHandle(d->mutex); d->mutex = 0; d->profile = QString::null; d->setWindowText(""); d->endChanges(); } QString ActiveProfiles::thisProfile() const { return d->profile; } bool ActiveProfiles::isActive(const QString &profile) const { HANDLE m; QT_WA( m = OpenMutexW(0, FALSE, (LPCWSTR)d->mutexName(profile).utf16()); , QByteArray a = d->mutexName(profile).toLocal8Bit(); m = OpenMutexA(0, FALSE, (LPCSTR)a.constData()); ) if (GetLastError() == ERROR_FILE_NOT_FOUND) { return false; } else { CloseHandle(m); return true; } } bool ActiveProfiles::isAnyActive() const { return !d->pickProfile().isEmpty(); } bool ActiveProfiles::raise(const QString &profile, bool withUI) const { QLabel *lab = 0; if (withUI) { lab = new QLabel(tr("This psi profile is already running...
please wait...")); QTimer::singleShot(250, lab, SLOT(show())); } bool res = d->sendMessage(profile, d->psiIpcCommand, d->raiseCommand, 0); if (withUI) { lab->hide(); delete lab; } return res; } bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const { QStringList list; list << "openUri" << uri; return d->sendStringList(profile, list); } bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const { QStringList list; list << "setStatus" << status << message; return d->sendStringList(profile, list); } psi-0.14/src/mood.cpp0000644000175000017500000000423711305557613012600 0ustar janjan/* * mood.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "mood.h" #include "moodcatalog.h" Mood::Mood() { type_ = Unknown; } Mood::Mood(Mood::Type type, const QString& text) : type_(type), text_(text) { } Mood::Mood(const QDomElement& e) { fromXml(e); } Mood::Type Mood::type() const { return type_; } QString Mood::typeText() const { return MoodCatalog::instance()->findEntryByType(type_).text(); } const QString& Mood::text() const { return text_; } bool Mood::isNull() const { return type_ == Unknown && text().isEmpty(); } QDomElement Mood::toXml(QDomDocument& doc) { QDomElement mood = doc.createElement("mood"); mood.setAttribute("xmlns", "http://jabber.org/protocol/mood"); if (!type() == Unknown) { QDomElement el = doc.createElement(MoodCatalog::instance()->findEntryByType(type()).value()); mood.appendChild(el); } else { qWarning("mood.cpp: ERROR: Converting unknown mood"); } if (!text().isEmpty()) { QDomElement el = doc.createElement("text"); QDomText t = doc.createTextNode(text()); el.appendChild(t); mood.appendChild(el); } return mood; } void Mood::fromXml(const QDomElement& e) { if (e.tagName() != "mood") return; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement m = n.toElement(); if (m.tagName() == "text") { text_ = m.text(); } else { type_ = MoodCatalog::instance()->findEntryByValue(m.tagName()).type(); } } } psi-0.14/src/psiaccount.cpp0000644000175000017500000042120311305557613014006 0ustar janjan/* * psiaccount.cpp - handles a Psi account * Copyright (C) 2001-2005 Justin Karneges * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psiaccount.h" #include "psiiconset.h" #include "psicon.h" #include "profiles.h" #include "xmpp_tasks.h" #include "xmpp_xmlcommon.h" #include "pongserver.h" #include "s5b.h" #include "filetransfer.h" #include "pgpkeydlg.h" #include "psioptions.h" #include "textutil.h" #include "httpauthmanager.h" #include "pgputil.h" #include "applicationinfo.h" #include "pgptransaction.h" #include "accountmanagedlg.h" #include "changepwdlg.h" #include "xmlconsole.h" #include "userlist.h" #include "psievent.h" #include "jidutil.h" #include "eventdlg.h" #include "psiprivacymanager.h" #include "rosteritemexchangetask.h" #include "chatdlg.h" #include "contactview.h" #include "mood.h" #include "tune.h" #ifdef USE_PEP #include "tunecontroller.h" #endif #include "groupchatdlg.h" #include "statusdlg.h" #include "infodlg.h" #include "adduserdlg.h" #include "historydlg.h" #include "capsmanager.h" #include "registrationdlg.h" #include "searchdlg.h" #include "discodlg.h" #include "eventdb.h" #include "accountmodifydlg.h" #include "passphrasedlg.h" #include "voicecaller.h" #include "voicecalldlg.h" #ifdef HAVE_JINGLE #include "jinglevoicecaller.h" #endif #ifdef GOOGLE_FT #include "googleftmanager.h" #endif #include "pepmanager.h" #include "serverinfomanager.h" #ifdef WHITEBOARDING #include "sxe/sxemanager.h" #include "whiteboarding/wbmanager.h" #endif #include "bookmarkmanager.h" #include "vcardfactory.h" //#include "qssl.h" #include "mooddlg.h" #include "qwextend.h" #include "geolocation.h" #include "physicallocation.h" #include "psipopup.h" #include "pgputil.h" #include "translationmanager.h" #include "irisprotocol/iris_discoinfoquerier.h" #include "iconwidget.h" #include "filetransdlg.h" #include "systeminfo.h" #include "avatars.h" #include "ahcommanddlg.h" #include "mucjoindlg.h" #include "ahcservermanager.h" #include "rc.h" #include "tabdlg.h" #include "proxy.h" #include "psicontactlist.h" #include "tabmanager.h" #include "fileutil.h" #include "Certificates/CertificateHelpers.h" #include "Certificates/CertificateErrorDialog.h" #include "Certificates/CertificateDisplayDialog.h" #include "psimedia/psimedia.h" #include "avcall/avcall.h" #include "avcall/calldlg.h" #ifdef PSI_PLUGINS #include "pluginmanager.h" #endif #include #if defined(Q_WS_MAC) && defined(HAVE_GROWL) #include "psigrowlnotifier.h" #endif #include "bsocket.h" /*#ifdef Q_WS_WIN #include typedef int socklen_t; #else #include #include #endif*/ using namespace XMPP; struct GCContact { Jid jid; Status status; }; //---------------------------------------------------------------------------- // BlockTransportPopup -- blocks popups on transport status changes //---------------------------------------------------------------------------- class BlockTransportPopupList; class BlockTransportPopup : public QObject { Q_OBJECT public: BlockTransportPopup(QObject *, const Jid &); Jid jid() const; private slots: void timeout(); private: Jid j; int userCounter; friend class BlockTransportPopupList; }; BlockTransportPopup::BlockTransportPopup(QObject *parent, const Jid &_j) : QObject(parent) { j = _j; userCounter = 0; // Hack for ICQ SMS if ( j.domain().left(3) == "icq" ) { new BlockTransportPopup(parent, "sms." + j.domain()); // sms.icq.host.com new BlockTransportPopup(parent, "sms" + j.domain().right(j.domain().length() - 3)); // sms.host.com } QTimer::singleShot(15000, this, SLOT(timeout())); } void BlockTransportPopup::timeout() { if ( userCounter > 1 ) { QTimer::singleShot(15000, this, SLOT(timeout())); userCounter = 0; } else deleteLater(); } Jid BlockTransportPopup::jid() const { return j; } //---------------------------------------------------------------------------- // BlockTransportPopupList //---------------------------------------------------------------------------- class BlockTransportPopupList : public QObject { Q_OBJECT public: BlockTransportPopupList(); bool find(const Jid &, bool online = false); }; BlockTransportPopupList::BlockTransportPopupList() : QObject() { } bool BlockTransportPopupList::find(const Jid &j, bool online) { if ( j.node().isEmpty() ) // always show popups for transports return false; QList list = findChildren(); foreach(BlockTransportPopup* btp, list) { if ( j.domain() == btp->jid().domain() ) { if ( online ) btp->userCounter++; return true; } } return false; } //---------------------------------------------------------------------------- // PsiAccount //---------------------------------------------------------------------------- class PsiAccount::Private : public QObject { Q_OBJECT public: Private(PsiAccount *parent) : QObject(parent) , contactList(0) , psi(0) , account(parent) , options(0) , client(0) , cp(0) , eventQueue(0) , xmlConsole(0) , blockTransportPopupList(0) , privacyManager(0) , capsManager(0) , rosterItemExchangeTask(0) , ahcManager(0) , rcSetStatusServer(0) , rcSetOptionsServer(0) , rcForwardServer(0) , avatarFactory(0) , voiceCaller(0) , avCallManager(0) , tabManager(0) #ifdef GOOGLE_FT , googleFTManager(0) #endif #ifdef WHITEBOARDING , wbManager(0) #endif , serverInfoManager(0) , pepManager(0) , bookmarkManager(0) , httpAuthManager(0) , conn(0) , stream(0) , tls(0) , tlsHandler(0) , xmlRingbuf(1000) , xmlRingbufWrite(0) , doPopups_(true) { } PsiContactList* contactList; PsiCon *psi; PsiAccount *account; PsiOptions *options; Client *client; ContactProfile *cp; UserAccount acc; Jid jid, nextJid; Status loginStatus; bool loginWithPriority; EventQueue *eventQueue; XmlConsole *xmlConsole; UserList userList; UserListItem self; int lastIdle; bool nickFromVCard; QCA::PGPKey cur_pgpSecretKey; QList messageQueue; BlockTransportPopupList *blockTransportPopupList; int userCounter; PsiPrivacyManager* privacyManager; CapsManager* capsManager; RosterItemExchangeTask* rosterItemExchangeTask; bool pepAvailable; // Tune Tune lastTune; // Ad-hoc commands AHCServerManager* ahcManager; RCSetStatusServer* rcSetStatusServer; RCSetOptionsServer* rcSetOptionsServer; RCForwardServer* rcForwardServer; // Avatars AvatarFactory* avatarFactory; QString photoHash; // Voice Call VoiceCaller* voiceCaller; AvCallManager *avCallManager; TabManager *tabManager; #ifdef GOOGLE_FT // Google file transfer manager GoogleFTManager* googleFTManager; #endif #ifdef WHITEBOARDING // SXE SxeManager* sxeManager; // Whiteboard WbManager* wbManager; #endif // PubSub ServerInfoManager* serverInfoManager; PEPManager* pepManager; // Bookmarks BookmarkManager* bookmarkManager; // HttpAuth HttpAuthManager* httpAuthManager; QList gcbank; QStringList groupchats; QPointer conn; QPointer stream; QPointer tls; QPointer tlsHandler; bool usingSSL; QVector xmlRingbuf; int xmlRingbufWrite; QHostAddress localAddress; QString pathToProfileEvents() { return pathToProfile(activeProfile) + "/events-" + acc.name + ".xml"; } private: bool doPopups_; public: bool noPopup(ActivationType activationType) const { if (activationType == FromXml || !doPopups_) return true; if (lastManualStatus_.isAvailable()) { if (lastManualStatus_.type() == XMPP::Status::DND) return true; if ((lastManualStatus_.type() == XMPP::Status::Away || lastManualStatus_.type() == XMPP::Status::XA) && PsiOptions::instance()->getOption("options.ui.notifications.popup-dialogs.suppress-while-away").toBool()) { return true; } } return false; } public slots: void queueChanged() { eventQueue->toFile(pathToProfileEvents()); } void loadQueue() { bool soundEnabled = PsiOptions::instance()->getOption("options.ui.notifications.sounds.enable").toBool(); PsiOptions::instance()->setOption("options.ui.notifications.sounds.enable", false); // disable the sound and popups doPopups_ = false; QFileInfo fi( pathToProfileEvents() ); if ( fi.exists() ) eventQueue->fromFile(pathToProfileEvents()); PsiOptions::instance()->setOption("options.ui.notifications.sounds.enable", soundEnabled); doPopups_ = true; } void setEnabled( bool e ) { psi->contactList()->beginBulkOperation(); acc.opt_enabled = e; cp->setEnabled(e); account->cpUpdate(self); // signals account->enabledChanged(); account->updatedAccount(); psi->contactList()->endBulkOperation(); } void client_xmlIncoming(const QString &s) { xmlRingbuf[xmlRingbufWrite].type = RingXmlIn; xmlRingbuf[xmlRingbufWrite].xml = s; xmlRingbuf[xmlRingbufWrite].time = QDateTime::currentDateTime(); xmlRingbufWrite = (xmlRingbufWrite + 1) % xmlRingbuf.count(); } void client_xmlOutgoing(const QString &s) { xmlRingbuf[xmlRingbufWrite].type = RingXmlOut; xmlRingbuf[xmlRingbufWrite].xml = s; xmlRingbuf[xmlRingbufWrite].time = QDateTime::currentDateTime(); xmlRingbufWrite = (xmlRingbufWrite + 1) % xmlRingbuf.count(); } void pm_proxyRemoved(QString proxykey) { if (acc.proxyID == proxykey) acc.proxyID = ""; } void vcardChanged(const Jid &j) { // our own vcard? if(j.compare(jid, false)) { const VCard *vcard = VCardFactory::instance()->vcard(j); if(vcard) { vcardPhotoUpdate(vcard->photo()); } } } void vcardPhotoUpdate(const QByteArray &photoData) { QString newHash; if(!photoData.isEmpty()) { newHash = QCA::Hash("sha1").hashToString(photoData); } if(newHash != photoHash) { photoHash = newHash; account->setStatusDirect(loginStatus); } } private: struct item_dialog2 { QWidget *widget; Jid jid; }; QList dialogList; bool compareJids(const Jid& j1, const Jid& j2, bool compareResource) const { return j1.compare(j2, compareResource); } public: // implementation for QList PsiAccount::dumpRingbuf() QList< xmlRingElem > dumpRingbuf() { xmlRingElem el; QList< xmlRingElem > ret; for(int i=0; i < xmlRingbuf.count(); i++) { el = xmlRingbuf[(xmlRingbufWrite + 1 + i) % xmlRingbuf.count()]; if (!el.xml.isEmpty()) { ret += el; } } return ret; } QWidget* findDialog(const QMetaObject& mo, const Jid& jid, bool compareResource) const { foreach(item_dialog2* i, dialogList) { if (mo.cast(i->widget) && compareJids(i->jid, jid, compareResource)) return i->widget; } return 0; } void findDialogs(const QMetaObject& mo, const Jid& jid, bool compareResource, QList* list) const { foreach(item_dialog2* i, dialogList) { if (mo.cast(i->widget) && compareJids(i->jid, jid, compareResource)) list->append(i->widget); } } void dialogRegister(QWidget* w, const Jid& jid) { connect(w, SIGNAL(destroyed(QObject*)), SLOT(forceDialogUnregister(QObject*))); item_dialog2 *i = new item_dialog2; i->widget = w; i->jid = jid; dialogList.append(i); } void dialogUnregister(QWidget* w) { foreach(item_dialog2 *i, dialogList) { if (i->widget == w) { dialogList.removeAll(i); delete i; return; } } } void deleteDialogList() { while (!dialogList.isEmpty()) { item_dialog2* i = dialogList.takeFirst(); delete i->widget; delete i; } } private slots: void forceDialogUnregister(QObject* obj) { dialogUnregister(static_cast(obj)); } void incoming_call() { AvCall *sess = avCallManager->takeIncoming(); AvCallEvent *ae = new AvCallEvent(sess->jid().full(), sess, account); ae->setTimeStamp(QDateTime::currentDateTime()); account->handleEvent(ae, IncomingStanza); } public: enum AutoAway { AutoAway_None = 0, AutoAway_Away, AutoAway_XA, AutoAway_Offline }; void setAutoAway(AutoAway autoAway) { if (!account->isAvailable()) return; Status status = autoAwayStatus(autoAway); if (status.type() != loginStatus.type() || status.status() != loginStatus.status()) { account->setStatusDirect(status); } } void setManualStatus(Status status) { lastManualStatus_ = status; } private: Status lastManualStatus_; XMPP::Status autoAwayStatus(AutoAway autoAway) { if (!lastManualStatus_.isAway() && !lastManualStatus_.isInvisible()) { switch (autoAway) { case AutoAway_Away: return Status(XMPP::Status::Away, PsiOptions::instance()->getOption("options.status.auto-away.message").toString(), acc.priority); case AutoAway_XA: return Status(XMPP::Status::XA, PsiOptions::instance()->getOption("options.status.auto-away.message").toString(), acc.priority); case AutoAway_Offline: return Status(Status::Offline, loginStatus.status(), acc.priority); default: ; } } return lastManualStatus_; } }; PsiAccount::PsiAccount(const UserAccount &acc, PsiContactList *parent, CapsRegistry* capsRegistry, TabManager *tabManager) :QObject(parent) { d = new Private( this ); d->contactList = parent; d->tabManager = tabManager; d->psi = parent->psi(); d->options = PsiOptions::instance(); d->client = 0; d->cp = 0; d->userCounter = 0; d->avatarFactory = 0; d->voiceCaller = 0; d->blockTransportPopupList = new BlockTransportPopupList(); v_isActive = false; isDisconnecting = false; notifyOnlineOk = false; doReconnect = false; presenceSent = false; d->loginStatus = Status(Status::Offline); d->loginWithPriority = false; d->lastIdle = 0; d->setManualStatus(Status(Status::Offline, "", 0)); d->eventQueue = new EventQueue(this); connect(d->eventQueue, SIGNAL(queueChanged()), SIGNAL(queueChanged())); connect(d->eventQueue, SIGNAL(queueChanged()), d, SLOT(queueChanged())); connect(d->eventQueue, SIGNAL(eventFromXml(PsiEvent *)), SLOT(eventFromXml(PsiEvent *))); d->self = UserListItem(true); d->self.setSubscription(Subscription::Both); d->nickFromVCard = false; // we need to copy groupState, because later initialization will depend on that d->acc.groupState = acc.groupState; // stream d->conn = 0; d->tls = 0; d->tlsHandler = 0; d->stream = 0; d->usingSSL = false; // create Jabber::Client d->client = new Client; d->client->setOSName(SystemInfo::instance()->os()); d->client->setClientName(ApplicationInfo::name()); d->client->setClientVersion(ApplicationInfo::version()); d->client->setCapsNode(ApplicationInfo::capsNode()); d->client->setCapsVersion(ApplicationInfo::capsVersion()); DiscoItem::Identity identity; identity.category = "client"; identity.type = "pc"; identity.name = ApplicationInfo::name(); d->client->setIdentity(identity); QStringList features; features << "http://jabber.org/protocol/commands"; features << "http://jabber.org/protocol/rosterx"; features << "http://jabber.org/protocol/muc"; features << "jabber:x:data"; d->client->setFeatures(Features(features)); d->client->setFileTransferEnabled(true); setSendChatState(PsiOptions::instance()->getOption("options.messages.send-composing-events").toBool()); //connect(d->client, SIGNAL(connected()), SLOT(client_connected())); //connect(d->client, SIGNAL(handshaken()), SLOT(client_handshaken())); //connect(d->client, SIGNAL(error(const StreamError &)), SLOT(client_error(const StreamError &))); //connect(d->client, SIGNAL(sslCertReady(const QSSLCert &)), SLOT(client_sslCertReady(const QSSLCert &))); //connect(d->client, SIGNAL(closeFinished()), SLOT(client_closeFinished())); //connect(d->client, SIGNAL(authFinished(bool, int, const QString &)), SLOT(client_authFinished(bool, int, const QString &))); connect(d->client, SIGNAL(rosterRequestFinished(bool, int, const QString &)), SLOT(client_rosterRequestFinished(bool, int, const QString &))); connect(d->client, SIGNAL(rosterItemAdded(const RosterItem &)), SLOT(client_rosterItemAdded(const RosterItem &))); connect(d->client, SIGNAL(rosterItemAdded(const RosterItem &)), SLOT(client_rosterItemUpdated(const RosterItem &))); connect(d->client, SIGNAL(rosterItemUpdated(const RosterItem &)), SLOT(client_rosterItemUpdated(const RosterItem &))); connect(d->client, SIGNAL(rosterItemRemoved(const RosterItem &)), SLOT(client_rosterItemRemoved(const RosterItem &))); connect(d->client, SIGNAL(resourceAvailable(const Jid &, const Resource &)), SLOT(client_resourceAvailable(const Jid &, const Resource &))); connect(d->client, SIGNAL(resourceUnavailable(const Jid &, const Resource &)), SLOT(client_resourceUnavailable(const Jid &, const Resource &))); connect(d->client, SIGNAL(presenceError(const Jid &, int, const QString &)), SLOT(client_presenceError(const Jid &, int, const QString &))); connect(d->client, SIGNAL(messageReceived(const Message &)), SLOT(client_messageReceived(const Message &))); connect(d->client, SIGNAL(subscription(const Jid &, const QString &, const QString&)), SLOT(client_subscription(const Jid &, const QString &, const QString&))); connect(d->client, SIGNAL(debugText(const QString &)), SLOT(client_debugText(const QString &))); connect(d->client, SIGNAL(groupChatJoined(const Jid &)), SLOT(client_groupChatJoined(const Jid &))); connect(d->client, SIGNAL(groupChatLeft(const Jid &)), SLOT(client_groupChatLeft(const Jid &))); connect(d->client, SIGNAL(groupChatPresence(const Jid &, const Status &)), SLOT(client_groupChatPresence(const Jid &, const Status &))); connect(d->client, SIGNAL(groupChatError(const Jid &, int, const QString &)), SLOT(client_groupChatError(const Jid &, int, const QString &))); connect(d->client->fileTransferManager(), SIGNAL(incomingReady()), SLOT(client_incomingFileTransfer())); connect(d->client, SIGNAL(xmlIncoming(const QString &)), d, SLOT(client_xmlIncoming(const QString &))); connect(d->client, SIGNAL(xmlOutgoing(const QString &)), d, SLOT(client_xmlOutgoing(const QString &))); // Privacy manager d->privacyManager = new PsiPrivacyManager(d->client->rootTask()); // Caps manager d->capsManager = new CapsManager(d->client->jid(), capsRegistry, new IrisProtocol::DiscoInfoQuerier(d->client)); d->capsManager->setEnabled(PsiOptions::instance()->getOption("options.service-discovery.enable-entity-capabilities").toBool()); // Roster item exchange task d->rosterItemExchangeTask = new RosterItemExchangeTask(d->client->rootTask()); connect(d->rosterItemExchangeTask,SIGNAL(rosterItemExchange(const Jid&, const RosterExchangeItems&)),SLOT(actionRecvRosterExchange(const Jid&,const RosterExchangeItems&))); // contactprofile context d->cp = new ContactProfile(this, acc.name, d->psi->contactView()); connect(d->cp, SIGNAL(actionDefault(const Jid &)),SLOT(actionDefault(const Jid &))); connect(d->cp, SIGNAL(actionRecvEvent(const Jid &)),SLOT(actionRecvEvent(const Jid &))); connect(d->cp, SIGNAL(actionSendMessage(const Jid &)),SLOT(actionSendMessage(const Jid &))); connect(d->cp, SIGNAL(actionSendMessage(const QList &)),SLOT(actionSendMessage(const QList &))); connect(d->cp, SIGNAL(actionSendUrl(const Jid &)),SLOT(actionSendUrl(const Jid &))); connect(d->cp, SIGNAL(actionRemove(const Jid &)),SLOT(actionRemove(const Jid &))); connect(d->cp, SIGNAL(actionRename(const Jid &, const QString &)),SLOT(actionRename(const Jid &, const QString &))); connect(d->cp, SIGNAL(actionGroupRename(const QString &, const QString &)),SLOT(actionGroupRename(const QString &, const QString &))); connect(d->cp, SIGNAL(actionHistory(const Jid &)),SLOT(actionHistory(const Jid &))); connect(d->cp, SIGNAL(actionOpenChat(const Jid &)),SLOT(actionOpenChat(const Jid &))); connect(d->cp, SIGNAL(actionOpenChatSpecific(const Jid &)),SLOT(actionOpenChatSpecific(const Jid &))); #ifdef WHITEBOARDING connect(d->cp, SIGNAL(actionOpenWhiteboard(const Jid &)),SLOT(actionOpenWhiteboard(const Jid &))); connect(d->cp, SIGNAL(actionOpenWhiteboardSpecific(const Jid &)),SLOT(actionOpenWhiteboardSpecific(const Jid &))); #endif connect(d->cp, SIGNAL(actionAgentSetStatus(const Jid &, Status &)),SLOT(actionAgentSetStatus(const Jid &, Status &))); connect(d->cp, SIGNAL(actionInfo(const Jid &)),SLOT(actionInfo(const Jid &))); connect(d->cp, SIGNAL(actionAuth(const Jid &)),SLOT(actionAuth(const Jid &))); connect(d->cp, SIGNAL(actionAuthRequest(const Jid &)),SLOT(actionAuthRequest(const Jid &))); connect(d->cp, SIGNAL(actionAuthRemove(const Jid &)),SLOT(actionAuthRemove(const Jid &))); connect(d->cp, SIGNAL(actionAdd(const Jid &)),SLOT(actionAdd(const Jid &))); connect(d->cp, SIGNAL(actionGroupAdd(const Jid &, const QString &)),SLOT(actionGroupAdd(const Jid &, const QString &))); connect(d->cp, SIGNAL(actionGroupRemove(const Jid &, const QString &)),SLOT(actionGroupRemove(const Jid &, const QString &))); connect(d->cp, SIGNAL(actionVoice(const Jid &)),SLOT(actionVoice(const Jid &))); connect(d->cp, SIGNAL(actionSendFile(const Jid &)),SLOT(actionSendFile(const Jid &))); connect(d->cp, SIGNAL(actionSendFiles(const Jid &, const QStringList&)),SLOT(actionSendFiles(const Jid &, const QStringList&))); connect(d->cp, SIGNAL(actionExecuteCommand(const Jid &, const QString&)),SLOT(actionExecuteCommand(const Jid &, const QString&))); connect(d->cp, SIGNAL(actionExecuteCommandSpecific(const Jid &, const QString&)),SLOT(actionExecuteCommandSpecific(const Jid &, const QString&))); connect(d->cp, SIGNAL(actionSetMood()),SLOT(actionSetMood())); connect(d->cp, SIGNAL(actionSetAvatar()),SLOT(actionSetAvatar())); connect(d->cp, SIGNAL(actionUnsetAvatar()),SLOT(actionUnsetAvatar())); connect(d->cp, SIGNAL(actionDisco(const Jid &, const QString &)),SLOT(actionDisco(const Jid &, const QString &))); connect(d->cp, SIGNAL(actionInvite(const Jid &, const QString &)),SLOT(actionInvite(const Jid &, const QString &))); connect(d->cp, SIGNAL(actionAssignKey(const Jid &)),SLOT(actionAssignKey(const Jid &))); connect(d->cp, SIGNAL(actionUnassignKey(const Jid &)),SLOT(actionUnassignKey(const Jid &))); // Initialize server info stuff d->serverInfoManager = new ServerInfoManager(d->client); connect(d->serverInfoManager,SIGNAL(featuresChanged()),SLOT(serverFeaturesChanged())); // XMPP Ping new PongServer(d->client->rootTask()); // Initialize PubSub stuff d->pepManager = new PEPManager(d->client, d->serverInfoManager); connect(d->pepManager,SIGNAL(itemPublished(const Jid&, const QString&, const PubSubItem&)),SLOT(itemPublished(const Jid&, const QString&, const PubSubItem&))); connect(d->pepManager,SIGNAL(itemRetracted(const Jid&, const QString&, const PubSubRetraction&)),SLOT(itemRetracted(const Jid&, const QString&, const PubSubRetraction&))); d->pepAvailable = false; #ifdef WHITEBOARDING // Initialize SXE manager d->sxeManager = new SxeManager(d->client, this); // Initialize Whiteboard manager d->wbManager = new WbManager(d->client, this, d->sxeManager); #endif // Avatars d->avatarFactory = new AvatarFactory(this); d->self.setAvatarFactory(avatarFactory()); connect(VCardFactory::instance(), SIGNAL(vcardChanged(const Jid&)), d, SLOT(vcardChanged(const Jid&))); // Bookmarks d->bookmarkManager = new BookmarkManager(this); connect(d->bookmarkManager, SIGNAL(availabilityChanged()), SLOT(bookmarksAvailabilityChanged())); #ifdef USE_PEP // Tune Controller connect(d->psi->tuneController(), SIGNAL(stopped()), SLOT(tuneStopped())); connect(d->psi->tuneController(), SIGNAL(playing(const Tune&)),SLOT(tunePlaying(const Tune&))); #endif // HttpAuth d->httpAuthManager = new HttpAuthManager(d->client->rootTask()); connect(d->httpAuthManager, SIGNAL(confirmationRequest(const PsiHttpAuthRequest &)), SLOT(incomingHttpAuthRequest(const PsiHttpAuthRequest &))); // Initialize Adhoc Commands server d->ahcManager = new AHCServerManager(this); d->rcSetStatusServer = 0; d->rcSetOptionsServer = 0; d->rcForwardServer = 0; setRCEnabled(PsiOptions::instance()->getOption("options.external-control.adhoc-remote-control.enable").toBool()); // Plugins #ifdef PSI_PLUGINS PluginManager::instance()->addAccount(this, d->client); #endif // HTML if(PsiOptions::instance()->getOption("options.html.chat.render").toBool()) d->client->addExtension("html",Features("http://jabber.org/protocol/xhtml-im")); // restore cached roster for(Roster::ConstIterator it = acc.roster.begin(); it != acc.roster.end(); ++it) client_rosterItemUpdated(*it); // restore pgp key bindings for(VarList::ConstIterator kit = acc.keybind.begin(); kit != acc.keybind.end(); ++kit) { const VarListItem &i = *kit; UserListItem *u = find(Jid(i.key())); if(u) { u->setPublicKeyID(i.data()); cpUpdate(*u); } } setUserAccount(acc); connect(d->psi->proxy(), SIGNAL(proxyRemoved(QString)), d, SLOT(pm_proxyRemoved(QString))); d->contactList->link(this); connect(d->psi, SIGNAL(emitOptionsUpdate()), SLOT(optionsUpdate())); //connect(d->psi, SIGNAL(pgpToggled(bool)), SLOT(pgpToggled(bool))); connect(&PGPUtil::instance(), SIGNAL(pgpKeysUpdated()), SLOT(pgpKeysUpdated())); d->setEnabled(d->acc.opt_enabled); // Listen to the capabilities manager connect(capsManager(),SIGNAL(capsChanged(const Jid&)),SLOT(capsChanged(const Jid&))); //printf("PsiAccount: [%s] loaded\n", name().latin1()); d->xmlConsole = new XmlConsole(this); if(PsiOptions::instance()->getOption("options.xml-console.enable-at-login").toBool() && d->acc.opt_enabled) { this->showXmlConsole(); d->xmlConsole->enable(); } // Voice Calling #ifdef HAVE_JINGLE d->voiceCaller = new JingleVoiceCaller(this); #endif if (d->voiceCaller) { d->client->addExtension("voice-v1", Features(QString("http://www.google.com/xmpp/protocol/voice/v1"))); connect(d->voiceCaller,SIGNAL(incoming(const Jid&)),SLOT(incomingVoiceCall(const Jid&))); } #ifdef GOOGLE_FT d->googleFTManager = new GoogleFTManager(client()); d->client->addExtension("share-v1", Features(QString("http://www.google.com/xmpp/protocol/share/v1"))); connect(d->googleFTManager,SIGNAL(incomingFileTransfer(GoogleFileTransfer*)),SLOT(incomingGoogleFileTransfer(GoogleFileTransfer*))); #endif if(AvCallManager::isSupported()) { d->avCallManager = new AvCallManager(this); connect(d->avCallManager, SIGNAL(incomingReady()), d, SLOT(incoming_call())); QStringList features; features << "urn:xmpp:jingle:1"; features << "urn:xmpp:jingle:transports:ice-udp:1"; features << "urn:xmpp:jingle:apps:rtp:1"; features << "urn:xmpp:jingle:apps:rtp:audio"; d->client->addExtension("ca", Features(features)); if(AvCallManager::isVideoSupported()) { features.clear(); features << "urn:xmpp:jingle:apps:rtp:video"; d->client->addExtension("cv", Features(features)); } d->avCallManager->setStunHost(acc.stunHost, acc.stunPort); } // Extended presence if (d->options->getOption("options.extended-presence.notify").toBool()) { QStringList pepNodes; pepNodes += "http://jabber.org/protocol/mood+notify"; pepNodes += "http://jabber.org/protocol/tune+notify"; pepNodes += "http://jabber.org/protocol/physloc+notify"; pepNodes += "http://jabber.org/protocol/geoloc+notify"; pepNodes += "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata+notify"; d->client->addExtension("ep-notify",Features(pepNodes)); } // load event queue from disk QTimer::singleShot(0, d, SLOT(loadQueue())); } PsiAccount::~PsiAccount() { // nuke all related dialogs deleteAllDialogs(); logout(true); QString str = name(); while (!d->messageQueue.isEmpty()) delete d->messageQueue.takeFirst(); d->psi->ftdlg()->killTransfers(this); delete d->avCallManager; if (d->voiceCaller) delete d->voiceCaller; delete d->ahcManager; delete d->cp; delete d->privacyManager; delete d->capsManager; delete d->pepManager; delete d->serverInfoManager; #ifdef WHITEBOARDING delete d->wbManager; delete d->sxeManager; #endif delete d->bookmarkManager; delete d->client; delete d->httpAuthManager; cleanupStream(); delete d->eventQueue; delete d->avatarFactory; delete d->blockTransportPopupList; d->contactList->unlink(this); delete d; //printf("PsiAccount: [%s] unloaded\n", str.latin1()); } void PsiAccount::cleanupStream() { delete d->stream; d->stream = 0; delete d->tls; d->tls = 0; d->tlsHandler = 0; delete d->conn; d->conn = 0; d->usingSSL = false; d->localAddress = QHostAddress(); } bool PsiAccount::enabled() const { return d->acc.opt_enabled; } void PsiAccount::setEnabled(bool e) { if ( d->acc.opt_enabled == e ) return; if (!e) { if (eventQueue()->count()) { QMessageBox::information(0, tr("Error"), tr("Unable to disable the account, as it has pending events.")); return; } if (isActive()) { if (QMessageBox::information(0, tr("Disable Account"), tr("The account is currently active.\nDo you want to log out ?"),QMessageBox::Yes,QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton) == QMessageBox::Yes) { logout(); } else { return; } } } d->setEnabled( e ); } bool PsiAccount::isActive() const { return v_isActive; } bool PsiAccount::isConnected() const { return (d->stream && d->stream->isAuthenticated()); } /** * This function returns true when the account is connected to the server, * authenticated and is not currently trying to disconnect. */ bool PsiAccount::isAvailable() const { return isConnected() && isActive() && loggedIn(); } const QString & PsiAccount::name() const { return d->acc.name; } // FIXME: we should move all PsiAccount::userAccount() users to PsiAccount::accountOptions() const UserAccount & PsiAccount::userAccount() const { // save the roster and pgp key bindings d->acc.roster.clear(); d->acc.keybind.clear(); foreach(UserListItem* u, d->userList) { if(u->inList()) d->acc.roster += *u; if(!u->publicKeyID().isEmpty()) d->acc.keybind.set(u->jid().full(), u->publicKeyID()); } return d->acc; } UserAccount PsiAccount::accountOptions() const { return d->acc; } UserList *PsiAccount::userList() const { return &d->userList; } Client *PsiAccount::client() const { return d->client; } ContactProfile *PsiAccount::contactProfile() const { return d->cp; } EventQueue *PsiAccount::eventQueue() const { return d->eventQueue; } EDB *PsiAccount::edb() const { return d->psi->edb(); } PsiCon *PsiAccount::psi() const { return d->psi; } AvatarFactory *PsiAccount::avatarFactory() const { return d->avatarFactory; } VoiceCaller* PsiAccount::voiceCaller() const { return d->voiceCaller; } PrivacyManager* PsiAccount::privacyManager() const { return d->privacyManager; } CapsManager* PsiAccount::capsManager() const { return d->capsManager; } bool PsiAccount::hasPGP() const { return !d->cur_pgpSecretKey.isNull(); } QHostAddress *PsiAccount::localAddress() const { QString s = d->localAddress.toString(); if (s.isEmpty() || s == "0.0.0.0") return 0; return &d->localAddress; } void PsiAccount::setUserAccount(const UserAccount &acc) { bool renamed = false; QString oldfname; if(d->acc.name != acc.name) { renamed = true; oldfname = d->pathToProfileEvents(); } d->acc = acc; // rename queue file? if(renamed) { QFileInfo oldfi(oldfname); QFileInfo newfi(d->pathToProfileEvents()); if(oldfi.exists()) { QDir dir = oldfi.dir(); dir.rename(oldfi.fileName(), newfi.fileName()); } } if(d->stream) { if(d->acc.opt_keepAlive) d->stream->setNoopTime(55000); // prevent NAT timeouts every minute else d->stream->setNoopTime(0); } d->cp->setName(d->acc.name); Jid j = acc.jid; d->nextJid = j; if(!isActive()) { d->jid = j; d->self.setJid(j); d->cp->updateEntry(d->self); } if(!d->nickFromVCard) setNick(j.node()); QString pgpSecretKeyID = (d->acc.pgpSecretKey.isNull() ? "" : d->acc.pgpSecretKey.keyId()); d->self.setPublicKeyID(pgpSecretKeyID); if(PGPUtil::instance().pgpAvailable()) { bool updateStatus = !PGPUtil::instance().equals(d->acc.pgpSecretKey, d->cur_pgpSecretKey) && loggedIn(); d->cur_pgpSecretKey = d->acc.pgpSecretKey; pgpKeyChanged(); if (updateStatus) { d->loginStatus.setXSigned(""); setStatusDirect(d->loginStatus); } } if(d->avCallManager) d->avCallManager->setStunHost(d->acc.stunHost, d->acc.stunPort); cpUpdate(d->self); updatedAccount(); } void PsiAccount::deleteQueueFile() { QFileInfo fi(d->pathToProfileEvents()); if(fi.exists()) { QDir dir = fi.dir(); dir.remove(fi.fileName()); } } const Jid & PsiAccount::jid() const { return d->jid; } QString PsiAccount::nameWithJid() const { return (name() + " (" + JIDUtil::toString(jid(),true) + ')'); } // Moved out of constructor to have all accounts loaded // when we ask for passwords. void PsiAccount::autoLogin() { // auto-login ? if (d->acc.opt_enabled) { bool autoLogin = d->acc.opt_auto; if (autoLogin) { setStatus(Status(Status::Online, "", d->acc.priority)); } } } // logs on with the active account settings void PsiAccount::login() { if(isActive() && !doReconnect) return; if((d->acc.ssl == UserAccount::SSL_Yes || d->acc.ssl == UserAccount::SSL_Legacy) && !QCA::isSupported("tls")) { QMessageBox::information(0, (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("Encryption Error"), tr("Cannot connect: Encryption is enabled but no QCA2 SSL/TLS plugin is available.")); return; } d->jid = d->nextJid; v_isActive = true; isDisconnecting = false; notifyOnlineOk = false; rosterDone = false; presenceSent = false; stateChanged(); bool useHost = false; QString host; int port = -1; if(d->acc.opt_host) { useHost = true; host = d->acc.host; if (host.isEmpty()) { host = d->jid.domain(); } port = d->acc.port; } AdvancedConnector::Proxy p; if(!d->acc.proxyID.isEmpty()) { const ProxyItem &pi = d->psi->proxy()->getItem(d->acc.proxyID); if(pi.type == "http") // HTTP Connect p.setHttpConnect(pi.settings.host, pi.settings.port); else if(pi.type == "socks") // SOCKS p.setSocks(pi.settings.host, pi.settings.port); else if(pi.type == "poll") { // HTTP Poll QUrl u = pi.settings.url; if(u.queryItems().isEmpty()) { if (useHost) u.addQueryItem("server",host + ':' + QString::number(port)); else u.addQueryItem("server",d->jid.domain()); } p.setHttpPoll(pi.settings.host, pi.settings.port, u.toString()); p.setPollInterval(2); } if(pi.settings.useAuth) p.setUserPass(pi.settings.user, pi.settings.pass); } // stream d->conn = new AdvancedConnector; if(d->acc.ssl != UserAccount::SSL_No && QCA::isSupported("tls")) { d->tls = new QCA::TLS; d->tls->setTrustedCertificates(CertificateHelpers::allCertificates(ApplicationInfo::getCertificateStoreDirs())); d->tlsHandler = new QCATLSHandler(d->tls); d->tlsHandler->setXMPPCertCheck(true); connect(d->tlsHandler, SIGNAL(tlsHandshaken()), SLOT(tls_handshaken())); } d->conn->setProxy(p); if (useHost) { d->conn->setOptHostPort(host, port); d->conn->setOptSSL(d->acc.ssl == UserAccount::SSL_Legacy); } else if (QCA::isSupported("tls")) { d->conn->setOptProbe(d->acc.legacy_ssl_probe && d->acc.ssl != UserAccount::SSL_No); } d->stream = new ClientStream(d->conn, d->tlsHandler); d->stream->setRequireMutualAuth(d->acc.req_mutual_auth); d->stream->setSSFRange(d->acc.security_level,256); d->stream->setAllowPlain(d->acc.allow_plain); d->stream->setCompress(d->acc.opt_compress); d->stream->setLang(TranslationManager::instance()->currentXMLLanguage()); if(d->acc.opt_keepAlive) d->stream->setNoopTime(55000); // prevent NAT timeouts every minute else d->stream->setNoopTime(0); connect(d->stream, SIGNAL(connected()), SLOT(cs_connected())); connect(d->stream, SIGNAL(securityLayerActivated(int)), SLOT(cs_securityLayerActivated(int))); connect(d->stream, SIGNAL(needAuthParams(bool, bool, bool)), SLOT(cs_needAuthParams(bool, bool, bool))); connect(d->stream, SIGNAL(authenticated()), SLOT(cs_authenticated())); connect(d->stream, SIGNAL(connectionClosed()), SLOT(cs_connectionClosed()), Qt::QueuedConnection); connect(d->stream, SIGNAL(delayedCloseFinished()), SLOT(cs_delayedCloseFinished())); connect(d->stream, SIGNAL(warning(int)), SLOT(cs_warning(int))); connect(d->stream, SIGNAL(error(int)), SLOT(cs_error(int)), Qt::QueuedConnection); Jid j = d->jid.withResource((d->acc.opt_automatic_resource ? localHostName() : d->acc.resource )); d->client->connectToServer(d->stream, j); } // disconnect or stop reconnecting void PsiAccount::logout(bool fast, const Status &s) { if(!isActive()) return; // cancel reconnect doReconnect = false; if(loggedIn()) { // Extended Presence if (d->options->getOption("options.extended-presence.tune.publish").toBool() && !d->lastTune.isNull()) publishTune(Tune()); d->client->removeExtension("ep"); d->client->removeExtension("pep"); // send logout status d->client->setPresence(s); } isDisconnecting = true; if(!fast) simulateRosterOffline(); v_isActive = false; d->loginStatus = Status(Status::Offline); stateChanged(); // Using 100msecs; See note on disconnect() QTimer::singleShot(100, this, SLOT(disconnect())); } // skz note: I had to split logout() because server seem to need some time to store status // before stream is closed (weird, I know) void PsiAccount::disconnect() { if (isDisconnecting) { // disconnect d->client->close(); cleanupStream(); disconnected(); } } bool PsiAccount::loggedIn() const { return (v_isActive && presenceSent); } void PsiAccount::tls_handshaken() { if (CertificateHelpers::checkCertificate(d->tls, d->tlsHandler, d->acc.tlsOverrideDomain, d->acc.tlsOverrideCert, this, (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("Server Authentication"), d->jid.domain())) { d->tlsHandler->continueAfterHandshake(); } else { logout(); } } void PsiAccount::showCert() { if (!d->tls || !d->tls->isHandshaken()) return; QCA::Certificate cert = d->tls->peerCertificateChain().primary(); int r = d->tls->peerIdentityResult(); if (r == QCA::TLS::Valid && !d->tlsHandler->certMatchesHostname()) r = QCA::TLS::HostMismatch; QCA::Validity validity = d->tls->peerCertificateValidity(); CertificateDisplayDialog dlg(cert, r, validity); dlg.exec(); } void PsiAccount::cs_connected() { // get IP address ByteStream *bs = d->conn ? d->conn->stream() : 0; if (!bs) return; if(bs->inherits("BSocket") || bs->inherits("XMPP::BSocket")) { d->localAddress = ((BSocket *)bs)->address(); if(d->avCallManager) d->avCallManager->setSelfAddress(d->localAddress); } } void PsiAccount::cs_securityLayerActivated(int layer) { if ((layer == ClientStream::LayerSASL) && (d->stream->saslSSF() <= 1)) { // integrity protected only } else { d->usingSSL = true; stateChanged(); } } void PsiAccount::cs_needAuthParams(bool user, bool pass, bool realm) { if(user) { if (d->acc.customAuth && !d->acc.authid.isEmpty()) d->stream->setUsername(d->acc.authid); else d->stream->setUsername(d->jid.node()); } else if (d->acc.customAuth && !d->acc.authid.isEmpty()) qWarning("Custom authentication user not used"); if(pass) d->stream->setPassword(d->acc.pass); if (realm) { if (d->acc.customAuth && !d->acc.realm.isEmpty()) { d->stream->setRealm(d->acc.realm); } else { d->stream->setRealm(d->jid.domain()); } } else if (d->acc.customAuth && !d->acc.realm.isEmpty()) qWarning("Custom authentication realm not used"); if(d->acc.customAuth) d->stream->setAuthzid(d->jid.bare()); d->stream->continueAfterParams(); } void PsiAccount::cs_authenticated() { //printf("PsiAccount: [%s] authenticated\n", name().latin1()); d->conn->changePollInterval(10); // for http poll, slow down after login // Update our jid (if necessary) if (!d->stream->jid().isEmpty()) { d->jid = d->stream->jid().bare(); } QString resource = (d->stream->jid().resource().isEmpty() ? ( d->acc.opt_automatic_resource ? localHostName() : d->acc.resource) : d->stream->jid().resource()); d->client->start(d->jid.domain(), d->jid.node(), d->acc.pass, resource); if (!d->stream->old()) { JT_Session *j = new JT_Session(d->client->rootTask()); connect(j,SIGNAL(finished()),SLOT(sessionStart_finished())); j->go(true); } else { sessionStarted(); } } void PsiAccount::sessionStart_finished() { JT_Session *j = (JT_Session*)sender(); if ( j->success() ) { sessionStarted(); } else { cs_error(-1); } } void PsiAccount::sessionStarted() { if (d->voiceCaller) d->voiceCaller->initialize(); // flag roster for delete foreach(UserListItem* u, d->userList) { if(u->inList()) u->setFlagForDelete(true); } // ask for roster d->client->rosterRequest(); } void PsiAccount::cs_connectionClosed() { cs_error(-1); } void PsiAccount::cs_delayedCloseFinished() { //printf("PsiAccount: [%s] connection closed\n", name().latin1()); } void PsiAccount::cs_warning(int w) { bool showNoTlsWarning = w == ClientStream::WarnNoTLS && d->acc.ssl == UserAccount::SSL_Yes; bool doCleanupStream = !d->stream || showNoTlsWarning; if (doCleanupStream) { d->client->close(); cleanupStream(); v_isActive = false; d->loginStatus = Status(Status::Offline); stateChanged(); disconnected(); } if (showNoTlsWarning) { QMessageBox* m = new QMessageBox(QMessageBox::Critical, (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("Server Error"), tr("The server does not support TLS encryption."), QMessageBox::Ok, 0); m->setAttribute(Qt::WA_DeleteOnClose, true); m->setModal(true); m->show(); } else if (!doCleanupStream) { Q_ASSERT(d->stream); d->stream->continueAfterWarning(); } } void PsiAccount::getErrorInfo(int err, AdvancedConnector *conn, Stream *stream, QCATLSHandler *tlsHandler, QString *_str, bool *_reconn) { QString str; bool reconn = false; if(err == -1) { str = tr("Disconnected"); reconn = true; } else if(err == XMPP::ClientStream::ErrParse) { str = tr("XML Parsing Error"); reconn = true; } else if(err == XMPP::ClientStream::ErrProtocol) { str = tr("XMPP Protocol Error"); reconn = true; } else if(err == XMPP::ClientStream::ErrStream) { int x; QString s, detail; reconn = true; if (stream) { // Stream can apparently be gone if you disconnect in time x = stream->errorCondition(); detail = stream->errorText(); } else { x = XMPP::Stream::GenericStreamError; reconn = false; } if(x == XMPP::Stream::GenericStreamError) s = tr("Generic stream error"); else if(x == XMPP::ClientStream::Conflict) { s = tr("Conflict (remote login replacing this one)"); reconn = false; } else if(x == XMPP::ClientStream::ConnectionTimeout) s = tr("Timed out from inactivity"); else if(x == XMPP::ClientStream::InternalServerError) s = tr("Internal server error"); else if(x == XMPP::ClientStream::InvalidXml) s = tr("Invalid XML"); else if(x == XMPP::ClientStream::PolicyViolation) { s = tr("Policy violation"); reconn = false; } else if(x == XMPP::ClientStream::ResourceConstraint) { s = tr("Server out of resources"); reconn = false; } else if(x == XMPP::ClientStream::SystemShutdown) { s = tr("Server is shutting down"); } str = tr("XMPP Stream Error: %1").arg(s) + "\n" + detail; } else if(err == XMPP::ClientStream::ErrConnection) { int x = conn->errorCode(); QString s; reconn = true; if(x == XMPP::AdvancedConnector::ErrConnectionRefused) s = tr("Unable to connect to server"); else if(x == XMPP::AdvancedConnector::ErrHostNotFound) s = tr("Host not found"); else if(x == XMPP::AdvancedConnector::ErrProxyConnect) s = tr("Error connecting to proxy"); else if(x == XMPP::AdvancedConnector::ErrProxyNeg) s = tr("Error during proxy negotiation"); else if(x == XMPP::AdvancedConnector::ErrProxyAuth) { s = tr("Proxy authentication failed"); reconn = false; } else if(x == XMPP::AdvancedConnector::ErrStream) s = tr("Socket/stream error"); str = tr("Connection Error: %1").arg(s); } else if(err == XMPP::ClientStream::ErrNeg) { QString s, detail; int x = stream->errorCondition(); detail = stream->errorText(); if(x == XMPP::ClientStream::HostGone) s = tr("Host no longer hosted"); else if(x == XMPP::ClientStream::HostUnknown) s = tr("Host unknown"); else if(x == XMPP::ClientStream::RemoteConnectionFailed) { s = tr("A required remote connection failed"); reconn = true; } else if(x == XMPP::ClientStream::SeeOtherHost) s = tr("See other host: %1").arg(stream->errorText()); else if(x == XMPP::ClientStream::UnsupportedVersion) s = tr("Server does not support proper XMPP version"); str = tr("Stream Negotiation Error: %1").arg(s) + "\n" + detail; } else if(err == XMPP::ClientStream::ErrTLS) { int x = stream->errorCondition(); QString s; if(x == XMPP::ClientStream::TLSStart) s = tr("Server rejected STARTTLS"); else if(x == XMPP::ClientStream::TLSFail) { int t = tlsHandler->tlsError(); if(t == QCA::TLS::ErrorHandshake) s = tr("TLS handshake error"); else s = tr("Broken security layer (TLS)"); } str = s; } else if(err == XMPP::ClientStream::ErrAuth) { int x = stream->errorCondition(); QString s; if(x == XMPP::ClientStream::GenericAuthError) { s = tr("Unable to login"); } else if(x == XMPP::ClientStream::NoMech) { s = tr("No appropriate mechanism available for given security settings (e.g. SASL library too weak, or plaintext authentication not enabled)"); s += "\n" + stream->errorText(); } else if(x == XMPP::ClientStream::BadProto) { s = tr("Bad server response"); } else if(x == XMPP::ClientStream::BadServ) { s = tr("Server failed mutual authentication"); } else if(x == XMPP::ClientStream::EncryptionRequired) { s = tr("Encryption required for chosen SASL mechanism"); } else if(x == XMPP::ClientStream::InvalidAuthzid) { s = tr("Invalid account information"); } else if(x == XMPP::ClientStream::InvalidMech) { s = tr("Invalid SASL mechanism"); } else if(x == XMPP::ClientStream::InvalidRealm) { s = tr("Invalid realm"); } else if(x == XMPP::ClientStream::MechTooWeak) { s = tr("SASL mechanism too weak for this account"); } else if(x == XMPP::ClientStream::NotAuthorized) { s = tr("Not authorized"); } else if(x == XMPP::ClientStream::TemporaryAuthFailure) { s = tr("Temporary auth failure"); } str = tr("Authentication error: %1").arg(s); } else if(err == XMPP::ClientStream::ErrSecurityLayer) str = tr("Broken security layer (SASL)"); else str = tr("None"); //printf("str[%s], reconn=%d\n", str.latin1(), reconn); *_str = str; *_reconn = reconn; } void PsiAccount::cs_error(int err) { QString str; bool reconn; if (!isActive()) return; // all cleaned up already getErrorInfo(err, d->conn, d->stream, d->tlsHandler, &str, &reconn); d->client->close(); cleanupStream(); //printf("Error: [%s]\n", str.latin1()); isDisconnecting = true; if ( loggedIn() ) { // FIXME: is this condition okay? simulateRosterOffline(); } presenceSent = false; // this stops the idle detector?? (FIXME) // Auto-Reconnect? if(d->acc.opt_reconn && reconn) { int delay = 5000; // reconnect in 5 seconds doReconnect = true; stateChanged(); QTimer::singleShot(delay, this, SLOT(reconnect())); return; } v_isActive = false; d->loginStatus = Status(Status::Offline); stateChanged(); disconnected(); bool printAccountName = d->psi->contactList()->enabledAccounts().count() > 1; QMessageBox* m = new QMessageBox(QMessageBox::Critical, (printAccountName ? QString("%1: ").arg(name()) : "") + tr("Server Error"), tr("There was an error communicating with the server.\nDetails: %1").arg(str), QMessageBox::Ok, 0); m->setAttribute(Qt::WA_DeleteOnClose, true); m->setModal(true); m->show(); } void PsiAccount::client_rosterRequestFinished(bool success, int, const QString &) { if(success) { //printf("PsiAccount: [%s] roster retrieved ok. %d entries.\n", name().latin1(), d->client->roster().count()); psi()->contactList()->beginBulkOperation(); // delete flagged items foreach(UserListItem* u, d->userList) { if(u->flagForDelete()) { //QMessageBox::information(0, "blah", QString("deleting: [%1]").arg(u->jid().full())); d->eventQueue->clear(u->jid()); updateReadNext(u->jid()); d->cp->removeEntry(u->jid()); d->userList.removeAll(u); delete u; } } psi()->contactList()->endBulkOperation(); } else { //printf("PsiAccount: [%s] error retrieving roster: [%d, %s]\n", name().latin1(), code, str.latin1()); } rosterDone = true; // Get stored options // FIXME: Should be an account-specific option //if (PsiOptions::instance()->getOption("options.options-storage.load").toBool()) // PsiOptions::instance()->load(d->client); setStatusDirect(d->loginStatus, d->loginWithPriority); } void PsiAccount::resolveContactName() { JT_VCard *j = (JT_VCard *)sender(); if (j->success()) { QString nick = j->vcard().nickName(); QString full = j->vcard().fullName(); if (!nick.isEmpty()) { actionRename(j->jid(), nick); } else if (!full.isEmpty()) { actionRename(j->jid(), full); } } } void PsiAccount::serverFeaturesChanged() { setPEPAvailable(d->serverInfoManager->hasPEP()); } void PsiAccount::setPEPAvailable(bool b) { if (d->pepAvailable == b) return; d->pepAvailable = b; #ifdef PEP // Publish support if (b && !d->client->extensions().contains("ep")) { QStringList pepNodes; pepNodes += "http://jabber.org/protocol/mood"; pepNodes += "http://jabber.org/protocol/tune"; pepNodes += "http://jabber.org/protocol/physloc"; pepNodes += "http://jabber.org/protocol/geoloc"; pepNodes += "http://www.xmpp.org/extensions/xep-0084.html#ns-data"; pepNodes += "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"; d->client->addExtension("ep",Features(pepNodes)); setStatusActual(d->loginStatus); } else if (!b && d->client->extensions().contains("ep")) { d->client->removeExtension("ep"); setStatusActual(d->loginStatus); } // Publish current tune information if (b && d->psi->tuneController() && d->options->getOption("options.extended-presence.tune.publish").toBool()) { Tune current = d->psi->tuneController()->currentTune(); if (!current.isNull()) publishTune(current); } #endif } void PsiAccount::bookmarksAvailabilityChanged() { if (!d->bookmarkManager->isAvailable() || !PsiOptions::instance()->getOption("options.muc.bookmarks.auto-join").toBool()) { return; } foreach(ConferenceBookmark c, d->bookmarkManager->conferences()) { if (!findDialog(Jid(c.jid().bare())) && c.autoJoin()) { actionJoin(c, true); } } } void PsiAccount::incomingHttpAuthRequest(const PsiHttpAuthRequest &req) { HttpAuthEvent *e = new HttpAuthEvent(req, this); handleEvent(e, IncomingStanza); } void PsiAccount::client_rosterItemAdded(const RosterItem &r) { if ( r.isPush() && r.name().isEmpty() && PsiOptions::instance()->getOption("options.contactlist.resolve-nicks-on-contact-add").toBool() ) { // automatically resolve nickname from vCard, if newly added item doesn't have any VCardFactory::instance()->getVCard(r.jid(), d->client->rootTask(), this, SLOT(resolveContactName())); } } void PsiAccount::client_rosterItemUpdated(const RosterItem &r) { // see if the item added is already in our local list UserListItem *u = d->userList.find(r.jid()); if(u) { u->setFlagForDelete(false); u->setRosterItem(r); } else { // we don't have it at all, so add it u = new UserListItem; u->setRosterItem(r); u->setAvatarFactory(avatarFactory()); d->userList.append(u); } u->setInList(true); d->cp->updateEntry(*u); } void PsiAccount::client_rosterItemRemoved(const RosterItem &r) { UserListItem *u = d->userList.find(r.jid()); if(!u) return; simulateContactOffline(u); // if the item has messages queued, then move them to 'not in list' if(d->eventQueue->count(r.jid()) > 0) { u->setInList(false); d->cp->updateEntry(*u); } // else remove them for good! else { d->cp->removeEntry(u->jid()); d->userList.removeAll(u); delete u; } } void PsiAccount::tryVerify(UserListItem *u, UserResource *ur) { if(PGPUtil::instance().pgpAvailable()) verifyStatus(u->jid().withResource(ur->name()), ur->status()); } void PsiAccount::incomingVoiceCall(const Jid& j) { VoiceCallDlg* vc = new VoiceCallDlg(j,voiceCaller()); vc->show(); vc->incoming(); } void PsiAccount::client_resourceAvailable(const Jid &j, const Resource &r) { // Notification enum PopupType { PopupOnline = 0, PopupStatusChange = 1 }; PopupType popupType = PopupOnline; if ( j.node().isEmpty() ) new BlockTransportPopup(d->blockTransportPopupList, j); bool doSound = false; bool doPopup = false; foreach(UserListItem* u, findRelevant(j)) { bool doAnim = false; bool local = false; if(u->isSelf() && r.name() == d->client->resource()) local = true; // add/update the resource QString oldStatus, oldKey; UserResource* rp; UserResourceList::Iterator rit = u->userResourceList().find(j.resource()); bool found = (rit == u->userResourceList().end()) ? false: true; if(!found) { popupType = PopupOnline; UserResource ur(r); //ur.setSecurityEnabled(true); if(local) ur.setClient(ApplicationInfo::name(),ApplicationInfo::version(),SystemInfo::instance()->os()); u->userResourceList().append(ur); rp = &u->userResourceList().last(); if(notifyOnlineOk && !local) { doAnim = true; if (!u->isHidden()) { doSound = true; doPopup = true; } } } else { if ( !doPopup ) popupType = PopupStatusChange; oldStatus = (*rit).status().status(); oldKey = (*rit).status().keyID(); rp = &(*rit); (*rit).setResource(r); if (!local && !u->isHidden()) doPopup = true; } rp->setPGPVerifyStatus(-1); if(!rp->status().xsigned().isEmpty()) tryVerify(u, rp); u->setPresenceError(""); cpUpdate(*u, r.name(), true); if(doAnim && PsiOptions::instance()->getOption("options.ui.contactlist.use-status-change-animation").toBool()) d->cp->animateNick(u->jid()); } if(doSound) playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.contact-online").toString()); #if !defined(Q_WS_MAC) || !defined(HAVE_GROWL) // Do the popup test earlier (to avoid needless JID lookups) if ((popupType == PopupOnline && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.online").toBool()) || (popupType == PopupStatusChange && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.other-changes").toBool())) #endif if(notifyOnlineOk && doPopup && !d->blockTransportPopupList->find(j, popupType == PopupOnline) && !d->noPopup(IncomingStanza)) { QString name; UserListItem *u = findFirstRelevant(j); PsiPopup::PopupType pt = PsiPopup::AlertNone; if ( popupType == PopupOnline ) pt = PsiPopup::AlertOnline; else if ( popupType == PopupStatusChange ) pt = PsiPopup::AlertStatusChange; if ((popupType == PopupOnline && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.online").toBool()) || (popupType == PopupStatusChange && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.other-changes").toBool())) { PsiPopup *popup = new PsiPopup(pt, this); popup->setData(j, r, u); } #if defined(Q_WS_MAC) && defined(HAVE_GROWL) PsiGrowlNotifier::instance()->popup(this, pt, j, r, u); #endif } else if ( !notifyOnlineOk ) d->userCounter++; // Update entity capabilities. // This has to happen after the userlist item has been created. if (!r.status().capsNode().isEmpty()) { capsManager()->updateCaps(j,r.status().capsNode(),r.status().capsVersion(),r.status().capsExt()); // Update the client version foreach(UserListItem* u, findRelevant(j)) { UserResourceList::Iterator rit = u->userResourceList().find(j.resource()); if (rit != u->userResourceList().end()) { //(*rit).setClient(capsManager()->clientName(j),capsManager()->clientVersion(j),""); (*rit).setClient(QString(),QString(),""); cpUpdate(*u,(*rit).name()); } } } } void PsiAccount::client_resourceUnavailable(const Jid &j, const Resource &r) { bool doSound = false; bool doPopup = false; if ( j.node().isEmpty() ) new BlockTransportPopup(d->blockTransportPopupList, j); foreach(UserListItem* u, findRelevant(j)) { bool local = false; if(u->isSelf() && r.name() == d->client->resource()) local = true; // remove resource UserResourceList::Iterator rit = u->userResourceList().find(j.resource()); bool found = (rit == u->userResourceList().end()) ? false: true; if(found) { u->setLastUnavailableStatus(r.status()); u->userResourceList().removeAll(*rit); if(!u->isAvailable()) u->setLastAvailable(QDateTime::currentDateTime()); if(!u->isAvailable() || u->isSelf()) { // don't sound for our own resource if(!isDisconnecting && !local && !u->isHidden()) { doSound = true; doPopup = true; } } } else { // if we get here, then we've received unavailable // presence for a contact that is already considered // unavailable u->setLastUnavailableStatus(r.status()); if (!u->isAvailable()) { QDateTime ts = r.status().timeStamp(); if (ts.isValid()) { u->setLastAvailable(ts); } } // no sounds/popups in this case } u->setPresenceError(""); cpUpdate(*u, r.name(), true); } if(doSound) playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.contact-offline").toString()); #if !defined(Q_WS_MAC) || !defined(HAVE_GROWL) // Do the popup test earlier (to avoid needless JID lookups) if (PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.offline").toBool()) #endif if(doPopup && !d->blockTransportPopupList->find(j) && !d->noPopup(IncomingStanza)) { QString name; UserListItem *u = findFirstRelevant(j); if (PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.status.offline").toBool()) { PsiPopup *popup = new PsiPopup(PsiPopup::AlertOffline, this); popup->setData(j, r, u); } #if defined(Q_WS_MAC) && defined(HAVE_GROWL) PsiGrowlNotifier::instance()->popup(this, PsiPopup::AlertOffline, j, r, u); #endif } } void PsiAccount::client_presenceError(const Jid &j, int, const QString &str) { foreach(UserListItem *u, findRelevant(j)) { simulateContactOffline(u); u->setPresenceError(str); cpUpdate(*u, j.resource(), false); } } void PsiAccount::client_messageReceived(const Message &m) { //check if it's a server message without a from, and set the from appropriately Message _m(m); if (_m.from().isEmpty()) { _m.setFrom(jid().domain()); } // if the sender is already in the queue, then queue this message also foreach(Message* mi, d->messageQueue) { if(mi->from().compare(_m.from())) { Message *m = new Message(_m); d->messageQueue.append(m); return; } } // check to see if message was forwarded from another resource if (jid().compare(_m.from(),false)) { AddressList oFrom = _m.findAddresses(Address::OriginalFrom); AddressList oTo = _m.findAddresses(Address::OriginalTo); if ((oFrom.count() > 0) && (oTo.count() > 0)) { // might want to store current values in MessageEvent object // replace out the from and to addresses with the original addresses _m.setFrom(oFrom[0].jid()); _m.setTo(oTo[0].jid()); } } // encrypted message? if(PGPUtil::instance().pgpAvailable() && !_m.xencrypted().isEmpty()) { Message *m = new Message(_m); d->messageQueue.append(m); processMessageQueue(); return; } processIncomingMessage(_m); } void PsiAccount::processIncomingMessage(const Message &_m) { // skip empty messages, but not if the message contains a data form if(_m.body().isEmpty() && _m.urlList().isEmpty() && _m.invite().isEmpty() && !_m.containsEvents() && _m.chatState() == StateNone && _m.subject().isEmpty() && _m.rosterExchangeItems().isEmpty() && _m.mucInvites().isEmpty() && _m.getForm().fields().empty()) return; // skip headlines? if(_m.type() == "headline" && PsiOptions::instance()->getOption("options.messages.ignore-headlines").toBool()) return; if(_m.type() == "groupchat") { GCMainDlg *w = findDialog(Jid(_m.from().bare())); if(w) w->message(_m); return; } // only toggle if not an invite or body is not empty if(_m.invite().isEmpty() && !_m.body().isEmpty() && _m.mucInvites().isEmpty() && _m.rosterExchangeItems().isEmpty()) toggleSecurity(_m.from(), _m.wasEncrypted()); UserListItem *u = findFirstRelevant(_m.from()); if(u) { if(_m.type() == "chat") u->setLastMessageType(1); else u->setLastMessageType(0); } Message m = _m; // smartchat: try to match up the incoming event to an existing chat // (prior to 0.9, m.from() always contained a resource) Jid j; ChatDlg *c; QList ul = findRelevant(m.from()); // ignore events from non-roster JIDs? if (ul.isEmpty() && PsiOptions::instance()->getOption("options.messages.ignore-non-roster-contacts").toBool()) { if (PsiOptions::instance()->getOption("options.messages.exclude-muc-from-ignore").toBool()) { GCMainDlg *w = findDialog(Jid(_m.from().bare())); if(!w) { return; } } else { return; } } if(ul.isEmpty()) j = m.from().bare(); else j = ul.first()->jid(); // Roster item exchange if (!_m.rosterExchangeItems().isEmpty()) { RosterExchangeEvent* ree = new RosterExchangeEvent(j,_m.rosterExchangeItems(), _m.body(), this); handleEvent(ree, IncomingStanza); return; } c = findChatDialog(j); if(!c) c = findChatDialog(m.from().full()); if(m.type() == "error") { Stanza::Error err = m.error(); QPair desc = err.description(); QString msg = desc.first + ".\n" + desc.second; if (!err.text.isEmpty()) msg += "\n" + err.text; m.setBody(msg + "\n------\n" + m.body()); } // change the type? if (m.type() != "headline" && m.invite().isEmpty() && m.mucInvites().isEmpty()) { if (PsiOptions::instance()->getOption("options.messages.force-incoming-message-type").toString() == "message") m.setType(""); else if (PsiOptions::instance()->getOption("options.messages.force-incoming-message-type").toString() == "chat") m.setType("chat"); else if (PsiOptions::instance()->getOption("options.messages.force-incoming-message-type").toString() == "current-open") { if (c != NULL && !c->isHidden()) m.setType("chat"); else m.setType(""); } } // urls or subject on a chat message? convert back to regular message //if(m.type() == "chat" && (!m.urlList().isEmpty() || !m.subject().isEmpty())) // m.setType(""); //We must not respond to recepit request automatically - KIS /*if(m.messageReceipt() == ReceiptRequest && !m.id().isEmpty()) { Message tm(m.from()); tm.setId(m.id()); tm.setMessageReceipt(ReceiptReceived); dj_sendMessage(tm, false); }*/ MessageEvent *me = new MessageEvent(m, this); me->setOriginLocal(false); handleEvent(me, IncomingStanza); } void PsiAccount::client_subscription(const Jid &j, const QString &str, const QString& nick) { // if they remove our subscription, then we lost presence if(str == "unsubscribed") { UserListItem *u = d->userList.find(j); if(u) simulateContactOffline(u); } AuthEvent *ae = new AuthEvent(j, str, this); ae->setTimeStamp(QDateTime::currentDateTime()); ae->setNick(nick); handleEvent(ae, IncomingStanza); } void PsiAccount::client_debugText(const QString &) { //printf("%s", str.latin1()); //fflush(stdout); } #ifdef GOOGLE_FT void PsiAccount::incomingGoogleFileTransfer(GoogleFileTransfer* ft) { if (QMessageBox::information(0, tr("Incoming file"), QString(tr("Do you want to accept %1 (%2 kb) from %3?")).arg(ft->fileName()).arg((float) ft->fileSize() / 1000).arg(ft->peer().full()), QMessageBox::Yes,QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton) == QMessageBox::Yes) { GoogleFileTransferProgressDialog* d = new GoogleFileTransferProgressDialog(ft); d->show(); ft->accept(); } else ft->reject(); } #endif void PsiAccount::client_incomingFileTransfer() { FileTransfer *ft = d->client->fileTransferManager()->takeIncoming(); if(!ft) return; /*printf("psiaccount: incoming file transfer:\n"); printf(" From: [%s]\n", ft->peer().full().latin1()); printf(" Name: [%s]\n", ft->fileName().latin1()); printf(" Size: %d bytes\n", ft->fileSize());*/ FileEvent *fe = new FileEvent(ft->peer().full(), ft, this); fe->setTimeStamp(QDateTime::currentDateTime()); handleEvent(fe, IncomingStanza); } void PsiAccount::reconnect() { if(doReconnect) { //printf("PsiAccount: [%s] reconnecting...\n", name().latin1()); emit reconnecting(); v_isActive = false; doReconnect = false; login(); } } Status PsiAccount::status() const { return d->loginStatus; } void PsiAccount::setStatus(const Status &_s, bool withPriority) { d->setManualStatus(_s); // Block all transports' contacts' status change popups from popping { Roster::ConstIterator rit = d->acc.roster.begin(); for ( ; rit != d->acc.roster.end(); ++rit) { const RosterItem &i = *rit; if ( i.jid().node().isEmpty() /*&& i.jid().resource() == "registered"*/ ) // it is very likely then, that it's transport new BlockTransportPopup(d->blockTransportPopupList, i.jid()); } } // cancel auto-status and reconnect doReconnect = false; Status s = _s; if (!withPriority) s.setPriority(d->acc.priority); d->loginStatus = s; d->loginWithPriority = withPriority; if(s.isAvailable()) { // if client is not active then attempt to login if(!isActive()) { Jid j = d->jid; if(!j.isValid()) { QMessageBox::information(0, CAP(tr("Error")), tr("Unable to login. Ensure your account information is filled out.")); modify(); return; } if(!d->acc.opt_pass) { bool ok = false; QString text = QInputDialog::getText(0, tr("Need Password"), ( d->psi->contactList()->enabledAccounts().count() > 1 ? tr("Please enter the password for %1:").arg(JIDUtil::toString(j,true)) : tr("Please enter your password:") ), QLineEdit::Password, QString::null, &ok); if(ok && !text.isEmpty()) { d->acc.pass = text; } else { // if the user clicks 'online' in the // status menu, then the online // option will be 'checked' in the // menu. if the user cancels the // password dialog, we call // updateMainwinStatus to restore // the status menu to the correct // state. d->psi->updateMainwinStatus(); return; } } login(); } // change status else { if(rosterDone) setStatusDirect(s, withPriority); if(s.isInvisible()) {//&&Pass invis to transports KEVIN //this is a nasty hack to let the transports know we're invisible, since they get an offline packet when we go invisible foreach(UserListItem* u, d->userList) { if(u->isTransport()) { JT_Presence *j = new JT_Presence(d->client->rootTask()); j->pres(u->jid(), s); j->go(true); } } } } } else { if(isActive()) logout(false, s); } } void PsiAccount::setStatusDirect(const Status &_s, bool withPriority) { Status s = _s; if (!withPriority) s.setPriority(d->acc.priority); //printf("setting status to [%s]\n", s.status().latin1()); // using pgp? if(!d->cur_pgpSecretKey.isNull()) { d->loginStatus = s; // sign presence trySignPresence(); } else { /*if(d->psi->pgp() && !d->cur_pgpSecretKeyID.isEmpty()) s.setKeyID(d->cur_pgpSecretKeyID); else s.setKeyID("");*/ // send presence normally setStatusActual(s); } } void PsiAccount::setStatusActual(const Status &_s) { Status s = _s; // Add entity capabilities information if (capsManager()->isEnabled()) { s.setCapsNode(d->client->capsNode()); s.setCapsVersion(d->client->capsVersion()); s.setCapsExt(d->client->capsExt()); } // Add vcard photo hash if available if(!d->photoHash.isEmpty()) { s.setPhotoHash(d->photoHash); } // Set the status d->loginStatus = s; d->client->setPresence(s); if(presenceSent) { stateChanged(); } else { presenceSent = true; stateChanged(); QTimer::singleShot(15000, this, SLOT(enableNotifyOnline())); // Get the vcard const VCard *vcard = VCardFactory::instance()->vcard(d->jid); if (PsiOptions::instance()->getOption("options.vcard.query-own-vcard-on-login").toBool() || !vcard || vcard->isEmpty() || (vcard->nickName().isEmpty() && vcard->fullName().isEmpty())) VCardFactory::instance()->getVCard(d->jid, d->client->rootTask(), this, SLOT(slotCheckVCard())); else { d->nickFromVCard = true; // if we get here, one of these fields is non-empty if (!vcard->nickName().isEmpty()) { setNick(vcard->nickName()); } else { setNick(vcard->fullName()); } } } } void PsiAccount::capsChanged(const Jid& j) { if (!loggedIn()) return; QString name = capsManager()->clientName(j); QString version = (name.isEmpty() ? QString() : capsManager()->clientVersion(j)); foreach(UserListItem *u, findRelevant(j)) { UserResourceList::Iterator rit = u->userResourceList().find(j.resource()); bool found = (rit == u->userResourceList().end()) ? false: true; if(!found) continue; //(*rit).setClient(name,version,""); (*rit).setClient(QString(),QString(),""); cpUpdate(*u); } } void PsiAccount::tuneStopped() { if (loggedIn() && d->options->getOption("options.extended-presence.tune.publish").toBool()) { publishTune(Tune()); } } void PsiAccount::tunePlaying(const Tune& tune) { if (loggedIn() && d->options->getOption("options.extended-presence.tune.publish").toBool()) { publishTune(tune); } } void PsiAccount::publishTune(const Tune& tune) { QDomDocument* doc = d->client->rootTask()->doc(); QDomElement t = doc->createElement("tune"); t.setAttribute("xmlns", "http://jabber.org/protocol/tune"); if (!tune.artist().isEmpty()) t.appendChild(textTag(doc, "artist", tune.artist())); if (!tune.name().isEmpty()) t.appendChild(textTag(doc, "title", tune.name())); if (!tune.album().isEmpty()) t.appendChild(textTag(doc, "source", tune.album())); if (!tune.track().isEmpty()) t.appendChild(textTag(doc, "track", tune.track())); if (tune.time() != 0) t.appendChild(textTag(doc, "length", QString::number(tune.time()))); d->lastTune = tune; d->pepManager->publish("http://jabber.org/protocol/tune",PubSubItem("current",t)); } void PsiAccount::secondsIdle(int seconds) { int minutes = seconds / 60; if(PsiOptions::instance()->getOption("options.status.auto-away.use-offline").toBool() && PsiOptions::instance()->getOption("options.status.auto-away.offline-after").toInt() > 0 && minutes >= PsiOptions::instance()->getOption("options.status.auto-away.offline-after").toInt()) d->setAutoAway(Private::AutoAway_Offline); else if(PsiOptions::instance()->getOption("options.status.auto-away.use-not-availible").toBool() && PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool() && PsiOptions::instance()->getOption("options.status.auto-away.not-availible-after").toInt() > 0 && minutes >= PsiOptions::instance()->getOption("options.status.auto-away.not-availible-after").toInt()) d->setAutoAway(Private::AutoAway_XA); else if(PsiOptions::instance()->getOption("options.status.auto-away.use-away").toBool() && PsiOptions::instance()->getOption("options.status.auto-away.away-after").toInt() > 0 && minutes >= PsiOptions::instance()->getOption("options.status.auto-away.away-after").toInt()) d->setAutoAway(Private::AutoAway_Away); else d->setAutoAway(Private::AutoAway_None); } void PsiAccount::playSound(const QString &str) { if(str.isEmpty()) return; int s = STATUS_OFFLINE; if(loggedIn()) s = makeSTATUS(status()); if(s == STATUS_DND) return; // no away sounds? if(PsiOptions::instance()->getOption("options.ui.notifications.sounds.silent-while-away").toBool() && (s == STATUS_AWAY || s == STATUS_XA)) return; d->psi->playSound(str); } QString PsiAccount::localHostName() { QString hostname = QHostInfo::localHostName(); int i = hostname.indexOf('.'); if (i != -1) return hostname.left(hostname.indexOf('.')); else return hostname; } bool PsiAccount::validRosterExchangeItem(const RosterExchangeItem& item) { if (item.action() == RosterExchangeItem::Add) { return (d->client->roster().find(item.jid(),true) == d->client->roster().end()); } else if (item.action() == RosterExchangeItem::Delete) { LiveRoster::ConstIterator i = d->client->roster().find(item.jid(),true); if (i == d->client->roster().end()) return false; foreach(QString group, item.groups()) { if (!(*i).groups().contains(group)) return false; } return true; } else if (item.action() == RosterExchangeItem::Modify) { // TODO return false; } return false; } ChatDlg* PsiAccount::findChatDialog(const Jid& jid) const { return findDialog(jid, true); } QWidget* PsiAccount::findDialog(const QMetaObject& mo, const Jid& jid, bool compareResource) const { return d->findDialog(mo, jid, compareResource); } void PsiAccount::findDialogs(const QMetaObject& mo, const Jid& jid, bool compareResource, QList* list) const { d->findDialogs(mo, jid, compareResource, list); } void PsiAccount::dialogRegister(QWidget *w, const Jid &j) { d->dialogRegister(w, j); } void PsiAccount::dialogUnregister(QWidget *w) { d->dialogUnregister(w); } void PsiAccount::deleteAllDialogs() { delete d->xmlConsole; d->deleteDialogList(); } bool PsiAccount::checkConnected(QWidget *par) { if (!isAvailable()) { QMessageBox::information(par, CAP(tr("Error")), tr("You must be connected to the server in order to do this.")); return false; } return true; } void PsiAccount::modify() { AccountModifyDlg *w = findDialog(); if (w) { bringToFront(w); } else { w = new AccountModifyDlg(this, 0); w->show(); } } void PsiAccount::changeVCard() { actionInfo(d->jid,false); } void PsiAccount::changePW() { if (!checkConnected()) { return; } ChangePasswordDlg *w = findDialog(); if (w) { bringToFront(w); } else { w = new ChangePasswordDlg(this); w->show(); } } void PsiAccount::showXmlConsole() { bringToFront(d->xmlConsole); } void PsiAccount::openAddUserDlg() { openAddUserDlg(QString(), QString(), QString()); } void PsiAccount::openAddUserDlg(const Jid &jid, const QString &nick, const QString &group) { QStringList gl, services, names; UserListIt it(d->userList); foreach(UserListItem* u, d->userList) { if(u->isTransport()) { services += u->jid().full(); names += JIDUtil::nickOrJid(u->name(), u->jid().full()); } foreach(QString group, u->groups()) { if(!gl.contains(group)) gl.append(group); } } AddUserDlg* w; if (jid.isEmpty()) { w = new AddUserDlg(services, names, gl, this); } else { w = new AddUserDlg(jid, nick, group, gl, this); } connect(w, SIGNAL(add(const XMPP::Jid &, const QString &, const QStringList &, bool)), SLOT(dj_add(const XMPP::Jid &, const QString &, const QStringList &, bool))); w->show(); } void PsiAccount::doDisco() { actionDisco(d->jid.domain(), ""); } void PsiAccount::actionDisco(const Jid &j, const QString &node) { DiscoDlg *w = new DiscoDlg(this, j, node); connect(w, SIGNAL(featureActivated(QString, Jid, QString)), SLOT(featureActivated(QString, Jid, QString))); w->show(); } void PsiAccount::featureActivated(QString feature, Jid jid, QString node) { Features f(feature); if ( f.canRegister() ) actionRegister(jid); else if ( f.canSearch() ) actionSearch(jid); else if ( f.canGroupchat() ) actionJoin(jid); else if ( f.canCommand() ) actionExecuteCommand(jid, node); else if ( f.canDisco() ) actionDisco(jid, node); else if ( f.isGateway() ) ; // TODO else if ( f.haveVCard() ) actionInfo(jid); else if ( f.id() == Features::FID_Add ) { QStringList sl; dj_add(jid, QString::null, sl, true); } } void PsiAccount::actionJoin(const Jid& mucJid, const QString& password) { actionJoin(ConferenceBookmark(QString(), mucJid, false, QString(), password), false); } void PsiAccount::actionJoin(const ConferenceBookmark& bookmark, bool connectImmediately) { MUCJoinDlg* w = new MUCJoinDlg(psi(), this); w->setJid(bookmark.jid()); w->setNick(bookmark.nick().isEmpty() ? d->jid.node() : bookmark.nick()); w->setPassword(bookmark.password()); w->show(); if (connectImmediately) { w->doJoin(); } } void PsiAccount::stateChanged() { if(loggedIn()) { d->cp->setState(makeSTATUS(status())); } else { if(isActive()) { d->cp->setState(-1); if(d->usingSSL) d->cp->setUsingSSL(true); else d->cp->setUsingSSL(false); } else { d->cp->setState(STATUS_OFFLINE); d->cp->setUsingSSL(false); } } emit updatedActivity(); } void PsiAccount::simulateContactOffline(UserListItem *u) { UserResourceList rl = u->userResourceList(); u->setPresenceError(""); if(!rl.isEmpty()) { for(UserResourceList::ConstIterator rit = rl.begin(); rit != rl.end(); ++rit) { const UserResource &r = *rit; Jid j = u->jid(); if(u->jid().resource().isEmpty()) { j = j.withResource(r.name()); } client_resourceUnavailable(j, r); } } u->setLastUnavailableStatus(makeStatus(STATUS_OFFLINE,"")); u->setLastAvailable(QDateTime()); cpUpdate(*u); } void PsiAccount::simulateRosterOffline() { foreach(UserListItem* u, d->userList) simulateContactOffline(u); // self { UserListItem *u = &d->self; UserResourceList rl = u->userResourceList(); for(UserResourceList::ConstIterator rit = rl.begin(); rit != rl.end(); ++rit) { Jid j = u->jid(); if(u->jid().resource().isEmpty()) { j = j.withResource((*rit).name()); } u->setPresenceError(""); client_resourceUnavailable(j, *rit); } } while (!d->gcbank.isEmpty()) delete d->gcbank.takeFirst(); } void PsiAccount::enableNotifyOnline() { if ( d->userCounter > 1 ) { QTimer::singleShot(15000, this, SLOT(enableNotifyOnline())); d->userCounter = 0; } else notifyOnlineOk = true; } void PsiAccount::itemRetracted(const Jid& j, const QString& n, const PubSubRetraction& item) { Q_UNUSED(item); // User Tune if (n == "http://jabber.org/protocol/tune") { // Parse tune foreach(UserListItem* u, findRelevant(j)) { // FIXME: try to find the right resource using JEP-33 'replyto' //UserResourceList::Iterator rit = u->userResourceList().find(); //bool found = (rit == u->userResourceList().end()) ? false: true; //if(found) // (*rit).setTune(tune); u->setTune(QString()); cpUpdate(*u); } } else if (n == "http://jabber.org/protocol/mood") { foreach(UserListItem* u, findRelevant(j)) { u->setMood(Mood()); cpUpdate(*u); } } else if (n == "http://jabber.org/protocol/geoloc") { // FIXME: try to find the right resource using JEP-33 'replyto' // see tune case above foreach(UserListItem* u, findRelevant(j)) { u->setGeoLocation(GeoLocation()); cpUpdate(*u); } } else if (n == "http://jabber.org/protocol/physloc") { // FIXME: try to find the right resource using JEP-33 'replyto' // see tune case above foreach(UserListItem* u, findRelevant(j)) { u->setPhysicalLocation(PhysicalLocation()); cpUpdate(*u); } } } void PsiAccount::itemPublished(const Jid& j, const QString& n, const PubSubItem& item) { // User Tune if (n == "http://jabber.org/protocol/tune") { // Parse tune QDomElement element = item.payload(); QDomElement e; QString tune; bool found; e = findSubTag(element, "artist", &found); if (found) tune += e.text() + " - "; e = findSubTag(element, "title", &found); if (found) tune += e.text(); foreach(UserListItem* u, findRelevant(j)) { // FIXME: try to find the right resource using JEP-33 'replyto' //UserResourceList::Iterator rit = u->userResourceList().find(); //bool found = (rit == u->userResourceList().end()) ? false: true; //if(found) // (*rit).setTune(tune); u->setTune(tune); cpUpdate(*u); } } else if (n == "http://jabber.org/protocol/mood") { Mood mood(item.payload()); foreach(UserListItem* u, findRelevant(j)) { u->setMood(mood); cpUpdate(*u); } } else if (n == "http://jabber.org/protocol/geoloc") { // FIXME: try to find the right resource using JEP-33 'replyto' // see tune case above GeoLocation geoloc(item.payload()); foreach(UserListItem* u, findRelevant(j)) { u->setGeoLocation(geoloc); cpUpdate(*u); } } else if (n == "http://jabber.org/protocol/physloc") { // FIXME: try to find the right resource using JEP-33 'replyto' // see tune case above PhysicalLocation physloc(item.payload()); foreach(UserListItem* u, findRelevant(j)) { u->setPhysicalLocation(physloc); cpUpdate(*u); } } } QList PsiAccount::findRelevant(const Jid &j) const { QList list; // self? if(j.compare(d->self.jid(), false)) list.append(&d->self); else { foreach(UserListItem* u, d->userList) { if(!u->jid().compare(j, false)) continue; if(!u->jid().resource().isEmpty()) { if(u->jid().resource() != j.resource()) continue; } else { // skip status changes from muc participants // if the MUC somehow got into userList. if (!j.resource().isEmpty() && d->groupchats.contains(j.bare())) continue; } list.append(u); } } return list; } UserListItem *PsiAccount::findFirstRelevant(const Jid &j) const { QList list = findRelevant(j); if(list.isEmpty()) return 0; else return list.first(); } UserListItem *PsiAccount::find(const Jid &j) const { UserListItem *u; if(j.compare(d->self.jid())) u = &d->self; else u = d->userList.find(j); return u; } void PsiAccount::cpUpdate(const UserListItem &u, const QString &rname, bool fromPresence) { PsiEvent *e = d->eventQueue->peek(u.jid()); d->cp->updateEntry(u); if(e) { d->cp->setAlert(u.jid(), PsiIconset::instance()->event2icon(e)); } else d->cp->clearAlert(u.jid()); updateContact(u); Jid j = u.jid(); if(!rname.isEmpty()) { j = j.withResource(rname); } updateContact(j); updateContact(j, fromPresence); d->psi->updateContactGlobal(this, j); } EventDlg *PsiAccount::ensureEventDlg(const Jid &j) { EventDlg *w = findDialog(j); if(!w) { w = new EventDlg(j, this, true); connect(w, SIGNAL(aReadNext(const Jid &)), SLOT(processReadNext(const Jid &))); connect(w, SIGNAL(aChat(const Jid &)), SLOT(actionOpenChat2(const Jid&))); connect(w, SIGNAL(aReply(const Jid &, const QString &, const QString &, const QString &)), SLOT(dj_replyMessage(const Jid &, const QString &, const QString &, const QString &))); connect(w, SIGNAL(aAuth(const Jid &)), SLOT(dj_addAuth(const Jid &))); connect(w, SIGNAL(aDeny(const Jid &)), SLOT(dj_deny(const Jid &))); connect(w, SIGNAL(aHttpConfirm(const PsiHttpAuthRequest &)), SLOT(dj_confirmHttpAuth(const PsiHttpAuthRequest &))); connect(w, SIGNAL(aHttpDeny(const PsiHttpAuthRequest &)), SLOT(dj_denyHttpAuth(const PsiHttpAuthRequest &))); connect(w, SIGNAL(aRosterExchange(const RosterExchangeItems &)), SLOT(dj_rosterExchange(const RosterExchangeItems &))); connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate())); connect(this, SIGNAL(updateContact(const Jid &)), w, SLOT(updateContact(const Jid &))); connect(w, SIGNAL(aFormSubmit(const XData&, const QString&, const Jid&)), SLOT(dj_formSubmit(const XData&, const QString&, const Jid&))); connect(w, SIGNAL(aFormCancel(const XData&, const QString&, const Jid&)), SLOT(dj_formCancel(const XData&, const QString&, const Jid&))); } return w; } ChatDlg *PsiAccount::ensureChatDlg(const Jid &j) { ChatDlg *c = findChatDialog(j); if(!c) { // create the chatbox c = ChatDlg::create(j, this, d->tabManager); connect(c, SIGNAL(aSend(const Message &)), SLOT(dj_sendMessage(const Message &))); connect(c, SIGNAL(messagesRead(const Jid &)), SLOT(chatMessagesRead(const Jid &))); connect(c, SIGNAL(aInfo(const Jid &)), SLOT(actionInfo(const Jid &))); connect(c, SIGNAL(aHistory(const Jid &)), SLOT(actionHistory(const Jid &))); connect(c, SIGNAL(aFile(const Jid &)), SLOT(actionSendFile(const Jid &))); connect(c, SIGNAL(aVoice(const Jid &)), SLOT(actionVoice(const Jid &))); connect(d->psi, SIGNAL(emitOptionsUpdate()), c, SLOT(optionsUpdate())); connect(this, SIGNAL(updateContact(const Jid &, bool)), c, SLOT(updateContact(const Jid &, bool))); } else { // on X11, do a special reparent to open on the right desktop #ifdef Q_WS_X11 /* KIS added an exception for tabs here. We do *not* want chats flying * randomlyi, it pulls them out of tabsets. So instead, we move the * tabset instead. It's just as filthy, unfortunately, but it's the * only way */ //TODO: This doesn't work as expected atm, it doesn't seem to reparent the tabset QWidget *window=c; if ( PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool() ) window = d->tabManager->getManagingTabs(c); if(window && window->isHidden()) { QPixmap pp = c->windowIcon().pixmap(16,16); // FIXME: 16x16 is just a guess of what size old QWidget::icon() used QPixmap p; if(!pp.isNull()) p = pp; #ifdef __GNUC__ #warning "Removed reparenting call from qwextend" #endif //reparent_good(window, 0, false); if(!p.isNull()) c->setWindowIcon(p); } #endif } Q_ASSERT(c); return c; } void PsiAccount::changeStatus(int x) { if(x == STATUS_OFFLINE && !PsiOptions::instance()->getOption("options.status.ask-for-message-on-offline").toBool()) { setStatus(Status(Status::Offline, "Logged out", 0)); } else { if(x == STATUS_ONLINE && !PsiOptions::instance()->getOption("options.status.ask-for-message-on-online").toBool()) { setStatus(Status()); } else if(x == STATUS_INVISIBLE){ Status s("","",0,true); s.setIsInvisible(true); setStatus(s); } else { StatusSetDlg *w = new StatusSetDlg(this, makeStatus(x, "")); connect(w, SIGNAL(set(const XMPP::Status &, bool)), SLOT(setStatus(const XMPP::Status &, bool))); w->show(); } } } void PsiAccount::actionVoice(const Jid &j) { Jid j2 = j; if(j.resource().isEmpty()) { UserListItem *u = find(j); if(u && u->isAvailable()) j2 = j2.withResource((*u->userResourceList().priority()).name()); } CallDlg *w = new CallDlg(this, 0); w->setAttribute(Qt::WA_DeleteOnClose); w->setOutgoing(j2); w->show(); /* Q_ASSERT(voiceCaller() != NULL); Jid jid; if (j.resource().isEmpty()) { bool found = false; UserListItem *u = find(j); if (u) { const UserResourceList &rl = u->userResourceList(); for (UserResourceList::ConstIterator it = rl.begin(); it != rl.end() && !found; ++it) { if (capsManager()->features(j.withResource((*it).name())).canVoice()) { jid = j.withResource((*it).name()); found = true; } } } if (!found) return; } else { jid = j; } VoiceCallDlg* vc = new VoiceCallDlg(jid,voiceCaller()); vc->show(); vc->call(); */ } void PsiAccount::sendFiles(const Jid& j, const QStringList& l, bool direct) { Jid j2 = j; if(j.resource().isEmpty()) { UserListItem *u = find(j); if(u && u->isAvailable()) j2 = j2.withResource((*u->userResourceList().priority()).name()); } // Create a dialog for each file in the list. Once the xfer dialog itself // supports multiple files, only the 'else' branch needs to stay. if (!l.isEmpty()) { for (QStringList::ConstIterator f = l.begin(); f != l.end(); ++f ) { QStringList fl(*f); FileRequestDlg *w = new FileRequestDlg(j2, d->psi, this, fl, direct); w->show(); } } else { FileRequestDlg *w = new FileRequestDlg(j2, d->psi, this, l, direct); w->show(); } } void PsiAccount::actionSendFile(const Jid &j) { QStringList l; sendFiles(j,l); } void PsiAccount::actionSendFiles(const Jid &j, const QStringList& l) { sendFiles(j, l); } void PsiAccount::actionExecuteCommand(const Jid& j, const QString& node) { Jid j2 = j; if(j.resource().isEmpty()) { UserListItem *u = find(j); if(u && u->isAvailable()) j2 = j2.withResource((*u->userResourceList().priority()).name()); } actionExecuteCommandSpecific(j2, node); } void PsiAccount::actionExecuteCommandSpecific(const Jid& j, const QString& node) { if (node.isEmpty()) { AHCommandDlg *w = new AHCommandDlg(this,j); w->show(); } else { AHCommandDlg::executeCommand(d->client,j,node); } } void PsiAccount::actionSetMood() { MoodDlg *w = new MoodDlg(this); w->show(); } void PsiAccount::actionSetAvatar() { QString str = FileUtil::getImageFileName(0); if (!str.isEmpty()) { avatarFactory()->setSelfAvatar(str); } } void PsiAccount::actionUnsetAvatar() { avatarFactory()->setSelfAvatar(""); } void PsiAccount::actionDefault(const Jid &j) { UserListItem *u = find(j); if(!u) return; if(d->eventQueue->count(u->jid()) > 0) openNextEvent(*u, UserAction); else { if(PsiOptions::instance()->getOption("options.messages.default-outgoing-message-type").toString() == "message") actionSendMessage(u->jid()); else actionOpenChat(u->jid()); } } void PsiAccount::actionRecvEvent(const Jid &j) { UserListItem *u = find(j); if(!u) return; openNextEvent(*u, UserAction); } void PsiAccount::actionRecvRosterExchange(const Jid& j, const RosterExchangeItems& items) { handleEvent(new RosterExchangeEvent(j,items,"", this), IncomingStanza); } void PsiAccount::actionSendMessage(const Jid &j) { EventDlg *w = d->psi->createEventDlg(j.full(), this); w->show(); } void PsiAccount::actionSendMessage(const QList &j) { QString str; bool first = true; for(QList::ConstIterator it = j.begin(); it != j.end(); ++it) { if(!first) str += ", "; first = false; str += (*it).full(); } EventDlg *w = d->psi->createEventDlg(str, this); w->show(); } void PsiAccount::actionSendUrl(const Jid &j) { EventDlg *w = d->psi->createEventDlg(j.full(), this); w->setUrlOnShow(); w->show(); } void PsiAccount::actionRemove(const Jid &j) { avatarFactory()->removeManualAvatar(j); dj_remove(j); } void PsiAccount::actionRename(const Jid &j, const QString &name) { dj_rename(j, name); } void PsiAccount::actionGroupRename(const QString &oldname, const QString &newname) { QList nu; foreach(UserListItem* u, d->userList) { if(u->inGroup(oldname)) { u->removeGroup(oldname); u->addGroup(newname); cpUpdate(*u); if(u->inList()) { nu.append(u); } } } if(!nu.isEmpty()) { foreach(UserListItem* u, nu) { JT_Roster *r = new JT_Roster(d->client->rootTask()); r->set(u->jid(), u->name(), u->groups()); r->go(true); } } } void PsiAccount::actionHistory(const Jid &j) { HistoryDlg *w = findDialog(j); if(w) bringToFront(w); else { w = new HistoryDlg(j, this); connect(w, SIGNAL(openEvent(PsiEvent *)), SLOT(actionHistoryBox(PsiEvent *))); w->show(); } } void PsiAccount::actionHistoryBox(PsiEvent *e) { EventDlg *w = new EventDlg(e->from(), this, false); connect(w, SIGNAL(aChat(const Jid &)), SLOT(actionOpenChat2(const Jid&))); connect(w, SIGNAL(aReply(const Jid &, const QString &, const QString &, const QString &)), SLOT(dj_replyMessage(const Jid &, const QString &, const QString &, const QString &))); connect(w, SIGNAL(aAuth(const Jid &)), SLOT(dj_addAuth(const Jid &))); connect(w, SIGNAL(aDeny(const Jid &)), SLOT(dj_deny(const Jid &))); connect(w, SIGNAL(aRosterExchange(const RosterExchangeItems &)), SLOT(dj_rosterExchange(const RosterExchangeItems &))); connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate())); connect(this, SIGNAL(updateContact(const Jid &)), w, SLOT(updateContact(const Jid &))); w->updateEvent(e); w->show(); } void PsiAccount::actionOpenChat(const Jid &j) { UserListItem *u = find(j); if(!u) { printf("[%s] not in userlist\n", qPrintable(j.full())); return; } // if 'j' is bare, we might want to switch to a specific resource QString res; if(j.resource().isEmpty()) { // first, are there any queued chats? /*PsiEvent *e = d->eventQueue->peekFirstChat(j, false); if(e) { res = e->from().resource(); // if we have a bare chat, change to 'res' ChatDlg *c = findChatDialog(j); if(c) c->setJid(j.withResource(res)); } // else, is there a priority chat window available? else*/ if(u->isAvailable()) { QString pr = (*u->userResourceList().priority()).name(); if(!pr.isEmpty() && findChatDialog(j.withResource(pr))) res = pr; } else { QStringList list = hiddenChats(j); if(!list.isEmpty()) res = list.first(); } } if(!res.isEmpty()) openChat(j.withResource(res), UserAction); else openChat(j, UserAction); } // unlike actionOpenChat(), this function will work on jids that aren't // necessarily in the userlist. void PsiAccount::actionOpenChat2(const Jid &_j) { Jid j = _j; UserListItem *u = findFirstRelevant(j); if(u) { j = u->jid(); } else { // this can happen if the contact is not in the roster at all GCContact *c = findGCContact(j); if(c) { // if the contact is from a groupchat, use invokeGCChat invokeGCChat(j); return; } else { // otherwise, make an item u = new UserListItem; // HACK: reverting to bare jid is probably "wrong", but // i think in almost every case it's what you'd want j = j.withResource(QString()); u->setJid(j); u->setInList(false); d->userList.append(u); cpUpdate(*u); } } actionOpenChat(j); } void PsiAccount::actionOpenChatSpecific(const Jid &j) { openChat(j, UserAction); } #ifdef WHITEBOARDING void PsiAccount::actionOpenWhiteboard(const Jid &j) { UserListItem *u = find(j); if(!u) return; // if 'j' is bare, we might want to switch to a specific resource QString res; if(j.resource().isEmpty()) { if(u->isAvailable()) { QString pr = (*u->userResourceList().priority()).name(); if(!pr.isEmpty()) res = pr; } } if(!res.isEmpty()) { actionOpenWhiteboardSpecific(j.withResource(res)); } else { actionOpenWhiteboardSpecific(j); } } /*! \brief Opens a whiteboard to \a target. * \a ownJid and \a groupChat should be specified in the case of a group chat session. */ void PsiAccount::actionOpenWhiteboardSpecific(const Jid &target, Jid ownJid, bool groupChat) { if(ownJid.isEmpty()) ownJid = jid(); d->wbManager->openWhiteboard(target, ownJid, groupChat, true); } #endif void PsiAccount::actionAgentSetStatus(const Jid &j, Status &s) { if ( j.node().isEmpty() ) // add all transport popups to block list new BlockTransportPopup(d->blockTransportPopupList, j); JT_Presence *p = new JT_Presence(d->client->rootTask()); p->pres(j, s); p->go(true); } void PsiAccount::actionInfo(const Jid &_j, bool showStatusInfo) { bool useCache = true; Jid j; if(findGCContact(_j)) { useCache = false; j = _j; } else { j = _j.bare(); } InfoDlg *w = findDialog(j); if(w) { w->updateStatus(); w->setStatusVisibility(showStatusInfo); bringToFront(w); } else { const VCard *vcard = VCardFactory::instance()->vcard(j); VCard tmp; if ( vcard ) tmp = *vcard; w = new InfoDlg(j.compare(d->jid) ? InfoDlg::Self : InfoDlg::Contact, j, tmp, this, 0, useCache); w->setStatusVisibility(showStatusInfo); w->show(); // automatically retrieve info if it doesn't exist if(!vcard && loggedIn()) w->doRefresh(); } } void PsiAccount::actionAuth(const Jid &j) { dj_auth(j); } void PsiAccount::actionAuthRequest(const Jid &j) { dj_authReq(j); } void PsiAccount::actionAuthRemove(const Jid &j) { dj_deny(j); } void PsiAccount::actionAdd(const Jid &j) { dj_addAuth(j); } void PsiAccount::actionGroupAdd(const Jid &j, const QString &g) { UserListItem *u = d->userList.find(j); if(!u) return; if(!u->addGroup(g)) return; cpUpdate(*u); JT_Roster *r = new JT_Roster(d->client->rootTask()); r->set(u->jid(), u->name(), u->groups()); r->go(true); } void PsiAccount::actionGroupRemove(const Jid &j, const QString &g) { UserListItem *u = d->userList.find(j); if(!u) return; if(!u->removeGroup(g)) return; cpUpdate(*u); JT_Roster *r = new JT_Roster(d->client->rootTask()); r->set(u->jid(), u->name(), u->groups()); r->go(true); } void PsiAccount::actionRegister(const Jid &j) { if(!checkConnected()) return; RegistrationDlg *w = findDialog(j); if(w) bringToFront(w); else { w = new RegistrationDlg(j, this); w->show(); } } void PsiAccount::actionSearch(const Jid &j) { if(!checkConnected()) return; SearchDlg *w = findDialog(j); if(w) bringToFront(w); else { w = new SearchDlg(j, this); connect(w, SIGNAL(add(const XMPP::Jid &, const QString &, const QStringList &, bool)), SLOT(dj_add(const XMPP::Jid &, const QString &, const QStringList &, bool))); connect(w, SIGNAL(aInfo(const Jid &)), SLOT(actionInfo(const Jid &))); w->show(); } } void PsiAccount::actionInvite(const Jid &j, const QString &gc) { Message m; Jid room(gc); m.setTo(room); m.addMUCInvite(MUCInvite(j)); QString password = d->client->groupChatPassword(room.node(),room.domain()); if (!password.isEmpty()) m.setMUCPassword(password); m.setTimeStamp(QDateTime::currentDateTime()); dj_sendMessage(m); } void PsiAccount::actionAssignKey(const Jid &j) { if(ensureKey(j)) { UserListItem *u = findFirstRelevant(j); if(u) cpUpdate(*u); } } void PsiAccount::actionUnassignKey(const Jid &j) { UserListItem *u = findFirstRelevant(j); if(u) { u->setPublicKeyID(""); cpUpdate(*u); } } void PsiAccount::openUri(const QUrl &uriToOpen) { QUrl uri(uriToOpen); // got to copy, because setQueryDelimiters() is not const // entity QString path = uri.path(); if (path.startsWith('/')) { // this happens when authority part is present path = path.mid(1); } Jid entity = JIDUtil::fromString(path); // query uri.setQueryDelimiters('=', ';'); QString querytype = uri.queryItems().value(0).first; // defaults to empty string if (0) { //} else if (querytype == "command") { // // action //} else if (querytype == "disco") { // actionDisco(entity, uri.queryItemValue("node")); //x // // request, type } else if (querytype == "invite") { actionJoin(entity, uri.queryItemValue("password")); // jid } else if (querytype == "join") { actionJoin(entity, uri.queryItemValue("password")); } else if (querytype == "message") { QString subject = uri.queryItemValue("subject"); QString body = uri.queryItemValue("body"); QString type = uri.queryItemValue("type"); if (type == "chat" && subject.isEmpty() && body.isEmpty()) { if (!find(entity)) { addUserListItem(entity); } actionOpenChat(entity); } else { dj_newMessage(entity, body, subject, ""); } // thread, from, id //} else if (querytype == "pubsub") { // // action, node //} else if (querytype == "recvfile") { // // ... //} else if (querytype == "register") { //} else if (querytype == "remove") { } else if (querytype == "roster") { openAddUserDlg(entity, uri.queryItemValue("name"), uri.queryItemValue("group")); //} else if (querytype == "sendfile") { //} else if (querytype == "subscribe") { //} else if (querytype == "unregister") { //} else if (querytype == "unsubscribe") { //} else if (querytype == "vcard") { // pa->actionInfo(entity, true, true); } else { // TODO: default case - be more smart!! ;-) //if (QMessageBox::question(0, tr("Hmm.."), QString(tr("So, you'd like to open %1 URI, right?\n" // "Unfortunately, this URI only identifies an entity, but it doesn't say what action to perform (or at least Psi cannot understand it). " // "So it's pretty much like if I said \"John\" to you - you'd immediately ask \"But what about John?\".\n" // "So... What about %1??\n" // "At worst, you may send a message to %2 to ask what to do (and maybe complain about this URI ;)) " // "Would you like to do this now?")).arg(uri).arg(entity.full()), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) actionSendMessage(entity); } } void PsiAccount::dj_sendMessage(const Message &m, bool log) { UserListItem *u = findFirstRelevant(m.to()); Message nm = m; if(PsiOptions::instance()->getOption("options.messages.force-incoming-message-type").toString() == "current-open") { if(u) { switch(u->lastMessageType()) { case 0: nm.setType(""); break; case 1: nm.setType("chat"); break; } } } if (!nm.body().isEmpty()) { UserListItem *u = findFirstRelevant(m.to()); if (!u || (u->subscription().type() != Subscription::Both && u->subscription().type() != Subscription::From)) { nm.setNick(nick()); } } d->client->sendMessage(nm); // only toggle if not an invite or body is not empty if(m.invite().isEmpty() && !m.body().isEmpty()) toggleSecurity(m.to(), m.wasEncrypted()); // don't log groupchat, private messages, or encrypted messages if(d->acc.opt_log && log) { if(m.type() != "groupchat" && m.xencrypted().isEmpty() && !findGCContact(m.to())) { MessageEvent *me = new MessageEvent(m, this); me->setOriginLocal(true); me->setTimeStamp(QDateTime::currentDateTime()); logEvent(m.to(), me); delete me; } } // don't sound when sending groupchat messages or message events if(m.type() != "groupchat" && !m.body().isEmpty()) playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.outgoing-chat").toString()); // auto close an open messagebox (if non-chat) if(m.type() != "chat" && !m.body().isEmpty()) { UserListItem *u = findFirstRelevant(m.to()); if(u) { EventDlg *e = findDialog(u->jid()); if(e) e->closeAfterReply(); } } } void PsiAccount::dj_newMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread) { EventDlg *w = d->psi->createEventDlg(jid.full(), this); if (!body.isEmpty()) { w->setHtml(TextUtil::plain2rich(body)); } if (!subject.isEmpty()) { w->setSubject(subject); } if (!thread.isEmpty()) { w->setThread(thread); } w->show(); } void PsiAccount::dj_replyMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread) { QString re = (!subject.isEmpty() && subject.left(3) != "Re:") ? "Re: " : QString(); dj_newMessage(jid, !body.isEmpty() ? TextUtil::quote(body) : body, re + subject, thread); } void PsiAccount::dj_replyMessage(const Jid &j, const QString &body) { dj_replyMessage(j, body, QString::null, QString::null); } void PsiAccount::dj_addAuth(const Jid &j) { dj_addAuth(j,QString()); } void PsiAccount::dj_addAuth(const Jid &j, const QString& nick) { QString name; QStringList groups; UserListItem *u = d->userList.find(j); if(u) { name = u->name(); groups = u->groups(); } else if (!nick.isEmpty()){ name = nick; } dj_add(j, name, groups, true); dj_auth(j); } void PsiAccount::dj_confirmHttpAuth(const PsiHttpAuthRequest &req) { d->httpAuthManager->confirm(req); } void PsiAccount::dj_denyHttpAuth(const PsiHttpAuthRequest &req) { d->httpAuthManager->deny(req); } void PsiAccount::dj_formSubmit(const XData& data, const QString& thread, const Jid& jid) { Message m; m.setTo(jid); m.setThread(thread, true); m.setForm(data); d->client->sendMessage(m); } void PsiAccount::dj_formCancel(const XData& data, const QString& thread, const Jid& jid) { Message m; m.setTo(jid); m.setThread(thread, true); m.setForm(data); d->client->sendMessage(m); } void PsiAccount::dj_add(const XMPP::Jid &j, const QString &name, const QStringList &groups, bool authReq) { JT_Roster *r = new JT_Roster(d->client->rootTask()); r->set(j, name, groups); r->go(true); if(authReq) dj_authReq(j); } void PsiAccount::dj_authReq(const Jid &j) { d->client->sendSubscription(j, "subscribe", nick()); } void PsiAccount::dj_auth(const Jid &j) { d->client->sendSubscription(j, "subscribed"); } void PsiAccount::dj_deny(const Jid &j) { d->client->sendSubscription(j, "unsubscribed"); } void PsiAccount::dj_rename(const Jid &j, const QString &name) { UserListItem *u = d->userList.find(j); if(!u) return; QString str; if(name == u->jid().full()) str = ""; else str = name; // strange workaround to avoid a null string ?? QString uname; if(u->name().isEmpty()) uname = ""; else uname = u->name(); if(uname == str) return; u->setName(str); cpUpdate(*u); if(u->inList()) { JT_Roster *r = new JT_Roster(d->client->rootTask()); r->set(u->jid(), u->name(), u->groups()); r->go(true); } } void PsiAccount::dj_remove(const Jid &j) { UserListItem *u = d->userList.find(j); if(!u) return; // remove all events from the queue d->eventQueue->clear(j); updateReadNext(j); // TODO: delete the item immediately (to simulate local change) if(!u->inList()) { //simulateContactOffline(u); d->userList.removeAll(u); delete u; } else { JT_Roster *r = new JT_Roster(d->client->rootTask()); r->remove(j); r->go(true); // if it looks like a transport, unregister (but not if it is the server!!) if(u->isTransport() && !Jid(d->client->host()).compare(u->jid())) { JT_UnRegister *ju = new JT_UnRegister(d->client->rootTask()); ju->unreg(j); ju->go(true); } } } void PsiAccount::dj_rosterExchange(const RosterExchangeItems& items) { foreach(RosterExchangeItem item, items) { if (!validRosterExchangeItem(item)) continue; if (item.action() == RosterExchangeItem::Add) { if (d->client->roster().find(item.jid(),true) == d->client->roster().end()) { dj_add(item.jid(),item.name(),item.groups(),true); } } else if (item.action() == RosterExchangeItem::Delete) { //dj_remove(item.jid()); } else if (item.action() == RosterExchangeItem::Modify) { // TODO } } } void PsiAccount::eventFromXml(PsiEvent* e) { handleEvent(e, FromXml); } // handle an incoming event void PsiAccount::handleEvent(PsiEvent* e, ActivationType activationType) { if ( e ) { setEnabled(); } bool doPopup = false; bool putToQueue = true; PsiPopup::PopupType popupType = PsiPopup::AlertNone; // find someone to accept the event Jid j; QList ul = findRelevant(e->from()); if(ul.isEmpty()) { // if groupchat, then we want the full JID if(findGCContact(e->from())) { j = e->from(); } else { Jid bare = e->from().bare(); Jid reg = bare.withResource("registered"); // see if we have a "registered" variant of the jid if(findFirstRelevant(reg)) { j = reg; e->setFrom(reg); // HACK!! } // retain full jid if sent to "registered" else if(e->from().resource() == "registered") j = e->from(); // otherwise don't use the resource for new entries else j = bare; } } else { j = ul.first()->jid(); } e->setJid(j); #ifdef PSI_PLUGINS QDomElement eXml = e->toXml(new QDomDocument()); if (PluginManager::instance()->processEvent(this, eXml)) { delete e; return; } //FIXME(KIS): must now cause the event to be recreated from this xml or such. Horrid. #endif if(d->acc.opt_log && activationType != FromXml) { if(e->type() == PsiEvent::Message || e->type() == PsiEvent::Auth) { // don't log private messages if(!findGCContact(e->from()) && !(e->type() == PsiEvent::Message && ((MessageEvent *)e)->message().body().isEmpty())) logEvent(e->from(), e); } } if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); #ifdef PSI_PLUGINS //TODO(mck): clean up //UserListItem *ulItem=NULL; //if ( !ul.isEmpty() ) // ulItem=ul.first(); if (PluginManager::instance()->processMessage(this, e->from().full(), m.body(), m.subject())) { delete e; return; } //PluginManager::instance()->message(this,e->from(),ulItem,((MessageEvent*)e)->message().body()); #endif // Pass message events to chat window if ((m.containsEvents() || m.chatState() != StateNone) && m.body().isEmpty()) { if (PsiOptions::instance()->getOption("options.messages.send-composing-events").toBool()) { ChatDlg *c = findChatDialog(e->from()); if (!c) { c = findChatDialog(e->jid()); } if (c) { c->incomingMessage(m); } } return; } // pass chat messages directly to a chat window if possible (and deal with sound) if(m.type() == "chat") { ChatDlg *c = findChatDialog(e->from()); if(!c) c = findChatDialog(e->jid()); if(c) c->setJid(e->from()); //if the chat exists, and is either open in a tab, //or in a window if( c && ( d->tabManager->isChatTabbed(c) || !c->isHidden() ) ) { c->incomingMessage(m); playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.chat-message").toString()); if(PsiOptions::instance()->getOption("options.ui.chat.alert-for-already-open-chats").toBool() && !c->isActiveTab()) { // to alert the chat also, we put it in the queue me->setSentToChatWindow(true); } else putToQueue = false; } else { bool firstChat = !d->eventQueue->hasChats(e->from()); playSound(PsiOptions::instance()->getOption(firstChat ? "options.ui.notifications.sounds.new-chat": "options.ui.notifications.sounds.chat-message").toString()); } if (putToQueue) { doPopup = true; popupType = PsiPopup::AlertChat; } } // /chat else if (m.type() == "headline") { playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-headline").toString()); doPopup = true; popupType = PsiPopup::AlertHeadline; } // /headline else if (m.type().isEmpty()) { playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-message").toString()); doPopup = true; popupType = PsiPopup::AlertMessage; } // /"" else playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.system-message").toString()); if(m.type() == "error") { // FIXME: handle message errors //msg.text = QString(tr("[Error Message]
%1").arg(plain2rich(msg.text))); } } else if(e->type() == PsiEvent::HttpAuth) { playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.system-message").toString()); } else if(e->type() == PsiEvent::File) { playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-file-transfer").toString()); doPopup = true; popupType = PsiPopup::AlertFile; } else if(e->type() == PsiEvent::AvCallType) { playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.incoming-file-transfer").toString()); doPopup = true; popupType = PsiPopup::AlertAvCall; } else if(e->type() == PsiEvent::RosterExchange) { RosterExchangeEvent* re = (RosterExchangeEvent*) e; RosterExchangeItems items; foreach(RosterExchangeItem item, re->rosterExchangeItems()) { if (validRosterExchangeItem(item)) items += item; } if (items.isEmpty()) { delete e; return; } re->setRosterExchangeItems(items); playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.system-message").toString()); } else if (e->type() == PsiEvent::Auth) { playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.system-message").toString()); AuthEvent *ae = (AuthEvent *)e; if(ae->authType() == "subscribe") { if(PsiOptions::instance()->getOption("options.subscriptions.automatically-allow-authorization").toBool()) { // Check if we want to request auth as well UserListItem *u = d->userList.find(ae->from()); if (!u || (u->subscription().type() != Subscription::Both && u->subscription().type() != Subscription::To)) { dj_addAuth(ae->from(),ae->nick()); } else { dj_auth(ae->from()); } putToQueue = false; } } else if(ae->authType() == "subscribed") { if(!PsiOptions::instance()->getOption("options.ui.notifications.successful-subscription").toBool()) putToQueue = false; } else if(ae->authType() == "unsubscribe") { putToQueue = false; } } else { putToQueue = false; doPopup = false; } if (doPopup && !d->noPopup(activationType)) { Resource r; UserListItem *u = findFirstRelevant(j); if (u && u->priority() != u->userResourceList().end()) { r = *(u->priority()); } if ((popupType == PsiPopup::AlertChat && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-chat").toBool()) || (popupType == PsiPopup::AlertMessage && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-message").toBool()) || (popupType == PsiPopup::AlertHeadline && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-headline").toBool()) || (popupType == PsiPopup::AlertFile && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-file-transfer").toBool()) || (popupType == PsiPopup::AlertAvCall && PsiOptions::instance()->getOption("options.ui.notifications.passive-popups.incoming-message").toBool())) { PsiPopup *popup = new PsiPopup(popupType, this); popup->setData(j, r, u, e); } #if defined(Q_WS_MAC) && defined(HAVE_GROWL) PsiGrowlNotifier::instance()->popup(this, popupType, j, r, u, e); #endif emit startBounce(); } if ( putToQueue ) queueEvent(e, activationType); else delete e; } UserListItem* PsiAccount::addUserListItem(const Jid& jid, const QString& nick) { // create item UserListItem *u = new UserListItem; u->setJid(jid); u->setInList(false); u->setAvatarFactory(avatarFactory()); u->setName(nick); // is it a private groupchat? Jid j = u->jid(); GCContact *c = findGCContact(j); if(c) { u->setName(j.resource()); u->setPrivate(true); // make a resource so the contact appears online UserResource ur; ur.setName(j.resource()); ur.setStatus(c->status); u->userResourceList().append(ur); } // treat it like a push [pushinfo] //VCard info; //if(readUserInfo(item->jid, &info) && !info.field[vNickname].isEmpty()) // item->nick = info.field[vNickname]; //else { // if(localStatus != STATUS_OFFLINE) // serv->getVCard(item->jid); //} d->userList.append(u); cpUpdate(*u); return u; } // put an event into the event queue, and update the related alerts void PsiAccount::queueEvent(PsiEvent* e, ActivationType activationType) { // do we have roster item for this? UserListItem *u = find(e->jid()); if(!u) { QString nick; if (e->type() == PsiEvent::Auth) { AuthEvent* ae = (AuthEvent*) e; nick = ae->nick(); } else if (e->type() == PsiEvent::Message) { MessageEvent* me = (MessageEvent*) e; if (me->message().type() != "error") nick = me->nick(); } u = addUserListItem(e->jid(), nick); } //printf("queuing message from [%s] for [%s].\n", e->from().full().latin1(), e->jid().full().latin1()); d->eventQueue->enqueue(e); updateReadNext(e->jid()); if(PsiOptions::instance()->getOption("options.ui.contactlist.raise-on-new-event").toBool()) d->psi->raiseMainwin(); // update the roster cpUpdate(*u); // FIXME: We shouldn't be doing this kind of stuff here, because this // function is named *queue*Event() not deleteThisMessageSometimes() if (!d->noPopup(activationType)) { bool doPopup = false; // Check to see if we need to popup if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); if (m.type() == "chat") doPopup = PsiOptions::instance()->getOption("options.ui.chat.auto-popup").toBool(); else if (m.type() == "headline") doPopup = PsiOptions::instance()->getOption("options.ui.message.auto-popup-headlines").toBool(); else doPopup = PsiOptions::instance()->getOption("options.ui.message.auto-popup").toBool(); } else if (e->type() == PsiEvent::File) { doPopup = PsiOptions::instance()->getOption("options.ui.file-transfer.auto-popup").toBool(); } else { doPopup = PsiOptions::instance()->getOption("options.ui.message.auto-popup").toBool(); } // Popup if (doPopup) { UserListItem *u = find(e->jid()); if (u && (!PsiOptions::instance()->getOption("options.ui.notifications.popup-dialogs.suppress-when-not-on-roster").toBool() || u->inList())) openNextEvent(*u, activationType); } } } // take the next event from the queue and display it void PsiAccount::openNextEvent(const UserListItem& u, ActivationType activationType) { PsiEvent *e = d->eventQueue->peek(u.jid()); if(!e) return; psi()->processEvent(e, activationType); } void PsiAccount::openNextEvent(ActivationType activationType) { PsiEvent *e = d->eventQueue->peekNext(); if(!e) return; if(e->type() == PsiEvent::PGP) { psi()->processEvent(e, activationType); return; } UserListItem *u = find(e->jid()); if(!u) return; openNextEvent(*u, activationType); } int PsiAccount::forwardPendingEvents(const Jid &jid) { QList chatList; d->eventQueue->extractMessages(&chatList); foreach(PsiEvent* e, chatList) { MessageEvent *me = (MessageEvent *) e; Message m = me->message(); AddressList oFrom = m.findAddresses(Address::OriginalFrom); AddressList oTo = m.findAddresses(Address::OriginalTo); if (oFrom.count() == 0) m.addAddress(Address(Address::OriginalFrom, m.from())); if (oTo.count() == 0) m.addAddress(Address(Address::OriginalTo, m.to())); m.setTimeStamp(m.timeStamp(), true); m.setTo(jid); m.setFrom(""); d->client->sendMessage(m); // update the eventdlg UserListItem *u = find(e->jid()); delete e; // update the contact if(u) cpUpdate(*u); updateReadNext(u->jid()); } return chatList.count(); } void PsiAccount::updateReadNext(const Jid &j) { // update eventdlg's read-next EventDlg *w = findDialog(j); if(w) { PsiIcon *nextAnim = 0; int nextAmount = d->eventQueue->count(j); if(nextAmount > 0) nextAnim = PsiIconset::instance()->event2icon(d->eventQueue->peek(j)); w->updateReadNext(nextAnim, nextAmount); } queueChanged(); } void PsiAccount::processReadNext(const Jid &j) { UserListItem *u = find(j); if(u) processReadNext(*u); } void PsiAccount::processReadNext(const UserListItem &u) { EventDlg *w = findDialog(u.jid()); if(!w) { // this should NEVER happen return; } // peek the event PsiEvent *e = d->eventQueue->peek(u.jid()); if(!e) return; bool isChat = false; if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); if(m.type() == "chat" && m.getForm().fields().empty()) isChat = true; } // if it's a chat message, just open the chat window. there is no need to do // further processing. the chat window will remove it from the queue, update // the cvlist, etc etc. if(isChat) { openChat(e->from(), UserAction); return; } // remove from queue e = d->eventQueue->dequeue(u.jid()); // update the eventdlg w->updateEvent(e); delete e; // update the contact cpUpdate(u); updateReadNext(u.jid()); } void PsiAccount::processChats(const Jid &j) { //printf("processing chats for [%s]\n", j.full().latin1()); ChatDlg *c = findChatDialog(j); if(!c) return; // extract the chats QList chatList; d->eventQueue->extractChats(&chatList, j); if(!chatList.isEmpty()) { // dump the chats into the chat window, and remove the related cvlist alerts foreach(PsiEvent *e, chatList) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); // process the message if(!me->sentToChatWindow()) c->incomingMessage(m); } while (!chatList.isEmpty()) delete chatList.takeFirst(); QList ul = findRelevant(j); if(!ul.isEmpty()) { UserListItem *u = ul.first(); cpUpdate(*u); updateReadNext(u->jid()); } } } void PsiAccount::openChat(const Jid& j, ActivationType activationType) { ChatDlg* chat = ensureChatDlg(j); chat->ensureTabbedCorrectly(); processChats(j); if (activationType == UserAction) { chat->bringToFront(); } } void PsiAccount::chatMessagesRead(const Jid &j) { if(PsiOptions::instance()->getOption("options.ui.chat.alert-for-already-open-chats").toBool()) { processChats(j); } } void PsiAccount::logEvent(const Jid &j, PsiEvent *e) { EDBHandle *h = new EDBHandle(d->psi->edb()); connect(h, SIGNAL(finished()), SLOT(edb_finished())); h->append(j, e); } void PsiAccount::edb_finished() { EDBHandle *h = (EDBHandle *)sender(); delete h; } void PsiAccount::openGroupChat(const Jid &j, ActivationType activationType) { QString str = j.bare(); bool found = false; for(QStringList::ConstIterator it = d->groupchats.begin(); it != d->groupchats.end(); ++it) { if((*it) == str) { found = true; break; } } if(!found) d->groupchats += str; GCMainDlg *w = new GCMainDlg(this, j, d->tabManager); w->setPassword(d->client->groupChatPassword(j.node(),j.domain())); connect(w, SIGNAL(aSend(const Message &)), SLOT(dj_sendMessage(const Message &))); connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate())); w->ensureTabbedCorrectly(); if (activationType == UserAction) w->bringToFront(); } bool PsiAccount::groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString& pass, bool nohistory) { if (nohistory) return d->client->groupChatJoin(host, room, nick, pass, 0); else { Status s = d->loginStatus; s.setXSigned(""); return d->client->groupChatJoin(host, room, nick, pass, d->options->getOption("options.muc.context.maxchars").toInt(),d->options->getOption("options.muc.context.maxstanzas").toInt(),d->options->getOption("options.muc.context.seconds").toInt(),s); } } void PsiAccount::groupChatChangeNick(const QString &host, const QString &room, const QString& nick, const Status &s) { d->client->groupChatChangeNick(host, room, nick, s); } void PsiAccount::groupChatSetStatus(const QString &host, const QString &room, const Status &s) { d->client->groupChatSetStatus(host, room, s); } void PsiAccount::groupChatLeave(const QString &host, const QString &room) { d->groupchats.removeAll(room + '@' + host); d->client->groupChatLeave(host, room); } GCContact *PsiAccount::findGCContact(const Jid &j) { foreach(GCContact *c, d->gcbank) { if(c->jid.compare(j)) return c; } return 0; } QStringList PsiAccount::groupchats() const { return d->groupchats; } void PsiAccount::client_groupChatJoined(const Jid &j) { //d->client->groupChatSetStatus(j.domain(), j.node(), d->loginStatus); GCMainDlg *m = findDialog(Jid(j.bare())); if(m) { m->setPassword(d->client->groupChatPassword(j.node(),j.domain())); m->joined(); return; } MUCJoinDlg *w = findDialog(j); if(!w) return; w->joined(); // TODO: Correctly handle auto-join groupchats openGroupChat(j, UserAction); } void PsiAccount::client_groupChatLeft(const Jid &j) { // remove all associated groupchat contacts from the bank for(QList::Iterator it = d->gcbank.begin(); it != d->gcbank.end(); ) { GCContact *c = *it; // contact from this room? if(!c->jid.compare(j, false)) { ++it; continue; } UserListItem *u = find(c->jid); if(!u) { ++it; continue; } simulateContactOffline(u); it = d->gcbank.erase(it); delete c; } } void PsiAccount::client_groupChatPresence(const Jid &j, const Status &s) { GCMainDlg *w = findDialog(Jid(j.bare())); if(!w) return; GCContact *c = findGCContact(j); if(!c) { c = new GCContact; c->jid = j; c->status = s; d->gcbank.append(c); } w->presence(j.resource(), s); // pass through the core presence handling also (so that roster items // from groupchat contacts get a resource as well Resource r; r.setName(j.resource()); r.setStatus(s); if(s.isAvailable()) client_resourceAvailable(j, r); else client_resourceUnavailable(j, j.resource()); } void PsiAccount::client_groupChatError(const Jid &j, int code, const QString &str) { GCMainDlg *w = findDialog(Jid(j.bare())); if(w) { w->error(code, str); } else { MUCJoinDlg *w = findDialog(j); if(w) { w->error(code, str); } } } QStringList PsiAccount::hiddenChats(const Jid &j) const { QStringList list; foreach(ChatDlg* chat, findDialogs(j, false)) list += chat->jid().resource(); return list; } void PsiAccount::slotCheckVCard() { if (!isConnected() || !isActive()) return; QString nick = d->jid.node(); JT_VCard* j = static_cast(sender()); if (j->success() && j->statusCode() == Task::ErrDisc) { if (!j->vcard().nickName().isEmpty()) { d->nickFromVCard = true; nick = j->vcard().nickName(); } else if (!j->vcard().fullName().isEmpty()) { d->nickFromVCard = true; nick = j->vcard().fullName(); } } if (j->vcard().isEmpty()) { changeVCard(); return; } if (!j->vcard().photo().isEmpty()) { d->vcardPhotoUpdate(j->vcard().photo()); } setNick(nick); } void PsiAccount::setNick(const QString &nick) { d->self.setName(nick); cpUpdate(d->self); nickChanged(); } QString PsiAccount::nick() const { return d->self.name(); } //void PsiAccount::pgpToggled(bool b) //{ // QCA::PGPKey oldkey = d->cur_pgpSecretKey; // // // gaining pgp? // if(b) // d->cur_pgpSecretKey = d->acc.pgpSecretKey; // // losing it? // else { // d->cur_pgpSecretKey = QCA::PGPKey(); // } // // if(!PGPUtil::instance().equals(oldkey,d->cur_pgpSecretKey)) { // pgpKeyChanged(); // // resend status if online // if(loggedIn()) // setStatusDirect(d->loginStatus); // } //} void PsiAccount::pgpKeysUpdated() { // are there any sigs that need verifying? foreach(UserListItem* u, d->userList) { UserResourceList &rl = u->userResourceList(); for(UserResourceList::Iterator rit = rl.begin(); rit != rl.end(); ++rit) { UserResource &r = *rit; if(!r.status().xsigned().isEmpty() && r.pgpVerifyStatus() == QCA::SecureMessageSignature::NoKey) { QCA::KeyStoreEntry e = PGPUtil::instance().getPublicKeyStoreEntry(r.publicKeyID()); if (!e.isNull()) tryVerify(u, &r); } } } } void PsiAccount::trySignPresence() { QCA::SecureMessageKey skey; skey.setPGPSecretKey(d->cur_pgpSecretKey); QByteArray plain = d->loginStatus.status().toUtf8(); PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP()); connect(t, SIGNAL(finished()), SLOT(pgp_signFinished())); t->setFormat(QCA::SecureMessage::Ascii); t->setSigner(skey); t->startSign(QCA::SecureMessage::Detached); t->update(plain); t->end(); } void PsiAccount::pgp_signFinished() { PGPTransaction *t = (PGPTransaction*) sender(); if (t->success()) { Status s = d->loginStatus; s.setXSigned(PGPUtil::instance().stripHeaderFooter(QString(t->signature()))); setStatusActual(s); } else { // Clear passphrase from cache if (t->errorCode() == QCA::SecureMessage::ErrorPassphrase) { QCA::KeyStoreEntry ke = PGPUtil::instance().getSecretKeyStoreEntry(d->cur_pgpSecretKey.keyId()); if (!ke.isNull()) PGPUtil::instance().removePassphrase(ke.id()); } PGPUtil::showDiagnosticText(tr("There was an error trying to sign your status.\nReason: %1.") .arg(PGPUtil::instance().messageErrorString(t->errorCode())), t->diagnosticText()); logout(); return; } t->deleteLater(); } void PsiAccount::verifyStatus(const Jid &j, const Status &s) { PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP()); t->setJid(j); connect(t, SIGNAL(finished()), SLOT(pgp_verifyFinished())); t->startVerify(PGPUtil::instance().addHeaderFooter(s.xsigned(),1).toUtf8()); t->update(s.status().toUtf8()); t->end(); } void PsiAccount::pgp_verifyFinished() { PGPTransaction *t = (PGPTransaction*) sender(); Jid j = t->jid(); foreach(UserListItem *u, findRelevant(j)) { UserResourceList::Iterator rit = u->userResourceList().find(j.resource()); bool found = (rit == u->userResourceList().end()) ? false: true; if(!found) continue; UserResource &ur = *rit; QCA::SecureMessageSignature signer; if(t->success()) { signer = t->signer(); ur.setPublicKeyID(signer.key().pgpPublicKey().keyId()); ur.setPGPVerifyStatus(signer.identityResult()); ur.setSigTimestamp(signer.timestamp()); // if the key doesn't match the assigned key, unassign it if(signer.key().pgpPublicKey().keyId() != u->publicKeyID()) u->setPublicKeyID(""); } else { ur.setPGPVerifyStatus(-1); } cpUpdate(*u); } t->deleteLater(); } int PsiAccount::sendMessageEncrypted(const Message &_m) { if(!ensureKey(_m.to())) return -1; QString keyID = findFirstRelevant(_m.to())->publicKeyID(); QCA::KeyStoreEntry keyEntry = PGPUtil::instance().getPublicKeyStoreEntry(keyID); if (keyEntry.isNull()) return -1; QCA::SecureMessageKey key; key.setPGPPublicKey(keyEntry.pgpPublicKey()); PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP()); t->setMessage(_m); connect(t, SIGNAL(finished()), SLOT(pgp_encryptFinished())); t->setFormat(QCA::SecureMessage::Ascii); t->setRecipient(key); t->startEncrypt(); t->update(_m.body().toUtf8()); t->end(); return t->id(); } void PsiAccount::pgp_encryptFinished() { PGPTransaction *pt = (PGPTransaction *)sender(); int x = pt->id(); if(pt->success()) { Message m = pt->message(); // log the message here, before we encrypt it if(d->acc.opt_log) { MessageEvent *me = new MessageEvent(m, this); me->setOriginLocal(true); me->setTimeStamp(QDateTime::currentDateTime()); logEvent(m.to(), me); delete me; } Message mwrap; mwrap.setTo(m.to()); mwrap.setType(m.type()); QString enc = PGPUtil::instance().stripHeaderFooter(pt->read()); mwrap.setBody(tr("[ERROR: This message is encrypted, and you are unable to decrypt it.]")); mwrap.setXEncrypted(enc); mwrap.setWasEncrypted(true); // FIXME: Should be done cleaner, with an extra method in Iris if (m.containsEvent(OfflineEvent)) mwrap.addEvent(OfflineEvent); if (m.containsEvent(DeliveredEvent)) mwrap.addEvent(DeliveredEvent); if (m.containsEvent(DisplayedEvent)) mwrap.addEvent(DisplayedEvent); if (m.containsEvent(ComposingEvent)) mwrap.addEvent(ComposingEvent); if (m.containsEvent(CancelEvent)) mwrap.addEvent(CancelEvent); mwrap.setChatState(m.chatState()); dj_sendMessage(mwrap); } emit encryptedMessageSent(x, pt->success(), pt->errorCode(), pt->diagnosticText()); pt->deleteLater(); } void PsiAccount::processEncryptedMessage(const Message &m) { PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP()); t->setMessage(m); connect(t, SIGNAL(finished()), SLOT(pgp_decryptFinished())); t->setFormat(QCA::SecureMessage::Ascii); t->startDecrypt(); t->update(PGPUtil::instance().addHeaderFooter(m.xencrypted(),0).toUtf8()); t->end(); } void PsiAccount::pgp_decryptFinished() { PGPTransaction *pt = (PGPTransaction*) sender(); bool tryAgain = false; if (pt->success()) { Message m = pt->message(); m.setBody(QString::fromUtf8(pt->read())); m.setXEncrypted(""); m.setWasEncrypted(true); processIncomingMessage(m); } else { if (loggedIn()) { Message m; m.setTo(pt->message().from()); m.setType("error"); if (!pt->message().id().isEmpty()) m.setId(pt->message().id()); m.setBody(pt->message().body()); m.setError(Stanza::Error(Stanza::Error::Modify, Stanza::Error::NotAcceptable, "Unable to decrypt")); d->client->sendMessage(m); } } pt->deleteLater(); if (tryAgain) { processEncryptedMessageNext(); } else { processEncryptedMessageDone(); } } void PsiAccount::processMessageQueue() { while(!d->messageQueue.isEmpty()) { Message *mp = d->messageQueue.first(); // encrypted? if(PGPUtil::instance().pgpAvailable() && !mp->xencrypted().isEmpty()) { processEncryptedMessageNext(); break; } processIncomingMessage(*mp); d->messageQueue.removeAll(mp); delete mp; } } void PsiAccount::processEncryptedMessageNext() { // 'peek' and try to process it Message *mp = d->messageQueue.first(); processEncryptedMessage(*mp); } void PsiAccount::processEncryptedMessageDone() { // 'pop' the message if (!d->messageQueue.isEmpty()) delete d->messageQueue.takeFirst(); // do the rest of the queue processMessageQueue(); } void PsiAccount::optionsUpdate() { d->cp->updateEntry(d->self); // Tune #ifdef USE_PEP bool publish = d->options->getOption("options.extended-presence.tune.publish").toBool(); if (!d->lastTune.isNull() && !publish) { publishTune(Tune()); } else if (d->lastTune.isNull() && publish) { Tune current = d->psi->tuneController()->currentTune(); if (!current.isNull()) publishTune(current); } #endif // Chat states setSendChatState(PsiOptions::instance()->getOption("options.messages.send-composing-events").toBool()); // Remote Controlling setRCEnabled(PsiOptions::instance()->getOption("options.external-control.adhoc-remote-control.enable").toBool()); // Roster item exchange d->rosterItemExchangeTask->setIgnoreNonRoster(PsiOptions::instance()->getOption("options.messages.ignore-non-roster-contacts").toBool()); // Caps manager d->capsManager->setEnabled(PsiOptions::instance()->getOption("options.service-discovery.enable-entity-capabilities").toBool()); } void PsiAccount::setRCEnabled(bool b) { if (b && !d->rcSetStatusServer) { d->rcSetStatusServer = new RCSetStatusServer(d->ahcManager); d->rcForwardServer = new RCForwardServer(d->ahcManager); d->rcSetOptionsServer = new RCSetOptionsServer(d->ahcManager, d->psi); } else if (!b && d->rcSetStatusServer) { delete d->rcSetStatusServer; d->rcSetStatusServer = 0; delete d->rcForwardServer; d->rcForwardServer = 0; delete d->rcSetOptionsServer; d->rcSetOptionsServer = 0; } } void PsiAccount::setSendChatState(bool b) { if (b && !d->client->extensions().contains("cs")) { d->client->addExtension("cs",Features("http://jabber.org/protocol/chatstates")); if (isConnected()) setStatusActual(d->loginStatus); } else if (!b && d->client->extensions().contains("cs")) { d->client->removeExtension("cs"); if (isConnected()) setStatusActual(d->loginStatus); } } void PsiAccount::invokeGCMessage(const Jid &j) { GCContact *c = findGCContact(j); if(!c) return; // create dummy item, open chat, then destroy item. HORRIBLE HACK! UserListItem *u = new UserListItem; u->setJid(j); u->setInList(false); u->setName(j.resource()); u->setPrivate(true); // make a resource so the contact appears online UserResource ur; ur.setName(j.resource()); ur.setStatus(c->status); u->userResourceList().append(ur); d->userList.append(u); actionSendMessage(j); d->userList.removeAll(u); delete u; } void PsiAccount::invokeGCChat(const Jid &j) { GCContact *c = findGCContact(j); if(!c) return; // create dummy item, open chat, then destroy item. HORRIBLE HACK! // note: we no longer destroy the item (commented out below) UserListItem *u = new UserListItem; u->setJid(j); u->setInList(false); u->setName(j.resource()); u->setPrivate(true); // make a resource so the contact appears online UserResource ur; ur.setName(j.resource()); ur.setStatus(c->status); u->userResourceList().append(ur); d->userList.append(u); actionOpenChat(j); cpUpdate(*u); //d->userList.removeAll(u); //delete u; } void PsiAccount::invokeGCInfo(const Jid &j) { actionInfo(j); } void PsiAccount::invokeGCFile(const Jid &j) { actionSendFile(j); } void PsiAccount::toggleSecurity(const Jid &j, bool b) { UserListItem *u = findFirstRelevant(j); if(!u) return; bool isBare = j.resource().isEmpty(); bool isPriority = false; // sick sick sick sick sick sick UserResource *r1, *r2; r1 = r2 = 0; UserResourceList::Iterator it1 = u->userResourceList().find(j.resource()); UserResourceList::Iterator it2 = u->userResourceList().priority(); r1 = (it1 != u->userResourceList().end() ? &(*it1) : 0); r2 = (it2 != u->userResourceList().end() ? &(*it2) : 0); if(r1 && (r1 == r2)) isPriority = true; bool needUpdate = false; bool sec = u->isSecure(j.resource()); if(sec != b) { u->setSecure(j.resource(), b); needUpdate = true; } if(isBare && r2) { sec = u->isSecure(r2->name()); if(sec != b) { u->setSecure(r2->name(), b); needUpdate = true; } } if(isPriority) { sec = u->isSecure(""); if(sec != b) { u->setSecure("", b); needUpdate = true; } } if(needUpdate) cpUpdate(*u); } bool PsiAccount::ensureKey(const Jid &j) { if(!PGPUtil::instance().pgpAvailable()) return false; UserListItem *u = findFirstRelevant(j); if(!u) return false; // no key? if(u->publicKeyID().isEmpty()) { // does the user have any presence signed with a key? QString akey; const UserResourceList &rl = u->userResourceList(); for(UserResourceList::ConstIterator it = rl.begin(); it != rl.end(); ++it) { const UserResource &r = *it; if(!r.publicKeyID().isEmpty()) { akey = r.publicKeyID(); break; } } if(akey.isEmpty() || PGPUtil::instance().getPublicKeyStoreEntry(akey).isNull()) { int n = QMessageBox::information(0, CAP(tr("No key")), tr( "

Psi was unable to locate the OpenPGP key to use for %1.
" "
" "This can happen if you do not have the key that the contact is advertising " "via signed presence, or if the contact is not advertising any key at all.

" ).arg(JIDUtil::toString(u->jid(),true)), tr("&Choose key manually"), tr("Do ¬hing")); if(n != 0) return false; } // Select a key PGPKeyDlg *w = new PGPKeyDlg(PGPKeyDlg::Public, akey, 0); w->setWindowTitle(tr("Public Key: %1").arg(JIDUtil::toString(j,true))); int r = w->exec(); QCA::KeyStoreEntry entry; if(r == QDialog::Accepted) entry = w->keyStoreEntry(); delete w; if(entry.isNull()) return false; u->setPublicKeyID(entry.pgpPublicKey().keyId()); cpUpdate(*u); } return true; } ServerInfoManager* PsiAccount::serverInfoManager() { return d->serverInfoManager; } PEPManager* PsiAccount::pepManager() { return d->pepManager; } BookmarkManager* PsiAccount::bookmarkManager() { return d->bookmarkManager; } AvCallManager *PsiAccount::avCallManager() { return d->avCallManager; } /** * \brief Returns the current contents of the debug ringbuffer. * it doesn't clear the ringbuffer * \return a QList of the current debug buffer items. */ QList PsiAccount::dumpRingbuf() { return d->dumpRingbuf(); } #include "psiaccount.moc" psi-0.14/src/changepwdlg.cpp0000644000175000017500000000775311305557613014133 0ustar janjan/* * changepwdlg.cpp - dialog for changing password * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "changepwdlg.h" #include #include #include #include #include #include #include "profiles.h" #include "psiaccount.h" #include "busywidget.h" #include "xmpp_tasks.h" #include "accountmodifydlg.h" #include "iconwidget.h" using namespace XMPP; ChangePasswordDlg::ChangePasswordDlg(PsiAccount *_pa, QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose, true); ui_.setupUi(this); pa = _pa; pa->dialogRegister(this); connect(pa, SIGNAL(disconnected()), SLOT(disc())); setWindowTitle(CAP(windowTitle())); connect(ui_.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), SLOT(close())); connect(ui_.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(apply())); adjustSize(); } ChangePasswordDlg::~ChangePasswordDlg() { pa->dialogUnregister(this); } /*void ChangePasswordDlg::closeEvent(QCloseEvent *e) { e->ignore(); reject(); }*/ void ChangePasswordDlg::done(int r) { if(ui_.busy->isActive()) return; QDialog::done(r); } void ChangePasswordDlg::apply() { // sanity check if(ui_.le_pwcur->text().isEmpty() || ui_.le_pwnew->text().isEmpty() || ui_.le_pwver->text().isEmpty()) { QMessageBox::information(this, tr("Error"), tr("You must fill out the fields properly before you can proceed.")); return; } if(ui_.le_pwcur->text() != pa->userAccount().pass) { QMessageBox::information(this, tr("Error"), tr("You entered your old password incorrectly. Try again.")); ui_.le_pwcur->setText(""); ui_.le_pwcur->setFocus(); return; } if(ui_.le_pwnew->text() != ui_.le_pwver->text()) { QMessageBox::information(this, tr("Error"), tr("New password and confirmation do not match. Please enter them again.")); ui_.le_pwnew->setText(""); ui_.le_pwver->setText(""); ui_.le_pwnew->setFocus(); return; } ui_.busy->start(); blockWidgets(); JT_Register *reg = new JT_Register(pa->client()->rootTask()); connect(reg, SIGNAL(finished()), SLOT(finished())); Jid j = pa->userAccount().jid; reg->reg(j.node(), ui_.le_pwnew->text()); reg->go(true); } void ChangePasswordDlg::finished() { ui_.busy->stop(); JT_Register *reg = (JT_Register *)sender(); QString err = reg->statusString(); int code = reg->statusCode(); bool ok = reg->success(); if(ok) { UserAccount acc = pa->userAccount(); acc.pass = ui_.le_pwnew->text(); pa->setUserAccount(acc); AccountModifyDlg *amd = pa->findDialog(); if(amd) amd->setPassword(acc.pass); QMessageBox::information(this, tr("Success"), tr("Successfully changed password.")); close(); } else { // ignore task disconnect error if(code == Task::ErrDisc) return; QMessageBox::critical(this, tr("Error"), QString(tr("There was an error when trying to set the password.\nReason: %1")).arg(QString(err).replace('\n', "
"))); restoreWidgets(); } } void ChangePasswordDlg::disc() { ui_.busy->stop(); close(); } void ChangePasswordDlg::blockWidgets() { setWidgetsEnabled(false); } void ChangePasswordDlg::restoreWidgets() { setWidgetsEnabled(true); } void ChangePasswordDlg::setWidgetsEnabled(bool enabled) { foreach(QWidget* w, findChildren()) { w->setEnabled(enabled); } } psi-0.14/src/accountmodify.ui0000644000175000017500000007633011305557613014344 0ustar janjan AccountModify 0 0 528 386 Account Properties Name: QTabWidget::Rounded 0 Account 6 9 Account 6 11 0 6 false Example: juliet@capulet.com Jabber ID: 6 0 Password: QLineEdit::Password Change... Settings 6 10 Automatically connect on startup Automatically connect after sleep Automatically reconnect if disconnected Log message history Qt::Vertical QSizePolicy::Expanding 20 0 Details 6 9 Personal Information 6 11 <qt>Information about you is stored as a VCard on the server, which other people can retrieve at any time.</qt> true 6 0 Qt::Horizontal QSizePolicy::Expanding 0 0 Edit Personal &Details... OpenPGP 6 10 6 0 0 0 placeholder2 6 0 Qt::Horizontal QSizePolicy::Expanding 0 20 Select &Key... Use None Qt::Vertical QSizePolicy::Expanding 20 0 Privacy 6 9 1 6 0 Qt::Vertical 20 0 Qt::AlignCenter Qt::Vertical 20 0 6 0 Blocked Contacts 6 9 6 0 Add Remove Qt::Vertical 20 0 6 0 You are using advanced settings. This list may not be accurate. true Qt::Horizontal 0 20 Advanced ... Connection 6 9 6 0 Connection proxy: proxychooser Compress traffic (if possible) Send "keep-alive" packets (to prevent timeouts) Manually Specify Server Host/Port: 6 0 Host: Port: 56 0 56 32767 6 0 Encrypt connection: 0 0 QComboBox::AdjustToContents Qt::Horizontal QSizePolicy::Expanding 0 16 Probe legacy SSL port 6 0 Allow plaintext authentication: 0 0 QComboBox::AdjustToContents Qt::Horizontal QSizePolicy::Expanding 0 16 Require mutual authentication 6 0 SASL Security Level: 0 0 QComboBox::AdjustToContents Qt::Horizontal QSizePolicy::Expanding 0 16 Qt::Vertical QSizePolicy::Expanding 20 0 Misc. Use hostname as resource 6 0 Resource: 100 0 Priority: 0 0 56 0 56 32767 6 0 Data Transfer Proxy: STUN Host: Port: 56 0 56 16777215 Authenticate as: 6 0 false User: false 2 0 false Realm: false 3 0 Qt::Vertical QSizePolicy::Expanding 460 0 QDialogButtonBox::Cancel|QDialogButtonBox::Save qPixmapFromMimeSource IconLabel QWidget
iconlabel.h
1
le_name tab_main le_jid le_pass pb_changepw ck_auto ck_connectAfterSleep ck_reconn ck_log pb_vcard pb_key pb_keyclear lv_blocked pb_addBlock pb_removeBlock pb_privacy ck_compress ck_keepAlive ck_host le_host le_port cb_ssl ck_legacy_ssl_probe cb_plain ck_req_mutual cb_security_level ck_automatic_resource le_resource le_priority le_dtProxy le_stunHost le_stunPort ck_custom_auth le_authid le_realm buttonBox rejected() AccountModify reject() 346 439 523 386
psi-0.14/src/voicecalldlg.cpp0000644000175000017500000001203111305557613014261 0ustar janjan/* * voicecalldlg.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "voicecalldlg.h" #include "voicecaller.h" VoiceCallDlg::VoiceCallDlg(const Jid& jid, VoiceCaller* voiceCaller) : QDialog(0), jid_(jid), voiceCaller_(voiceCaller) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); setModal(false); setWindowTitle(QString(tr("Voice Call (%1)")).arg(jid.full())); // Voice Caller signals connect(voiceCaller_,SIGNAL(accepted(const Jid&)),SLOT(accepted(const Jid&))); connect(voiceCaller_,SIGNAL(rejected(const Jid&)),SLOT(rejected(const Jid&))); connect(voiceCaller_,SIGNAL(in_progress(const Jid&)),SLOT(in_progress(const Jid&))); connect(voiceCaller_,SIGNAL(terminated(const Jid&)),SLOT(terminated(const Jid&))); // Buttons ui_.pb_hangup->setEnabled(false); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); connect(ui_.pb_hangup,SIGNAL(clicked()),SLOT(terminate_call())); connect(ui_.pb_accept,SIGNAL(clicked()),SLOT(accept_call())); connect(ui_.pb_reject,SIGNAL(clicked()),SLOT(reject_call())); } void VoiceCallDlg::call() { setStatus(Calling); voiceCaller_->call(jid_); } void VoiceCallDlg::accept_call() { setStatus(Accepting); voiceCaller_->accept(jid_); } void VoiceCallDlg::reject_call() { setStatus(Rejecting); voiceCaller_->reject(jid_); finalize(); close(); } void VoiceCallDlg::terminate_call() { setStatus(Terminating); voiceCaller_->terminate(jid_); finalize(); close(); } void VoiceCallDlg::accepted(const Jid& j) { if (jid_.compare(j)) { setStatus(Accepted); } } void VoiceCallDlg::rejected(const Jid& j) { if (jid_.compare(j)) { setStatus(Rejected); finalize(); } } void VoiceCallDlg::in_progress(const Jid& j) { if (jid_.compare(j)) { setStatus(InProgress); } } void VoiceCallDlg::terminated(const Jid& j) { if (jid_.compare(j)) { setStatus(Terminated); finalize(); } } void VoiceCallDlg::incoming() { setStatus(Incoming); } void VoiceCallDlg::setStatus(CallStatus s) { status_ = s; switch (s) { case Calling: ui_.lb_status->setText(tr("Calling")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(true); break; case Accepting: ui_.lb_status->setText(tr("Accepting")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(true); break; case Rejecting: ui_.lb_status->setText(tr("Rejecting")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(false); break; case Terminating: ui_.lb_status->setText(tr("Hanging up")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(false); break; case Accepted: ui_.lb_status->setText(tr("Accepted")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(true); break; case Rejected: ui_.lb_status->setText(tr("Rejected")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(false); break; case InProgress: ui_.lb_status->setText(tr("In progress")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(true); break; case Terminated: ui_.lb_status->setText(tr("Terminated")); ui_.pb_accept->setEnabled(false); ui_.pb_reject->setEnabled(false); ui_.pb_hangup->setEnabled(false); break; case Incoming: ui_.lb_status->setText(tr("Incoming Call")); ui_.pb_accept->setEnabled(true); ui_.pb_reject->setEnabled(true); ui_.pb_hangup->setEnabled(false); break; default: break; } } void VoiceCallDlg::reject() { finalize(); QDialog::reject(); } void VoiceCallDlg::finalize() { // Close connection if (status_ == Incoming) { reject_call(); } else if (status_ == InProgress || status_ == Calling || status_ == Accepting || status_ == Accepted) { terminate_call(); } // Disconnect signals disconnect(voiceCaller_,SIGNAL(accepted(const Jid&)),this,SLOT(accepted(const Jid&))); disconnect(voiceCaller_,SIGNAL(rejected(const Jid&)),this,SLOT(rejected(const Jid&))); disconnect(voiceCaller_,SIGNAL(in_progress(const Jid&)),this,SLOT(in_progress(const Jid&))); disconnect(voiceCaller_,SIGNAL(terminated(const Jid&)),this,SLOT(terminated(const Jid&))); } psi-0.14/src/tipdlg.h0000644000175000017500000000302511305557613012564 0ustar janjan/* * tipdlg.h - handles tip of the day * Copyright (C) 2001-2006 Michail Pishchagin * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TIPDLG_H #define TIPDLG_H #include #include #include "ui_tip.h" class QString; class PsiCon; class TipDlg : public QDialog, public Ui::Tip { Q_OBJECT public: static void show(PsiCon* psi); private: TipDlg(PsiCon* psi); ~TipDlg(); public slots: void showTipsChanged(bool); void next(); void previous(); protected: void updateTip(); void addTip(const QString& tip, const QString& author); private: PsiCon* psi_; QStringList tips; }; #endif psi-0.14/src/pepmanager.cpp0000644000175000017500000004224211305557613013757 0ustar janjan/* * pepmanager.cpp - Classes for PEP * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "pepmanager.h" #include #include "xmpp_xmlcommon.h" #include "xmpp_tasks.h" #include "serverinfomanager.h" using namespace XMPP; // TODO: Get affiliations upon startup, and only create nodes based on that. // (subscriptions is not accurate, since one doesn't subscribe to the // avatar data node) // ----------------------------------------------------------------------------- class PEPGetTask : public Task { public: PEPGetTask(Task* parent, const QString& jid, const QString& node, const QString& itemID) : Task(parent), jid_(jid), node_(node) { iq_ = createIQ(doc(), "get", jid_, id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement items = doc()->createElement("items"); items.setAttribute("node", node); pubsub.appendChild(items); QDomElement item = doc()->createElement("item"); item.setAttribute("id", itemID); items.appendChild(item); } void onGo() { send(iq_); } bool take(const QDomElement &x) { if(!iqVerify(x, jid_, id())) return false; if(x.attribute("type") == "result") { bool found; // FIXME Check namespace... QDomElement e = findSubTag(x, "pubsub", &found); if (found) { QDomElement i = findSubTag(e, "items", &found); if (found) { for(QDomNode n1 = i.firstChild(); !n1.isNull(); n1 = n1.nextSibling()) { QDomElement e1 = n1.toElement(); if (!e1.isNull() && e1.tagName() == "item") { for(QDomNode n2 = e1.firstChild(); !n2.isNull(); n2 = n2.nextSibling()) { QDomElement e2 = n2.toElement(); if (!e2.isNull()) { items_ += PubSubItem(e1.attribute("id"),e2); } } } } } } setSuccess(); return true; } else { setError(x); return true; } } const QList& items() const { return items_; } const QString& jid() const { return jid_; } const QString& node() const { return node_; } private: QDomElement iq_; QString jid_; QString node_; QList items_; }; // ----------------------------------------------------------------------------- /* class PEPUnsubscribeTask : public Task { public: PEPUnsubscribeTask(Task* parent, const QString& jid, const QString& node) : Task(parent), jid_(jid) { iq_ = createIQ(doc(), "set", jid_, id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement unsubscribe = doc()->createElement("unsubscribe"); unsubscribe.setAttribute("node", node); unsubscribe.setAttribute("jid", client()->jid().bare()); pubsub.appendChild(unsubscribe); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, jid_, id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } private: QDomElement iq_; QString jid_; }; // ----------------------------------------------------------------------------- class PEPSubscribeTask : public Task { public: PEPSubscribeTask(Task* parent, const QString& jid, const QString& node) : Task(parent), jid_(jid) { iq_ = createIQ(doc(), "set", jid_, id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement subscribe = doc()->createElement("subscribe"); subscribe.setAttribute("node", node); subscribe.setAttribute("jid", client()->jid().bare()); pubsub.appendChild(subscribe); } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, jid_, id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } private: QDomElement iq_; QString jid_; };*/ // ----------------------------------------------------------------------------- /* class PEPCreateNodeTask : public Task { public: PEPCreateNodeTask(Task* parent, const QString& node) : Task(parent) { node_ = node; iq_ = createIQ(doc(), "set", "", id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement subscribe = doc()->createElement("create"); subscribe.setAttribute("node", node); pubsub.appendChild(subscribe); QDomElement configure = doc()->createElement("configure"); pubsub.appendChild(configure); } const QString& node() const { return node_; } void onGo() { send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } private: QDomElement iq_; QString node_; };*/ // ----------------------------------------------------------------------------- class PEPPublishTask : public Task { public: PEPPublishTask(Task* parent, const QString& node, const PubSubItem& it, PEPManager::Access access) : Task(parent), node_(node), item_(it) { iq_ = createIQ(doc(), "set", "", id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement publish = doc()->createElement("publish"); publish.setAttribute("node", node); pubsub.appendChild(publish); QDomElement item = doc()->createElement("item"); item.setAttribute("id", it.id()); publish.appendChild(item); if (access != PEPManager::DefaultAccess) { QDomElement conf = doc()->createElement("configure"); QDomElement conf_x = doc()->createElementNS("jabber:x:data","x"); // Form type QDomElement conf_x_field_type = doc()->createElement("field"); conf_x_field_type.setAttribute("var","FORM_TYPE"); conf_x_field_type.setAttribute("type","hidden"); QDomElement conf_x_field_type_value = doc()->createElement("value"); conf_x_field_type_value.appendChild(doc()->createTextNode("http://jabber.org/protocol/pubsub#node_config")); conf_x_field_type.appendChild(conf_x_field_type_value); conf_x.appendChild(conf_x_field_type); // Access model QDomElement access_model = doc()->createElement("field"); access_model.setAttribute("var","pubsub#access_model"); QDomElement access_model_value = doc()->createElement("value"); access_model.appendChild(access_model_value); if (access == PEPManager::PublicAccess) { access_model_value.appendChild(doc()->createTextNode("open")); } else if (access == PEPManager::PresenceAccess) { access_model_value.appendChild(doc()->createTextNode("presence")); } conf_x.appendChild(access_model); conf.appendChild(conf_x); pubsub.appendChild(conf); } item.appendChild(it.payload()); } bool take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } void onGo() { send(iq_); } const PubSubItem& item() const { return item_; } const QString& node() const { return node_; } private: QDomElement iq_; QString node_; PubSubItem item_; }; // ----------------------------------------------------------------------------- class PEPRetractTask : public Task { public: PEPRetractTask(Task* parent, const QString& node, const QString& itemId) : Task(parent), node_(node), itemId_(itemId) { iq_ = createIQ(doc(), "set", "", id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement retract = doc()->createElement("retract"); retract.setAttribute("node", node); retract.setAttribute("notify", "1"); pubsub.appendChild(retract); QDomElement item = doc()->createElement("item"); item.setAttribute("id", itemId); retract.appendChild(item); } bool take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } void onGo() { send(iq_); } const QString& node() const { return node_; } private: QDomElement iq_; QString node_; QString itemId_; }; // ----------------------------------------------------------------------------- /* class GetPubSubSubscriptionsTask : public Task { public: GetPubSubSubscriptionsTask(Task* parent, const Jid& jid) : Task(parent), jid_(jid) { iq_ = createIQ(doc(), "get", jid_.bare(), id()); QDomElement pubsub = doc()->createElement("pubsub"); pubsub.setAttribute("xmlns", "http://jabber.org/protocol/pubsub"); iq_.appendChild(pubsub); QDomElement subscriptions = doc()->createElement("subscriptions"); pubsub.appendChild(subscriptions); } bool take(const QDomElement &x) { if(!iqVerify(x, jid_.bare(), id())) return false; if(x.attribute("type") == "result") { subscriptions_.clear(); for(QDomNode m = x.firstChild(); !m.isNull(); m = m.nextSibling()) { QDomElement me = m.toElement(); if (me.tagName() != "pubsub") continue; for(QDomNode n = me.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement s = n.toElement(); if (s.tagName() != "subscriptions") continue; for(QDomNode sub_node = s.firstChild(); !sub_node.isNull(); sub_node = sub_node.nextSibling()) { // TODO: Check if the jid is the right one (ours) ? PubSubSubscription sub(sub_node.toElement()); subscriptions_ += sub; } } } setSuccess(); return true; } else { setError(x); return true; } } const Jid& jid() const { return jid_; } const QList subscriptions() const { return subscriptions_; } void onGo() { send(iq_); } private: QDomElement iq_; Jid jid_; QList subscriptions_; };*/ // ----------------------------------------------------------------------------- PEPManager::PEPManager(Client* client, ServerInfoManager* serverInfo) : client_(client), serverInfo_(serverInfo) { connect(client_, SIGNAL(messageReceived(const Message &)), SLOT(messageReceived(const Message &))); } /*void PEPManager::setAvailable(bool a) { if (available_ != a) { available_ = a; emit available(available_); } } void PEPManager::registerNode(const QString& node) { if (nodes_.contains(node)) return; if (available_) { createNode(node); } nodes_ += node; } void PEPManager::registerNodes(const QStringList& nodes) { foreach(QString node, nodes) { registerNode(node); } } bool PEPManager::canPublish(const QString& node) const { return ensured_nodes_.contains(node); } void PEPManager::saveSubscriptions() { } void PEPManager::createNode(const QString& node) { PEPCreateNodeTask* t = new PEPCreateNodeTask(client_->rootTask(),node); connect(t,SIGNAL(finished()),SLOT(createFinished())); t->go(true); } void PEPManager::subscribe(const QString& jid, const QString& ns) { PEPSubscribeTask* t = new PEPSubscribeTask(client_->rootTask(),jid,ns); connect(t,SIGNAL(finished()),SLOT(subscribeFinished())); t->go(true); } void PEPManager::createFinished() { PEPCreateNodeTask* task = (PEPCreateNodeTask*) sender(); if (task->success() || task->statusCode() == 409) { if (task->statusCode() == 409) qWarning(QString("[%1] PEP Node already exists. Ignoring.").arg(client_->jid().full())); // Subscribe to our own nodes if (task->node() != "http://www.xmpp.org/extensions/xep-0084.html#ns-data") subscribe(client_->jid().bare(),task->node()); // Notify ensured_nodes_ += task->node(); emit ready(task->node()); } else { qWarning(QString("[%3] PEP Create failed: '%1' (%2)").arg(task->statusString()).arg(QString::number(task->statusCode())).arg(client_->jid().full())); } } void PEPManager::subscribeFinished() { PEPSubscribeTask* task = (PEPSubscribeTask*) sender(); if (task->success()) { //subscriptions_ += task->subscription(); saveSubscriptions(); } else { qWarning(QString("[%3] PEP Subscribe failed: '%1' (%2)").arg(task->statusString()).arg(QString::number(task->statusCode())).arg(client_->jid().full())); } } void PEPManager::unsubscribe(const QString& jid, const QString& node) { PEPUnsubscribeTask* t = new PEPUnsubscribeTask(client_->rootTask(),jid,node); connect(t,SIGNAL(finished()),SLOT(unsubscribeFinished())); t->go(true); } void PEPManager::unsubscribeFinished() { PEPUnsubscribeTask* task = (PEPUnsubscribeTask*) sender(); if (!task->success()) { qWarning(QString("[%3] PEP Unsubscribe failed: '%1' (%2)").arg(task->statusString()).arg(QString::number(task->statusCode())).arg(client_->jid().full())); } // We're being conservative about unsubscribing. Remove subscription, // even if there was an error. //subscriptions_.remove(task->subscription()); saveSubscriptions(); }*/ void PEPManager::publish(const QString& node, const PubSubItem& it, Access access) { //if (!canPublish(node)) // return; if (!serverInfo_->hasPEP()) return; PEPPublishTask* tp = new PEPPublishTask(client_->rootTask(),node,it,access); connect(tp, SIGNAL(finished()), SLOT(publishFinished())); tp->go(true); } void PEPManager::retract(const QString& node, const QString& id) { if (!serverInfo_->hasPEP()) return; PEPRetractTask* tp = new PEPRetractTask(client_->rootTask(),node,id); // FIXME: add notification of success/failure tp->go(true); } void PEPManager::publishFinished() { PEPPublishTask* task = (PEPPublishTask*) sender(); if (task->success()) { emit publish_success(task->node(),task->item()); } else { qWarning() << QString("[%3] PEP Publish failed: '%1' (%2)").arg(task->statusString()).arg(QString::number(task->statusCode())).arg(client_->jid().full()); emit publish_error(task->node(),task->item()); } } void PEPManager::get(const Jid& jid, const QString& node, const QString& id) { PEPGetTask* g = new PEPGetTask(client_->rootTask(),jid.bare(),node,id); connect(g, SIGNAL(finished()), SLOT(getFinished())); g->go(true); } void PEPManager::messageReceived(const Message& m) { foreach(PubSubRetraction i, m.pubsubRetractions()) { emit itemRetracted(m.from(),m.pubsubNode(), i); } foreach(PubSubItem i, m.pubsubItems()) { emit itemPublished(m.from(),m.pubsubNode(),i); } } /*void PEPManager::serverFeaturesChanged() { if (!available_ && serverInfo_->hasPEP()) { GetPubSubSubscriptionsTask* task = new GetPubSubSubscriptionsTask(client_->rootTask(),client_->jid()); connect(task,SIGNAL(finished()),SLOT(getSelfSubscriptionsTaskFinished())); task->go(true); } else if (available_ && !serverInfo_->hasPEP()) { ensured_nodes_.clear(); setAvailable(false); } }*/ void PEPManager::getFinished() { PEPGetTask* task = (PEPGetTask*) sender(); if (task->success()) { // Act as if the item was published. This is a convenience // implementation, probably should be changed later. if (!task->items().isEmpty()) { emit itemPublished(task->jid(),task->node(),task->items().first()); } } else { qWarning() << QString("[%3] PEP Get failed: '%1' (%2)").arg(task->statusString()).arg(QString::number(task->statusCode())).arg(client_->jid().full()); } } /* void PEPManager::getSubscriptions(const Jid& jid) { GetPubSubSubscriptionsTask* task = new GetPubSubSubscriptionsTask(client_->rootTask(),jid); connect(task,SIGNAL(finished()),SLOT(getSubscriptionsTaskFinished())); task->go(true); } void PEPManager::getSelfSubscriptionsTaskFinished() { GetPubSubSubscriptionsTask* task = (GetPubSubSubscriptionsTask*) sender(); if (task->success() || task->statusCode() == 404) { QStringList nodes = nodes_; foreach(PubSubSubscription s, task->subscriptions()) { if (nodes.contains(s.node())) { nodes.remove(s.node()); ensured_nodes_ += s.node(); emit ready(s.node()); // Subscribe to our own nodes if (s.state() == PubSubSubscription::None && s.node() != "http://www.xmpp.org/extensions/xep-0084.html#ns-data") { subscribe(client_->jid().bare(),s.node()); } } } // Create remaining nodes foreach(QString node, nodes) { createNode(node); } } else { qWarning(QString("[%3] Error getting own subscriptions: '%1' (%2)").arg(task->statusString()).arg(QString::number(task->statusCode())).arg(client_->jid().full())); } } void PEPManager::getSubscriptionsTaskFinished() { GetPubSubSubscriptionsTask* task = (GetPubSubSubscriptionsTask*) sender(); if (task->success()) { emit getSubscriptions_success(task->jid(), task->subscriptions()); } else { emit getSubscriptions_error(task->jid(),task->statusCode(), task->statusString()); } }*/ psi-0.14/src/xdata_widget.cpp0000644000175000017500000002747411305557613014316 0ustar janjan/* * xdata_widget.cpp - a class for displaying jabber:x:data forms * Copyright (C) 2003-2004 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xdata_widget.h" #include #include #include #include #include #include #include #include #include #include #include "desktoputil.h" #include "xmpp_xdata.h" using namespace XMPP; //---------------------------------------------------------------------------- // XDataField //---------------------------------------------------------------------------- class XDataField { public: XDataField(XData::Field f) { _field = f; } virtual ~XDataField() { } virtual XData::Field field() const { return _field; } QString labelText() const { QString text = _field.label(); if ( text.isEmpty() ) text = _field.var(); return text + ": "; } QString reqText() const { QString req; if ( _field.required() ) req = "*"; if ( !_field.desc().isEmpty() ) { if ( !req.isEmpty() ) req += ' '; req += "(?)"; } return req; } virtual bool isValid() const { return field().isValid(); } private: XData::Field _field; }; //////////////////////////////////////// class XDataField_Hidden : public XDataField { public: XDataField_Hidden(XData::Field f) : XDataField(f) { } }; //////////////////////////////////////// class XDataField_Boolean : public XDataField { public: XDataField_Boolean(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField(f) { bool checked = false; if ( f.value().count() ) { QString s = f.value().first(); if ( s == "1" || s == "true" || s == "yes" ) checked = true; } QLabel *label = new QLabel(labelText(), parent); grid->addWidget(label, row, 0); check = new QCheckBox(parent); check->setChecked(checked); grid->addWidget(check, row, 1); QLabel *req = new QLabel(reqText(), parent); grid->addWidget(req, row, 2); if ( !f.desc().isEmpty() ) { label->setToolTip(f.desc()); check->setToolTip(f.desc()); req->setToolTip(f.desc()); } } XData::Field field() const { XData::Field f = XDataField::field(); QStringList val; val << QString( check->isChecked() ? "1" : "0" ); f.setValue(val); return f; } private: QCheckBox *check; }; //////////////////////////////////////// class XDataField_Fixed : public XDataField { public: XDataField_Fixed(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField(f) { QString text; QStringList val = f.value(); QStringList::Iterator it = val.begin(); for ( ; it != val.end(); ++it) { if ( !text.isEmpty() ) text += "
"; text += *it; } QLabel *fixed = new QLabel("" + text + "", parent); grid->addWidget(fixed, row, 0, 2, 0); if ( !f.desc().isEmpty() ) { fixed->setToolTip(f.desc()); } } }; //////////////////////////////////////// class XDataField_TextSingle : public XDataField { public: XDataField_TextSingle(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField(f) { QString text; if ( f.value().count() ) text = f.value().first(); QLabel *label = new QLabel(labelText(), parent); grid->addWidget(label, row, 0); edit = new QLineEdit(parent); edit->setText(text); grid->addWidget(edit, row, 1); QLabel *req = new QLabel(reqText(), parent); grid->addWidget(req, row, 2); if ( !f.desc().isEmpty() ) { label->setToolTip(f.desc()); edit->setToolTip(f.desc()); req->setToolTip(f.desc()); } } XData::Field field() const { XData::Field f = XDataField::field(); QStringList val; val << edit->text(); f.setValue(val); return f; } protected: QLineEdit *edit; }; //////////////////////////////////////// class XDataField_TextPrivate : public XDataField_TextSingle { public: XDataField_TextPrivate(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField_TextSingle(f, grid, row, parent) { edit->setEchoMode(QLineEdit::Password); } }; //////////////////////////////////////// class XDataField_JidSingle : public XDataField_TextSingle { public: XDataField_JidSingle(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField_TextSingle(f, grid, row, parent) { // TODO: add proper validation } }; //////////////////////////////////////// class XDataField_ListSingle : public XDataField { public: XDataField_ListSingle(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField(f) { QLabel *label = new QLabel(labelText(), parent); grid->addWidget(label, row, 0); combo = new QComboBox(parent); grid->addWidget(combo, row, 1); combo->setInsertPolicy(QComboBox::NoInsert); QString sel; if ( !f.value().isEmpty() ) sel = f.value().first(); XData::Field::OptionList opts = f.options(); XData::Field::OptionList::Iterator it = opts.begin(); for ( ; it != opts.end(); ++it) { QString lbl = (*it).label; if ( lbl.isEmpty() ) lbl = (*it).value; combo->addItem(lbl); if ( (*it).value == sel ) combo->setCurrentIndex(combo->count()-1); } QLabel *req = new QLabel(reqText(), parent); grid->addWidget(req, row, 2); if ( !f.desc().isEmpty() ) { label->setToolTip(f.desc()); combo->setToolTip(f.desc()); req->setToolTip(f.desc()); } } XData::Field field() const { QString lbl = combo->currentText(); XData::Field f = XDataField::field(); QStringList val; XData::Field::OptionList opts = f.options(); XData::Field::OptionList::Iterator it = opts.begin(); for ( ; it != opts.end(); ++it) { if ( (*it).label == lbl || (*it).value == lbl ) { val << (*it).value; break; } } f.setValue(val); return f; } private: QComboBox *combo; }; //////////////////////////////////////// class XDataField_ListMulti : public XDataField { public: XDataField_ListMulti(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField(f) { QLabel *label = new QLabel(labelText(), parent); grid->addWidget(label, row, 0); list = new QListWidget(parent); grid->addWidget(list, row, 1); list->setSelectionMode(QAbstractItemView::MultiSelection); XData::Field::OptionList opts = f.options(); XData::Field::OptionList::Iterator it = opts.begin(); for ( ; it != opts.end(); ++it) { QString lbl = (*it).label; if ( lbl.isEmpty() ) lbl = (*it).value; QListWidgetItem* item = new QListWidgetItem(lbl,list); QStringList val = f.value(); QStringList::Iterator sit = val.begin(); for ( ; sit != val.end(); ++sit) if ( (*it).label == *sit || (*it).value == *sit ) list->setItemSelected(item, true); } QLabel *req = new QLabel(reqText(), parent); grid->addWidget(req, row, 2); if ( !f.desc().isEmpty() ) { label->setToolTip(f.desc()); list->setToolTip(f.desc()); req->setToolTip(f.desc()); } } XData::Field field() const { XData::Field f = XDataField::field(); QStringList val; for (int i = 0; i < list->count(); i++) { QListWidgetItem* item = list->item(i); if ( list->isItemSelected(item) ) { QString lbl = item->text(); XData::Field::OptionList opts = f.options(); XData::Field::OptionList::Iterator it = opts.begin(); for ( ; it != opts.end(); ++it) { if ( (*it).label == lbl || (*it).value == lbl ) { val << (*it).value; break; } } } } f.setValue(val); return f; } private: QListWidget *list; }; //////////////////////////////////////// class XDataField_TextMulti : public XDataField { public: XDataField_TextMulti(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField(f) { QLabel *label = new QLabel(labelText(), parent); grid->addWidget(label, row, 0); edit = new QTextEdit(parent); grid->addWidget(edit, row, 1); QString text; QStringList val = f.value(); QStringList::Iterator it = val.begin(); for ( ; it != val.end(); ++it) { if ( !text.isEmpty() ) text += '\n'; text += *it; } edit->setText(text); QLabel *req = new QLabel(reqText(), parent); grid->addWidget(req, row, 2); if ( !f.desc().isEmpty() ) { label->setToolTip(f.desc()); edit->setToolTip(f.desc()); req->setToolTip(f.desc()); } } XData::Field field() const { XData::Field f = XDataField::field(); f.setValue( edit->toPlainText().split("\n") ); return f; } private: QTextEdit *edit; }; //////////////////////////////////////// class XDataField_JidMulti : public XDataField_TextMulti { public: XDataField_JidMulti(XData::Field f, QGridLayout *grid, int row, QWidget *parent) : XDataField_TextMulti(f, grid, row, parent) { // TODO: improve validation } }; //---------------------------------------------------------------------------- // XDataWidget //---------------------------------------------------------------------------- XDataWidget::XDataWidget(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); layout_ = new QVBoxLayout(this); } XDataWidget::~XDataWidget() { } void XDataWidget::setInstructions(const QString& instructions) { instructions_ = instructions; } void XDataWidget::setForm(const XMPP::XData& d) { setInstructions(d.instructions()); setFields(d.fields()); } XData::FieldList XDataWidget::fields() const { XData::FieldList f; for (QList::ConstIterator it = fields_.begin() ; it != fields_.end(); it ++) { f.append( (*it)->field() ); } return f; } void XDataWidget::setFields(const XData::FieldList &f) { fields_.clear(); QLayoutItem *child; while ((child = layout_->takeAt(0)) != 0) { delete child->widget(); delete child; } if (!instructions_.isEmpty()) { QLabel* l = new QLabel(instructions_, this); l->setWordWrap(true); l->setTextInteractionFlags(Qt::TextSelectableByMouse|Qt::LinksAccessibleByMouse); connect(l,SIGNAL(linkActivated(const QString&)),SLOT(linkActivated(const QString&))); layout_->addWidget(l); } QWidget *fields = new QWidget(this); layout_->addWidget(fields); if ( f.count() ) { // FIXME QGridLayout *grid = new QGridLayout(fields); int row = 0; XData::FieldList::ConstIterator it = f.begin(); for ( ; it != f.end(); ++it, ++row) { XDataField *f; switch ( (*it).type() ) { case XData::Field::Field_Boolean: f = new XDataField_Boolean(*it, grid, row, this); break; case XData::Field::Field_Fixed: f = new XDataField_Fixed(*it, grid, row, this); break; case XData::Field::Field_Hidden: f = new XDataField_Hidden(*it); break; case XData::Field::Field_JidSingle: f = new XDataField_JidSingle(*it, grid, row, this); break; case XData::Field::Field_ListMulti: f = new XDataField_ListMulti(*it, grid, row, this); break; case XData::Field::Field_ListSingle: f = new XDataField_ListSingle(*it, grid, row, this); break; case XData::Field::Field_TextMulti: f = new XDataField_TextMulti(*it, grid, row, this); break; case XData::Field::Field_JidMulti: f = new XDataField_JidMulti(*it, grid, row, this); break; case XData::Field::Field_TextPrivate: f = new XDataField_TextPrivate(*it, grid, row, this); break; default: f = new XDataField_TextSingle(*it, grid, row, this); } fields_.append(f); } } } void XDataWidget::linkActivated(const QString& link) { DesktopUtil::openUrl(link); } psi-0.14/src/jidutil.cpp0000644000175000017500000000671611305557613013312 0ustar janjan/* * jidutil.h * Copyright (C) 2006 Remko Troncon, Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_jid.h" #include "jidutil.h" #include "psioptions.h" using namespace XMPP; QString JIDUtil::defaultDomain() { return PsiOptions::instance()->getOption("options.account.domain").toString(); } void JIDUtil::setDefaultDomain(QString domain) { PsiOptions::instance()->setOption("options.account.domain", domain); } QString JIDUtil::encode(const QString &jid) { QString jid2; for(int n = 0; n < jid.length(); ++n) { if(jid.at(n) == '@') { jid2.append("_at_"); } else if(jid.at(n) == '.') { jid2.append('.'); } else if(!jid.at(n).isLetterOrNumber()) { // hex encode QString hex; hex.sprintf("%%%02X", jid.at(n).toLatin1()); jid2.append(hex); } else { jid2.append(jid.at(n)); } } return jid2; } QString JIDUtil::decode(const QString &jid) { QString jid2; int n; for(n = 0; n < (int)jid.length(); ++n) { if(jid.at(n) == '%' && (jid.length() - n - 1) >= 2) { QString str = jid.mid(n+1,2); bool ok; char c = str.toInt(&ok, 16); if(!ok) continue; QChar a(c); jid2.append(a); n += 2; } else { jid2.append(jid.at(n)); } } // search for the _at_ backwards, just in case for(n = (int)jid2.length(); n >= 3; --n) { if(jid2.mid(n, 4) == "_at_") { jid2.replace(n, 4, "@"); break; } } return jid2; } QString JIDUtil::nickOrJid(const QString &nick, const QString &jid) { if(nick.isEmpty()) return jid; else return nick; } QString JIDUtil::accountToString(const Jid& j, bool withResource) { QString s = j.node(); if (!defaultDomain().isEmpty()) { return (withResource && !j.resource().isEmpty() ? j.node() + "/" + j.resource() : j.node()); } else { return (withResource ? j.full() : j.bare()); } } Jid JIDUtil::accountFromString(const QString& s) { if (!defaultDomain().isEmpty()) { return Jid(s, defaultDomain(), ""); } else { return Jid(s); } } QString JIDUtil::toString(const Jid& j, bool withResource) { return (withResource ? j.full() : j.bare()); } Jid JIDUtil::fromString(const QString& s) { return Jid(s); } QString JIDUtil::encode822(const QString &s) { QString out; for(int n = 0; n < (int)s.length(); ++n) { if(s[n] == '\\' || s[n] == '<' || s[n] == '>') { QString hex; hex.sprintf("\\x%02X", (unsigned char )s[n].toLatin1()); out.append(hex); } else out += s[n]; } return out; } QString JIDUtil::decode822(const QString &s) { QString out; for(int n = 0; n < (int)s.length(); ++n) { if(s[n] == '\\' && n + 3 < (int)s.length()) { int x = n + 1; n += 3; if(s[x] != 'x') continue; ushort val = 0; val += QString(s[x+1]).toInt(NULL,16); val += QString(s[x+2]).toInt(NULL,16); QChar c(val); out += c; } else out += s[n]; } return out; } psi-0.14/src/activeprofiles.cpp0000644000175000017500000000672211305557613014662 0ustar janjan/* * activeprofiles.cpp - Class for interacting with other psi instances * Copyright (C) 2006 Maciej Niedzielski * Copyright (C) 2006-2007 Martin Hostettler * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "activeprofiles.h" #include #include "profiles.h" ActiveProfiles* ActiveProfiles::instance_ = 0; /** * \fn virtual ActiveProfiles::~ActiveProfiles(); * \brief Destroys the object. */ /** * \fn bool ActiveProfiles::isActive(const QString &profile) const; * \brief Returns true if \a profile is running. */ /** * \fn bool ActiveProfiles::isAnyActive() const; * \brief Returns true if there is at least one running Psi instance. */ /** * \fn bool ActiveProfiles::setThisProfile(const QString &profile); * \brief Registeres this application instance as \a profile. * Note: you can call this function multiple times with the same value of \a profile. */ /** * \fn void ActiveProfiles::unsetThisProfile(); * \brief Unregistered this application profile. */ /** * \fn QString ActiveProfiles::thisProfile() const; * \brief Returns the profile name registered for this application instance. * Returns empty string if no profile is registered. */ /** * \fn ActiveProfiles::ActiveProfiles(const QString &name); * \brief Creates new object and registers this application with its \a name. */ /** * \brief Returns the instance of ActiveProfiles. */ ActiveProfiles* ActiveProfiles::instance() { if (!instance_) { instance_ = new ActiveProfiles(); } return instance_; } /** * \fn ActiveProfiles::ActiveProfiles() * \brief Creates new object. */ /** * \fn bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const * \brief Requests Psi instance running \a profile to change status. * If \a profile is empty, other running instance is selected. * If the request cannot be sent, function returns false. */ /** * \fn bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const * \brief Requests Psi instance running \a profile to open \a uri. * If \a profile is empty, other running instance is selected. * If the request cannot be sent, function returns false. */ /** * \fn bool ActiveProfiles::raise(QString profile, bool withUI) const * \brief Raises the main windows of Psi instance running \a profile. * If \a profile is empty, other running instance is selected. */ /** * \fn void setStatusRequested(const QString &status, const QString &message) * \brief Signal emitted when other Psi instance requested to change status. */ /** * \fn void ActiveProfiles::openUriRequested(const QUrl &uri) * \brief Signal emitted when other Psi instance requested to open \a uri. */ /** * \fn void ActiveProfiles::raiseRequested() * \brief Signal emitted when other Psi instance requested to raise main window. */ psi-0.14/src/resourcemenu.cpp0000644000175000017500000000317611305557613014357 0ustar janjan/* * resourcemenu.cpp - helper class for displaying contact's resources * Copyright (C) 2006 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "resourcemenu.h" #include "psiiconset.h" #include "userlist.h" #include "xmpp_status.h" /** * \class ResourceMenu * Helper class that displays available resources using QMenu. * Please note that PsiMacStyle references name of ResourceMenu. */ ResourceMenu::ResourceMenu(QWidget *parent) : QMenu(parent) { // nothing here } /** * Helper function to add resource to the menu. */ void ResourceMenu::addResource(const UserResource &r, int id) { addResource(r.status().type(), r.name(), id); } /** * Helper function to add resource to the menu. */ void ResourceMenu::addResource(int status, QString name, int id) { QString rname = name; if(rname.isEmpty()) rname = tr("[blank]"); //rname += " (" + status2txt(status) + ")"; insertItem(PsiIconset::instance()->status(status).icon(), rname, id); } psi-0.14/src/tabcompletion.cpp0000644000175000017500000001347711305557613014510 0ustar janjan/* * Copyright (C) 2001-2008 Justin Karneges, Martin Hostettler * * 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 2 * 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, see . * */ // Generic tab completion support code. #include #include "tabcompletion.h" TabCompletion::TabCompletion(QObject *parent) : QObject(parent) { typingStatus_ = Typing_Normal; textEdit_ = 0; } TabCompletion::~TabCompletion() { } void TabCompletion::setTextEdit(QTextEdit* textEdit) { textEdit_ = textEdit; QColor mleBackground(textEdit_->palette().color(QPalette::Active, QPalette::Base)); if (mleBackground.value() < 128) { highlight_ = mleBackground.lighter(125); } else { highlight_ = mleBackground.darker(125); } } QTextEdit* TabCompletion::getTextEdit() { return textEdit_; } void TabCompletion::highlight(bool set) { Q_UNUSED(set); /* if (set) { QTextEdit::ExtraSelection es; es.cursor = replacementCursor_; es.format.setBackground(highlight_); textEdit_->setExtraSelections(QList() << es); } else { if (textEdit_) textEdit_->setExtraSelections(QList()); }*/ } void TabCompletion::moveCursorToOffset(QTextCursor &cur, int offset, QTextCursor::MoveMode mode) { cur.movePosition(QTextCursor::Start, mode); for (int i = 0; i < offset; i++) { // some sane limit on iterations if (cur.position() >= offset) break; // done our work if (!cur.movePosition(QTextCursor::NextCharacter, mode)) break; // failed? } } /** Find longest common (case insensitive) prefix of \a list. */ QString TabCompletion::longestCommonPrefix(QStringList list) { QString candidate = list.first().toLower(); int len = candidate.length(); while (len > 0) { bool found = true; foreach(QString str, list) { if (str.left(len).toLower() != candidate) { found = false; break; } } if (found) { break; } --len; candidate = candidate.left(len); } return candidate; } void TabCompletion::setup(QString text, int pos, int &start, int &end) { if (text.isEmpty() || pos==0) { atStart_ = true; toComplete_ = ""; start = 0; end = 0; return; } end = pos; int i; for (i = pos - 1; i > 0; --i) { if (text[i].isSpace()) { break; } } if (!text[i].isSpace()) { atStart_ = true; start = 0; } else { atStart_ = false; start = i+1; } toComplete_ = text.mid(start, end-start); } QString TabCompletion::suggestCompletion(bool *replaced) { suggestedCompletion_ = possibleCompletions(); suggestedIndex_ = -1; QString newText; if (suggestedCompletion_.count() == 1) { *replaced = true; newText = suggestedCompletion_.first(); } else if (suggestedCompletion_.count() > 1) { newText = longestCommonPrefix(suggestedCompletion_); if (newText.isEmpty()) { return toComplete_; // FIXME is this right? } typingStatus_ = Typing_MultipleSuggestions; // TODO: display a tooltip that will contain all suggestedCompletion *replaced = true; } return newText; } void TabCompletion::reset() { typingStatus_ = Typing_Normal; highlight(false); } /** Handle tab completion. * User interface uses a dual model, first tab completes upto the * longest common (case insensitiv) match, further tabbing cycles through all * possible completions. When doing a tab completion without something to complete * possibly offers a special guess first. */ void TabCompletion::tryComplete() { switch (typingStatus_) { case Typing_Normal: typingStatus_ = Typing_TabPressed; break; case Typing_TabPressed: typingStatus_ = Typing_TabbingCompletions; break; default: break; } QString newText; bool replaced = false; if (typingStatus_ == Typing_MultipleSuggestions) { if (!suggestedCompletion_.isEmpty()) { suggestedIndex_++; if (suggestedIndex_ >= (int)suggestedCompletion_.count()) { suggestedIndex_ = 0; } newText = suggestedCompletion_[suggestedIndex_]; replaced = true; } } else { QTextCursor cursor = textEdit_->textCursor(); QString wholeText = textEdit_->toPlainText(); int begin, end; setup(wholeText, cursor.position(), begin, end); replacementCursor_ = QTextCursor(textEdit_->document()); moveCursorToOffset(replacementCursor_, begin); moveCursorToOffset(replacementCursor_, end, QTextCursor::KeepAnchor); if (toComplete_.isEmpty() && typingStatus_ == Typing_TabbingCompletions) { typingStatus_ = Typing_MultipleSuggestions; QString guess; suggestedCompletion_ = allChoices(guess); if ( !guess.isEmpty() ) { suggestedIndex_ = -1; newText = guess; replaced = true; } else if (!suggestedCompletion_.isEmpty()) { suggestedIndex_ = 0; newText = suggestedCompletion_.first(); replaced = true; } } else { newText = suggestCompletion(&replaced); } } if (replaced) { textEdit_->setUpdatesEnabled(false); int start = qMin(replacementCursor_.anchor(), replacementCursor_.position()); replacementCursor_.beginEditBlock(); replacementCursor_.insertText(newText); replacementCursor_.endEditBlock(); QTextCursor newPos(replacementCursor_); moveCursorToOffset(replacementCursor_, start, QTextCursor::KeepAnchor); newPos.clearSelection(); textEdit_->setTextCursor(newPos); textEdit_->setUpdatesEnabled(true); textEdit_->viewport()->update(); } highlight(typingStatus_ == Typing_MultipleSuggestions); } psi-0.14/src/groupchatdlg.cpp0000644000175000017500000015074611305557613014334 0ustar janjan/* * groupchatdlg.cpp - dialogs for handling groupchat * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // TODO: Move all the 'logic' of groupchats into MUCManager. See MUCManager // for more details. #include "groupchatdlg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape() #include #include #include "psicon.h" #include "psiaccount.h" #include "capsmanager.h" #include "userlist.h" #include "mucconfigdlg.h" #include "textutil.h" #include "statusdlg.h" #include "xmpp_message.h" #include "psiiconset.h" #include "stretchwidget.h" #include "mucmanager.h" #include "busywidget.h" #include "msgmle.h" #include "iconwidget.h" #include "iconselect.h" #include "xmpp_tasks.h" #include "iconaction.h" #include "psitooltip.h" #include "psioptions.h" #include "shortcutmanager.h" #include "psicontactlist.h" #include "accountlabel.h" #include "gcuserview.h" #include "mucreasonseditor.h" #include "mcmdmanager.h" #include "lastactivitytask.h" #include "psirichtext.h" #include "mcmdsimplesite.h" #include "tabcompletion.h" #ifdef Q_WS_WIN #include #endif #define MCMDMUC "http://psi-im.org/ids/mcmd#mucmain" #define MCMDMUCNICK "http://psi-im.org/ids/mcmd#mucnick" //---------------------------------------------------------------------------- // StatusPingTask //---------------------------------------------------------------------------- #include "xmpp_xmlcommon.h" class StatusPingTask : public Task { Q_OBJECT public: StatusPingTask(const Jid& myjid, Task* parent) : Task(parent), myjid_(myjid) { } void onGo() { iq_ = createIQ(doc(), "get", myjid_.full(), id()); QDomElement ping = doc()->createElement("ping"); ping.setAttribute("xmlns", "urn:xmpp:ping"); iq_.appendChild(ping); timeout.setSingleShot ( true ); timeout.setInterval( 1000 * 60 * 10 ); connect(&timeout, SIGNAL(timeout()), SLOT(timeout_triggered())); send(iq_); } bool take(const QDomElement& x) { if(!iqVerify(x, myjid_, id())) // , "urn:xmpp:ping" return false; if(x.attribute("type") == "result") { // something bad, we never reply to this stanza so someone // else got it. // FIXME seems to be no longer true //emit result(NotUs, id()); emit result(LoggedIn, id()); setSuccess(); } else if(x.attribute("type") == "get") { // All went well! emit result(LoggedIn, id()); setSuccess(); } else { bool found; QDomElement tag = findSubTag(x, "error", &found); if(!found) { emit result(OtherErr, id()); } else { XMPP::Stanza::Error err; err.fromXml(tag, client()->stream().baseNS()); if (err.condition == XMPP::Stanza::Error::ItemNotFound) { emit result(NoSuch, id()); } else if (err.condition == XMPP::Stanza::Error::NotAcceptable ) { emit result(NotOccupant, id()); } else { emit result(OtherErr, id()); } setSuccess(); } } return true; } enum Result { NotOccupant, Timeout, NotUs, NoSuch, LoggedIn, OtherErr}; signals: void result(StatusPingTask::Result res, QString id); private slots: void timeout_triggered() { emit result(Timeout, id()); setSuccess(); } private: QDomElement iq_; Jid myjid_; QString xid; QTimer timeout; }; //---------------------------------------------------------------------------- // GCMainDlg //---------------------------------------------------------------------------- class GCMainDlg::Private : public QObject, public MCmdProviderIface { Q_OBJECT public: enum { Connecting, Connected, Idle, ForcedLeave }; Private(GCMainDlg *d) : mCmdManager(&mCmdSite), tabCompletion(this) { dlg = d; nickSeparator = ":"; nonAnonymous = false; trackBar = false; oldTrackBarPosition = 0; mCmdManager.registerProvider(this); } GCMainDlg *dlg; int state; MUCManager *mucManager; QString self, prev_self; QString password; bool nonAnonymous; // got status code 100 ? IconAction *act_find, *act_clear, *act_icon, *act_configure; #ifdef WHITEBOARDING IconAction *act_whiteboard; #endif QAction *act_send, *act_scrollup, *act_scrolldown, *act_close; QAction *act_mini_cmd, *act_nick; MCmdSimpleSite mCmdSite; MCmdManager mCmdManager; QString nickSeparator; // equals ":" QMenu *pm_settings; int pending; bool connecting; QStringList hist; int histAt; QPointer findDlg; QString lastSearch; QPointer configDlg; public: bool trackBar; protected: int oldTrackBarPosition; public: ChatEdit* mle() const { return dlg->ui_.mle->chatEdit(); } ChatView* te_log() const { return dlg->ui_.log; } public slots: void addEmoticon(const PsiIcon *icon) { addEmoticon(icon->defaultText()); } void addEmoticon(QString text) { if ( !dlg->isActiveTab() ) return; PsiRichText::addEmoticon(mle(), text); } void deferredScroll() { //QTimer::singleShot(250, this, SLOT(slotScroll())); te_log()->scrollToBottom(); } void sp_result(StatusPingTask::Result res, QString id) { //qDebug() << res; QString base = QString("Done Status ping (id=%1) ").arg(id); switch (res) { case StatusPingTask::NotOccupant: dlg->appendSysMsg(base + "NotOccupant", false); break; case StatusPingTask::Timeout: dlg->appendSysMsg(base + "Timeout", false); break; case StatusPingTask::NotUs: dlg->appendSysMsg(base + "NotUs", false); break; case StatusPingTask::NoSuch: dlg->appendSysMsg(base + "NoSuch", false); break; case StatusPingTask::LoggedIn: dlg->appendSysMsg(base + "LoggedIn", false); break; case StatusPingTask::OtherErr: dlg->appendSysMsg(base + "OtherErr", false); break; } } void version_finished() { JT_ClientVersion *version = qobject_cast(sender()); if (!version) { dlg->appendSysMsg(QString("No version information available for %1.").arg(version->jid().resource()) , false); return; } dlg->appendSysMsg(QString("Version response from %1: N: %2 V: %3 OS: %4") .arg(version->jid().resource(), version->name(), version->version(), version->os()), false); } void lastactivity_finished() { LastActivityTask *idle = (LastActivityTask *)sender(); if (!idle->success()) { dlg->appendSysMsg(QString("Can't determine last activity time for %1.").arg(idle->jid().resource()), false); return; } if (idle->status().isEmpty()) { dlg->appendSysMsg(QString("Last activity from %1 at %2") .arg(idle->jid().resource(), idle->time().toString()), false); } else { dlg->appendSysMsg(QString("Last activity from %1 at %2 (%3)") .arg(idle->jid().resource(), idle->time().toString(), idle->status()), false); } } void doSPing() { Jid full = dlg->jid().withResource(self); StatusPingTask *sp = new StatusPingTask(full, dlg->account()->client()->rootTask()); connect(sp, SIGNAL(result(StatusPingTask::Result, QString)), SLOT(sp_result(StatusPingTask::Result, QString))); sp->go(true); dlg->appendSysMsg(QString("Doing Status ping (id=%1)").arg(sp->id()), false); } void doNick() { MCmdSimpleState *state = new MCmdSimpleState(MCMDMUCNICK, tr("new nick") + '=', MCMDSTATE_UNPARSED); connect(state, SIGNAL(unhandled(QStringList)), SLOT(NickComplete(QStringList))); mCmdManager.open(state, QStringList() << self); } bool NickComplete(QStringList command) { if (command.count() > 0) { QString nick = command[0].trimmed(); if ( !nick.isEmpty() ) { prev_self = self; self = nick; dlg->account()->groupChatChangeNick(dlg->jid().domain(), dlg->jid().node(), self, dlg->account()->status()); } } return true; } void doMiniCmd() { mCmdManager.open(new MCmdSimpleState(MCMDMUC, tr("Command") + '>'), QStringList() ); } public: virtual bool mCmdTryStateTransit(MCmdStateIface *oldstate, QStringList command, MCmdStateIface *&newstate, QStringList &preset) { if (oldstate->getName() == MCMDMUC) { QString cmd; if (command.count() > 0) cmd = command[0].toLower(); /* TODO: topic invite part [message] kick [comment] ban Maybe?: join {,} query join {,} [pass{,} */ if(cmd == "clear") { dlg->doClear(); histAt = 0; newstate = 0; } else if(cmd == "nick") { if (command.count() > 1) { QString nick = command[1].trimmed(); // FIXME nick can't be empty.... prev_self = self; self = nick; dlg->account()->groupChatChangeNick(dlg->jid().domain(), dlg->jid().node(), self, dlg->account()->status()); newstate = 0; } else { // FIXME DRY with doNick MCmdSimpleState *state = new MCmdSimpleState("nick", tr("new nick") + '=', MCMDSTATE_UNPARSED); connect(state, SIGNAL(unhandled(QStringList)), SLOT(NickComplete(QStringList))); newstate = state; preset = QStringList() << self; } } else if(cmd == "sping") { doSPing(); newstate = 0; } else if (cmd == "version" && command.count() > 1) { QString nick = command[1].trimmed(); Jid target = dlg->jid().withResource(nick); JT_ClientVersion *version = new JT_ClientVersion(dlg->account()->client()->rootTask()); connect(version, SIGNAL(finished()), SLOT(version_finished())); version->get(target); version->go(); newstate = 0; } else if (cmd == "idle" && command.count() > 1) { QString nick = command[1].trimmed(); Jid target = dlg->jid().withResource(nick); LastActivityTask *idle = new LastActivityTask(target, dlg->account()->client()->rootTask()); connect(idle, SIGNAL(finished()), SLOT(lastactivity_finished())); idle->go(); newstate = 0; } else if (cmd == "quote") { dlg->appendSysMsg(command.join("|"), false); preset = command; newstate = oldstate; return true; } else if (!cmd.isEmpty()) { return false; } } else { return false; } return true; } virtual QStringList mCmdTryCompleteCommand(MCmdStateIface *state, QString query, QStringList partcommand, int item) { //qDebug() << "mCmdTryCompleteCommand " << item << ":" << query; QStringList all; if (state->getName() == MCMDMUC) { QString spaceAtEnd = QString(QChar(0)); if (item == 0) { all << "clear" + spaceAtEnd << "nick" + spaceAtEnd << "sping" + spaceAtEnd << "version" + spaceAtEnd << "idle" + spaceAtEnd << "quote" + spaceAtEnd; } else if (item == 1 && (partcommand[0] == "version" || partcommand[0] == "idle")) { all = dlg->ui_.lv_users->nickList(); } } QStringList res; foreach(QString cmd, all) { if (cmd.startsWith(query, Qt::CaseInsensitive)) { res << cmd; } } return res; } virtual void mCmdSiteDestroyed() { } protected slots: void slotScroll() { te_log()->scrollToBottom(); } public: bool internalFind(QString str, bool startFromBeginning = false) { if (startFromBeginning) { QTextCursor cursor = te_log()->textCursor(); cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); cursor.clearSelection(); te_log()->setTextCursor(cursor); } bool found = te_log()->find(str); if(!found) { if (!startFromBeginning) return internalFind(str, true); return false; } return true; } private: void removeTrackBar(QTextCursor &cursor) { if (oldTrackBarPosition) { cursor.setPosition(oldTrackBarPosition, QTextCursor::KeepAnchor); QTextBlockFormat blockFormat = cursor.blockFormat(); blockFormat.clearProperty(QTextFormat::BlockTrailingHorizontalRulerWidth); cursor.clearSelection(); cursor.setBlockFormat(blockFormat); } } void addTrackBar(QTextCursor &cursor) { cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); oldTrackBarPosition = cursor.position(); QTextBlockFormat blockFormat = cursor.blockFormat(); blockFormat.setProperty(QTextFormat::BlockTrailingHorizontalRulerWidth, QVariant(true)); cursor.clearSelection(); cursor.setBlockFormat(blockFormat); } public: void doTrackBar() { trackBar = false; // save position, because our manipulations could change it int scrollbarValue = te_log()->verticalScrollBar()->value(); QTextCursor cursor = te_log()->textCursor(); cursor.beginEditBlock(); PsiRichText::Selection selection = PsiRichText::saveSelection(te_log(), cursor); removeTrackBar(cursor); addTrackBar(cursor); PsiRichText::restoreSelection(te_log(), cursor, selection); cursor.endEditBlock(); te_log()->setTextCursor(cursor); te_log()->verticalScrollBar()->setValue(scrollbarValue); } public: QString lastReferrer; // contains nick of last person, who have said "yourNick: ..." public slots: /** Insert a nick FIXME called from mini roster. */ void insertNick(const QString& nick) { if (nick.isEmpty()) return; QTextCursor cursor(mle()->textCursor()); mle()->setUpdatesEnabled(false); cursor.beginEditBlock(); int index = cursor.position(); cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); QString prev = cursor.selectedText(); cursor.setPosition(index, QTextCursor::KeepAnchor); if (index > 0) { if (!prev.isEmpty() && !prev[0].isSpace()) mle()->insertPlainText(" "); mle()->insertPlainText(nick); } else { mle()->insertPlainText(nick); mle()->insertPlainText(nickSeparator); } mle()->insertPlainText(" "); mle()->setFocus(); cursor.endEditBlock(); mle()->setUpdatesEnabled(true); mle()->viewport()->update(); } public: bool eventFilter( QObject *obj, QEvent *ev ) { if (te_log()->handleCopyEvent(obj, ev, mle())) return true; if ( obj == mle() && ev->type() == QEvent::KeyPress ) { QKeyEvent *e = (QKeyEvent *)ev; if ( e->key() == Qt::Key_Tab ) { tabCompletion.tryComplete(); return true; } tabCompletion.reset(); return false; } return QObject::eventFilter( obj, ev ); } class TabCompletionMUC : public TabCompletion { public: GCMainDlg::Private *p_; TabCompletionMUC(GCMainDlg::Private *p) : p_(p), nickSeparator(":") {}; virtual void setup(QString str, int pos, int &start, int &end) { if (p_->mCmdSite.isActive()) { mCmdList_ = p_->mCmdManager.completeCommand(str, pos, start, end); } else { TabCompletion::setup(str, pos, start, end); } } virtual QStringList possibleCompletions() { if (p_->mCmdSite.isActive()) { return mCmdList_; } QStringList suggestedNicks; QStringList nicks = allNicks(); QString postAdd = atStart_ ? nickSeparator + " " : ""; foreach(QString nick, nicks) { if (nick.left(toComplete_.length()).toLower() == toComplete_.toLower()) { suggestedNicks << nick + postAdd; } } return suggestedNicks; }; virtual QStringList allChoices(QString &guess) { if (p_->mCmdSite.isActive()) { guess = QString(); return mCmdList_; } guess = p_->lastReferrer; if (!guess.isEmpty() && atStart_) { guess += nickSeparator + " "; } QStringList all = allNicks(); if (atStart_) { QStringList::Iterator it = all.begin(); for ( ; it != all.end(); ++it) { *it = *it + nickSeparator + " "; } } return all; }; QStringList allNicks() { return p_->dlg->ui_.lv_users->nickList(); } QStringList mCmdList_; // FIXME where to move this? QString nickSeparator; // equals ":" }; TabCompletionMUC tabCompletion; }; GCMainDlg::GCMainDlg(PsiAccount *pa, const Jid &j, TabManager *tabManager) : TabbableWidget(j.bare(), pa, tabManager) { setAttribute(Qt::WA_DeleteOnClose); if ( PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool() ) setAttribute(Qt::WA_MacMetalStyle); nicknumber=0; d = new Private(this); d->self = d->prev_self = j.resource(); account()->dialogRegister(this, jid()); connect(account(), SIGNAL(updatedActivity()), SLOT(pa_updatedActivity())); d->mucManager = new MUCManager(account()->client(), jid()); options_ = PsiOptions::instance(); d->pending = 0; d->connecting = false; d->histAt = 0; d->findDlg = 0; d->configDlg = 0; d->state = Private::Connected; setAcceptDrops(true); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/groupChat").icon()); #endif ui_.setupUi(this); ui_.lb_ident->setAccount(account()); ui_.lb_ident->setShowJid(false); connect(ui_.pb_topic, SIGNAL(clicked()), SLOT(doTopic())); PsiToolTip::install(ui_.le_topic); connect(account()->psi(), SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility())); updateIdentityVisibility(); d->act_find = new IconAction(tr("Find"), "psi/search", tr("&Find"), 0, this); connect(d->act_find, SIGNAL(triggered()), SLOT(openFind())); ui_.tb_find->setDefaultAction(d->act_find); ui_.tb_emoticons->setIcon(IconsetFactory::icon("psi/smile").icon()); #ifdef Q_WS_MAC connect(ui_.log, SIGNAL(selectionChanged()), SLOT(logSelectionChanged())); #endif ui_.lv_users->setMainDlg(this); connect(ui_.lv_users, SIGNAL(action(const QString &, const Status &, int)), SLOT(lv_action(const QString &, const Status &, int))); connect(ui_.lv_users, SIGNAL(insertNick(const QString&)), d, SLOT(insertNick(const QString&))); d->act_clear = new IconAction (tr("Clear Chat Window"), "psi/clearChat", tr("Clear Chat Window"), 0, this); connect( d->act_clear, SIGNAL( activated() ), SLOT( doClearButton() ) ); d->act_configure = new IconAction(tr("Configure Room"), "psi/configure-room", tr("&Configure Room"), 0, this); connect(d->act_configure, SIGNAL(triggered()), SLOT(configureRoom())); #ifdef WHITEBOARDING d->act_whiteboard = new IconAction(tr("Open a Whiteboard"), "psi/whiteboard", tr("Open a &Whiteboard"), 0, this); connect(d->act_whiteboard, SIGNAL(triggered()), SLOT(openWhiteboard())); #endif connect(pa->psi()->iconSelectPopup(), SIGNAL(textSelected(QString)), d, SLOT(addEmoticon(QString))); d->act_icon = new IconAction( tr( "Select Icon" ), "psi/smile", tr( "Select Icon" ), 0, this ); d->act_icon->setMenu( pa->psi()->iconSelectPopup() ); ui_.tb_emoticons->setMenu(pa->psi()->iconSelectPopup()); d->act_nick = new QAction(this); d->act_nick->setText(tr("Change Nickname...")); connect(d->act_nick, SIGNAL(triggered()), d, SLOT(doNick())); d->act_mini_cmd = new QAction(this); d->act_mini_cmd->setText(tr("Enter Command...")); connect(d->act_mini_cmd, SIGNAL(triggered()), d, SLOT(doMiniCmd())); addAction(d->act_mini_cmd); ui_.toolbar->setIconSize(QSize(16,16)); ui_.toolbar->addAction(d->act_clear); ui_.toolbar->addAction(d->act_configure); #ifdef WHITEBOARDING ui_.toolbar->addAction(d->act_whiteboard); #endif ui_.toolbar->addWidget(new StretchWidget(ui_.toolbar)); ui_.toolbar->addAction(d->act_icon); ui_.toolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum); // Common actions d->act_send = new QAction(this); addAction(d->act_send); connect(d->act_send,SIGNAL(triggered()), SLOT(mle_returnPressed())); d->act_close = new QAction(this); addAction(d->act_close); connect(d->act_close,SIGNAL(triggered()), SLOT(close())); d->act_scrollup = new QAction(this); addAction(d->act_scrollup); connect(d->act_scrollup,SIGNAL(triggered()), SLOT(scrollUp())); d->act_scrolldown = new QAction(this); addAction(d->act_scrolldown); connect(d->act_scrolldown,SIGNAL(triggered()), SLOT(scrollDown())); ui_.mini_prompt->hide(); connect(ui_.mle, SIGNAL(textEditCreated(QTextEdit*)), SLOT(chatEditCreated())); chatEditCreated(); d->pm_settings = new QMenu(this); connect(d->pm_settings, SIGNAL(aboutToShow()), SLOT(buildMenu())); ui_.tb_actions->setMenu(d->pm_settings); // resize the horizontal splitter QList list; list << 500; list << 80; ui_.hsplitter->setSizes(list); list.clear(); list << 324; list << 10; ui_.vsplitter->setSizes(list); X11WM_CLASS("groupchat"); ui_.mle->chatEdit()->setFocus(); resize(PsiOptions::instance()->getOption("options.ui.muc.size").toSize()); // Connect signals from MUC manager connect(d->mucManager,SIGNAL(action_error(MUCManager::Action, int, const QString&)), SLOT(action_error(MUCManager::Action, int, const QString&))); setLooks(); setShortcuts(); invalidateTab(); setConnecting(); } GCMainDlg::~GCMainDlg() { if(d->state != Private::Idle && d->state != Private::ForcedLeave) { account()->groupChatLeave(jid().domain(), jid().node()); } //QMimeSourceFactory *m = ui_.log->mimeSourceFactory(); //ui_.log->setMimeSourceFactory(0); //delete m; account()->dialogUnregister(this); delete d->mucManager; delete d; } void GCMainDlg::ensureTabbedCorrectly() { TabbableWidget::ensureTabbedCorrectly(); setShortcuts(); // QSplitter is broken again, force resize so that // lv_users gets initizalised properly and context menu // works in tabs too. QList tmp = ui_.hsplitter->sizes(); ui_.hsplitter->setSizes(QList() << 0); ui_.hsplitter->setSizes(tmp); } void GCMainDlg::setShortcuts() { d->act_clear->setShortcuts(ShortcutManager::instance()->shortcuts("chat.clear")); d->act_find->setShortcuts(ShortcutManager::instance()->shortcuts("chat.find")); d->act_send->setShortcuts(ShortcutManager::instance()->shortcuts("chat.send")); if (!isTabbed()) { d->act_close->setShortcuts(ShortcutManager::instance()->shortcuts("common.close")); } else { d->act_close->QAction::setShortcuts (QList()); } d->act_scrollup->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-up")); d->act_scrolldown->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-down")); d->act_mini_cmd->setShortcuts(ShortcutManager::instance()->shortcuts("chat.quick-command")); } void GCMainDlg::scrollUp() { ui_.log->verticalScrollBar()->setValue(ui_.log->verticalScrollBar()->value() - ui_.log->verticalScrollBar()->pageStep()/2); } void GCMainDlg::scrollDown() { ui_.log->verticalScrollBar()->setValue(ui_.log->verticalScrollBar()->value() + ui_.log->verticalScrollBar()->pageStep()/2); } void GCMainDlg::closeEvent(QCloseEvent *e) { e->accept(); } void GCMainDlg::resizeEvent(QResizeEvent* e) { if (PsiOptions::instance()->getOption("options.ui.remember-window-sizes").toBool()) PsiOptions::instance()->setOption("options.ui.muc.size", e->size()); } void GCMainDlg::deactivated() { TabbableWidget::deactivated(); d->trackBar = true; } void GCMainDlg::activated() { TabbableWidget::activated(); if(d->pending > 0) { d->pending = 0; invalidateTab(); } doFlash(false); ui_.mle->chatEdit()->setFocus(); d->trackBar = false; } void GCMainDlg::mucInfoDialog(const QString& title, const QString& message, const Jid& actor, const QString& reason) { QString m = message; if (!actor.isEmpty()) m += tr(" by %1").arg(actor.full()); m += "."; if (!reason.isEmpty()) m += tr("\nReason: %1").arg(reason); // FIXME maybe this should be queued in the future? QMessageBox* msg = new QMessageBox(QMessageBox::Information, title, m, QMessageBox::Ok, this); msg->setAttribute(Qt::WA_DeleteOnClose, true); msg->setModal(false); msg->show(); } void GCMainDlg::logSelectionChanged() { #ifdef Q_WS_MAC // A hack to only give the message log focus when text is selected if (ui_.log->textCursor().hasSelection()) ui_.log->setFocus(); else ui_.mle->chatEdit()->setFocus(); #endif } void GCMainDlg::setConnecting() { d->connecting = true; QTimer::singleShot(5000,this,SLOT(unsetConnecting())); } void GCMainDlg::updateIdentityVisibility() { ui_.lb_ident->setVisible(account()->psi()->contactList()->enabledAccounts().count() > 1); } #ifdef WHITEBOARDING void GCMainDlg::openWhiteboard() { account()->actionOpenWhiteboardSpecific(jid(), jid().withResource(d->self), true); } #endif void GCMainDlg::unsetConnecting() { d->connecting = false; } void GCMainDlg::action_error(MUCManager::Action, int, const QString& err) { appendSysMsg(err, false); } void MiniCommand_Depreciation_Message(const QString &old,const QString &newCmd, QString &line1, QString &line2) { line1 = QObject::tr("Warning: %1 is deprecated and will be removed in the future").arg(old); QList keys = ShortcutManager::instance()->shortcuts("chat.quick-command"); if (keys.isEmpty()) { line2 = QObject::tr("Please set a shortcut for 'Change to quick command mode', use that shortcut and enter '%1'.").arg(newCmd); } else { line2 = QObject::tr("Please instead press %1 and enter '%2'.").arg(keys.at(0).toString(), newCmd); } } void GCMainDlg::mle_returnPressed() { d->tabCompletion.reset(); QString str = d->mle()->toPlainText(); if (d->mCmdSite.isActive()) { if (!d->mCmdManager.processCommand(str)) { appendSysMsg(tr("Error: Cannot parse command: ") + str, false); } return; } if(str.isEmpty()) return; if(str == "/clear") { doClear(); d->histAt = 0; d->hist.prepend(str); ui_.mle->chatEdit()->setText(""); QString line1,line2; MiniCommand_Depreciation_Message("/clear", "clear", line1, line2); appendSysMsg(line1, false); appendSysMsg(line2, false); return; } if(str.toLower().startsWith("/nick ")) { QString nick = str.mid(6).trimmed(); XMPP::Jid newJid = jid().withResource(nick); if (!nick.isEmpty() && newJid.isValid()) { d->prev_self = d->self; d->self = newJid.resource(); account()->groupChatChangeNick(jid().domain(), jid().node(), d->self, account()->status()); } ui_.mle->chatEdit()->setText(""); QString line1,line2; MiniCommand_Depreciation_Message("/nick", "nick", line1, line2); appendSysMsg(line1, false); appendSysMsg(line2, false); return; } if(d->state != Private::Connected) return; Message m(jid()); m.setType("groupchat"); m.setBody(str); m.setTimeStamp(QDateTime::currentDateTime()); aSend(m); d->histAt = 0; d->hist.prepend(str); ui_.mle->chatEdit()->setText(""); } /*void GCMainDlg::le_upPressed() { if(d->histAt < (int)d->hist.count()) { ++d->histAt; d->le_input->setText(d->hist[d->histAt-1]); } } void GCMainDlg::le_downPressed() { if(d->histAt > 0) { --d->histAt; if(d->histAt == 0) d->le_input->setText(""); else d->le_input->setText(d->hist[d->histAt-1]); } }*/ void GCMainDlg::doTopic() { bool ok = false; QString str = QInputDialog::getText(this, tr("Set Groupchat Topic"), tr("Enter a topic:"), QLineEdit::Normal, ui_.le_topic->text(), &ok); if(ok) { Message m(jid()); m.setType("groupchat"); m.setSubject(str); m.setTimeStamp(QDateTime::currentDateTime()); aSend(m); } } void GCMainDlg::doClear() { ui_.log->setText(""); } void GCMainDlg::doClearButton() { int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to clear the chat window?\n(note: does not affect saved history)"), tr("&Yes"), tr("&No")); if(n == 0) doClear(); } void GCMainDlg::openFind() { if(d->findDlg) ::bringToFront(d->findDlg); else { d->findDlg = new GCFindDlg(d->lastSearch, this); connect(d->findDlg, SIGNAL(find(const QString &)), SLOT(doFind(const QString &))); d->findDlg->show(); } } void GCMainDlg::configureRoom() { if(d->configDlg) ::bringToFront(d->configDlg); else { GCUserViewItem* c = (GCUserViewItem*)ui_.lv_users->findEntry(d->self); MUCItem::Role role = c ? c->s.mucItem().role() : MUCItem::UnknownRole; MUCItem::Affiliation affiliation = c ? c->s.mucItem().affiliation() : MUCItem::UnknownAffiliation; d->configDlg = new MUCConfigDlg(d->mucManager, this); d->configDlg->setRoleAffiliation(role, affiliation); d->configDlg->show(); } } void GCMainDlg::doFind(const QString &str) { d->lastSearch = str; if (d->internalFind(str)) d->findDlg->found(); else d->findDlg->error(str); } void GCMainDlg::goDisc() { if(d->state != Private::Idle && d->state != Private::ForcedLeave) { d->state = Private::Idle; ui_.pb_topic->setEnabled(false); appendSysMsg(tr("Disconnected."), true); ui_.mle->chatEdit()->setEnabled(false); } } // kick, ban, removed muc, etc void GCMainDlg::goForcedLeave() { if(d->state != Private::Idle && d->state != Private::ForcedLeave) { goDisc(); account()->groupChatLeave(jid().domain(), jid().node()); d->state = Private::ForcedLeave; } } bool GCMainDlg::isInactive() const { return d->state == Private::ForcedLeave; } void GCMainDlg::reactivate() { d->state = Private::Idle; goConn(); } void GCMainDlg::goConn() { if(d->state == Private::Idle) { d->state = Private::Connecting; appendSysMsg(tr("Reconnecting..."), true); QString host = jid().domain(); QString room = jid().node(); QString nick = d->self; if(!account()->groupChatJoin(host, room, nick, d->password)) { appendSysMsg(tr("Error: You are in or joining this room already!"), true); d->state = Private::Idle; } } } void GCMainDlg::dragEnterEvent(QDragEnterEvent *e) { if (e->mimeData()->hasText()) e->accept(); } void GCMainDlg::dropEvent(QDropEvent *e) { Jid jid(e->mimeData()->text()); if (jid.isValid() && !ui_.lv_users->hasJid(jid)) { Message m; m.setTo(this->jid()); m.addMUCInvite(MUCInvite(jid)); if (!d->password.isEmpty()) m.setMUCPassword(d->password); m.setTimeStamp(QDateTime::currentDateTime()); account()->dj_sendMessage(m); } } void GCMainDlg::pa_updatedActivity() { if(!account()->loggedIn()) { goDisc(); } else { if(d->state == Private::Idle) { goConn(); } else if(d->state == Private::Connected) { Status s = account()->status(); s.setXSigned(""); account()->groupChatSetStatus(jid().domain(), jid().node(), s); } } } PsiAccount* GCMainDlg::account() const { return TabbableWidget::account(); } void GCMainDlg::error(int, const QString &str) { ui_.pb_topic->setEnabled(false); if(d->state == Private::Connecting) appendSysMsg(tr("Unable to join groupchat. Reason: %1").arg(str), true); else appendSysMsg(tr("Unexpected groupchat error: %1").arg(str), true); d->state = Private::Idle; } void GCMainDlg::mucKickMsgHelper(const QString &nick, const Status &s, const QString &nickJid, const QString &title, const QString &youSimple, const QString &youBy, const QString &someoneSimple, const QString &someoneBy) { QString message; if (nick == d->self) { message = youSimple; mucInfoDialog(title, message, s.mucItem().actor(), s.mucItem().reason()); if (!s.mucItem().actor().isEmpty()) { message = youBy.arg(s.mucItem().actor().full()); } goForcedLeave(); } else if (!s.mucItem().actor().isEmpty()) { message = someoneBy.arg(nickJid, s.mucItem().actor().full()); } else { message = someoneSimple.arg(nickJid); } if (!s.mucItem().reason().isEmpty()) { message += QString(" (%1)").arg(s.mucItem().reason()); } appendSysMsg(message, false, QDateTime::currentDateTime()); } void GCMainDlg::presence(const QString &nick, const Status &s) { if(s.hasError()) { QString message; if (s.errorCode() == 409) { message = tr("Please choose a different nickname"); d->self = d->prev_self; } else { message = tr("An error occurred (errorcode: %1)").arg(s.errorCode()); } appendSysMsg(message, false, QDateTime::currentDateTime()); return; } if ((nick.isEmpty()) && (s.getMUCStatuses().contains(100))) { d->nonAnonymous = true; } if (nick == d->self) { // Update configuration dialog if (d->configDlg) { d->configDlg->setRoleAffiliation(s.mucItem().role(),s.mucItem().affiliation()); } d->act_configure->setEnabled(s.mucItem().affiliation() >= MUCItem::Member); } if(s.isAvailable()) { // Available if (s.getMUCStatuses().contains(201)) { appendSysMsg(tr("New room created"), false, QDateTime::currentDateTime()); if (options_->getOption("options.muc.accept-defaults").toBool()) { d->mucManager->setDefaultConfiguration(); } else if (options_->getOption("options.muc.auto-configure").toBool()) { QTimer::singleShot(0, this, SLOT(configureRoom())); } } GCUserViewItem* contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact == NULL) { //contact joining if ( !d->connecting && options_->getOption("options.muc.show-joins").toBool() ) { QString message = tr("%1 has joined the room"); if ( options_->getOption("options.muc.show-role-affiliation").toBool() ) { if (s.mucItem().role() != MUCItem::NoRole) { if (s.mucItem().affiliation() != MUCItem::NoAffiliation) { message = tr("%3 has joined the room as %1 and %2").arg(MUCManager::roleToString(s.mucItem().role(),true)).arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true)); } else { message = tr("%2 has joined the room as %1").arg(MUCManager::roleToString(s.mucItem().role(),true)); } } else if (s.mucItem().affiliation() != MUCItem::NoAffiliation) { message = tr("%2 has joined the room as %1").arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true)); } } if (!s.mucItem().jid().isEmpty()) { message = message.arg(QString("%1 (%2)").arg(nick).arg(s.mucItem().jid().full())); } else { message = message.arg(nick); } appendSysMsg(message, false, QDateTime::currentDateTime()); } } else { // Status change if ( !d->connecting && options_->getOption("options.muc.show-role-affiliation").toBool() ) { QString message; if (contact->s.mucItem().role() != s.mucItem().role() && s.mucItem().role() != MUCItem::NoRole) { if (contact->s.mucItem().affiliation() != s.mucItem().affiliation()) { message = tr("%1 is now %2 and %3").arg(nick).arg(MUCManager::roleToString(s.mucItem().role(),true)).arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true)); } else { message = tr("%1 is now %2").arg(nick).arg(MUCManager::roleToString(s.mucItem().role(),true)); } } else if (contact->s.mucItem().affiliation() != s.mucItem().affiliation()) { message += tr("%1 is now %2").arg(nick).arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true)); } if (!message.isEmpty()) { appendSysMsg(message, false, QDateTime::currentDateTime()); } } if ( !d->connecting && options_->getOption("options.muc.show-status-changes").toBool() ) { if (s.status() != contact->s.status() || s.show() != contact->s.show()) { QString message; QString st; if (s.show().isEmpty()) { st=tr("online"); } else { st=s.show(); } message = tr("%1 is now %2").arg(nick).arg(st); if (!s.status().isEmpty()) { message+=QString(" (%1)").arg(s.status()); } appendSysMsg(message, false, QDateTime::currentDateTime()); } } } ui_.lv_users->updateEntry(nick, s); } else { // Unavailable if (s.hasMUCDestroy()) { // Room was destroyed QString message = tr("This room has been destroyed."); QString log = message; if (!s.mucDestroy().reason().isEmpty()) { message += "\n"; QString reason = tr("Reason: %1").arg(s.mucDestroy().reason()); message += reason; log += " " + reason; } if (!s.mucDestroy().jid().isEmpty()) { message += "\n"; message += tr("Do you want to join the alternate venue '%1'?").arg(s.mucDestroy().jid().full()); int ret = QMessageBox::information(this, tr("Room Destroyed"), message, QMessageBox::Yes, QMessageBox::No); if (ret == QMessageBox::Yes) { account()->actionJoin(s.mucDestroy().jid().full()); } } else { QMessageBox::information(this,tr("Room Destroyed"), message); } appendSysMsg(log, false, QDateTime::currentDateTime()); goForcedLeave(); } QString message; QString nickJid; GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact && !contact->s.mucItem().jid().isEmpty()) { nickJid = QString("%1 (%2)").arg(nick).arg(contact->s.mucItem().jid().full()); } else { nickJid = nick; } bool suppressDefault = false; if (s.getMUCStatuses().contains(301)) { // Ban mucKickMsgHelper(nick, s, nickJid, tr("Banned"), tr("You have been banned from the room"), tr("You have been banned from the room by %1"), tr("%1 has been banned"), tr("%1 has been banned by %2")); suppressDefault = true; } if (s.getMUCStatuses().contains(307)) { // Kick mucKickMsgHelper(nick, s, nickJid, tr("Kicked"), tr("You have been kicked from the room"), tr("You have been kicked from the room by %1"), tr("%1 has been kicked"), tr("%1 has been kicked by %2")); suppressDefault = true; } if (s.getMUCStatuses().contains(321)) { // Remove due to affiliation change mucKickMsgHelper(nick, s, nickJid, tr("Removed"), tr("You have been removed from the room due to an affiliation change"), tr("You have been removed from the room by %1 due to an affiliation change"), tr("%1 has been removed from the room due to an affilliation change"), tr("%1 has been removed from the room by %2 due to an affilliation change")); suppressDefault = true; } if (s.getMUCStatuses().contains(322)) { mucKickMsgHelper(nick, s, nickJid, tr("Removed"), tr("You have been removed from the room because the room was made members only"), tr("You have been removed from the room by %1 because the room was made members only"), tr("%1 has been removed from the room because the room was made members-only"), tr("%1 has been removed from the room by %2 because the room was made members-only")); suppressDefault = true; } if ( !d->connecting && !suppressDefault && options_->getOption("options.muc.show-joins").toBool() ) { if (s.getMUCStatuses().contains(303)) { message = tr("%1 is now known as %2").arg(nick).arg(s.mucItem().nick()); ui_.lv_users->updateEntry(s.mucItem().nick(), s); } else { //contact leaving message = tr("%1 has left the room").arg(nickJid); if (!s.status().isEmpty()) { message += QString(" (%1)").arg(s.status()); } } appendSysMsg(message, false, QDateTime::currentDateTime()); } ui_.lv_users->removeEntry(nick); } if (!s.capsNode().isEmpty()) { Jid caps_jid(s.mucItem().jid().isEmpty() || !d->nonAnonymous ? Jid(jid()).withResource(nick) : s.mucItem().jid()); account()->capsManager()->updateCaps(caps_jid,s.capsNode(),s.capsVersion(),s.capsExt()); } } void GCMainDlg::message(const Message &_m) { Message m = _m; QString from = m.from().resource(); bool alert = false; if (m.getMUCStatuses().contains(100)) { d->nonAnonymous = true; } if (m.getMUCStatuses().contains(172)) { d->nonAnonymous = true; } if (m.getMUCStatuses().contains(173)) { d->nonAnonymous = false; } if (m.getMUCStatuses().contains(174)) { d->nonAnonymous = false; } if(!m.subject().isEmpty()) { ui_.le_topic->setText(m.subject()); ui_.le_topic->setCursorPosition(0); ui_.le_topic->setToolTip(QString("

%1

").arg(m.subject())); if(m.body().isEmpty()) { if (!from.isEmpty()) m.setBody(QString("/me ") + tr("has set the topic to: %1").arg(m.subject())); else // The topic was set by the server m.setBody(tr("The topic has been set to: %1").arg(m.subject())); } } if(m.body().isEmpty()) return; // code to determine if the speaker was addressing this client in chat if(m.body().contains(d->self)) alert = true; if (m.body().left(d->self.length()) == d->self) d->lastReferrer = m.from().resource(); if(PsiOptions::instance()->getOption("options.ui.muc.use-highlighting").toBool()) { QStringList highlightWords = PsiOptions::instance()->getOption("options.ui.muc.highlight-words").toStringList(); foreach (QString word, highlightWords) { if(m.body().contains((word), Qt::CaseInsensitive)) { alert = true; } } } // play sound? if(from == d->self) { if(!m.spooled()) account()->playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.outgoing-chat").toString()); } else { if(alert || (PsiOptions::instance()->getOption("options.ui.notifications.sounds.notify-every-muc-message").toBool() && !m.spooled() && !from.isEmpty()) ) account()->playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.chat-message").toString()); } if(from.isEmpty()) appendSysMsg(m.body(), alert, m.timeStamp()); else appendMessage(m, alert); } void GCMainDlg::joined() { if(d->state == Private::Connecting) { ui_.lv_users->clear(); d->state = Private::Connected; ui_.pb_topic->setEnabled(true); ui_.mle->chatEdit()->setEnabled(true); setConnecting(); appendSysMsg(tr("Connected."), true); } } void GCMainDlg::setPassword(const QString& p) { d->password = p; } const QString& GCMainDlg::nick() const { return d->self; } void GCMainDlg::updateLastMsgTime(QDateTime t) { bool doInsert = t.date() != lastMsgTime_.date(); lastMsgTime_ = t; if (doInsert) { QString color = PsiOptions::instance()->getOption("options.ui.look.colors.messages.informational").toString(); ui_.log->appendText(QString("*** %2").arg(color).arg(t.date().toString(Qt::ISODate))); } } void GCMainDlg::appendSysMsg(const QString &str, bool alert, const QDateTime &ts) { if (d->trackBar) d->doTrackBar(); if (!PsiOptions::instance()->getOption("options.ui.muc.use-highlighting").toBool()) alert=false; QDateTime time = QDateTime::currentDateTime(); if(!ts.isNull()) time = ts; updateLastMsgTime(time); QString timestr = ui_.log->formatTimeStamp(time); QString color = PsiOptions::instance()->getOption("options.ui.look.colors.messages.informational").toString(); ui_.log->appendText(QString("[%2]").arg(color, timestr) + QString(" *** %1").arg(Qt::escape(str))); if(alert) doAlert(); } QString GCMainDlg::getNickColor(QString nick) { int sender; if(nick == d->self||nick.isEmpty()) sender = -1; else { if (!nicks.contains(nick)) { //not found in map nicks.insert(nick,nicknumber); nicknumber++; } sender=nicks[nick]; } QStringList nickColors = PsiOptions::instance()->getOption("options.ui.look.colors.muc.nick-colors").toStringList(); if(!PsiOptions::instance()->getOption("options.ui.muc.use-nick-coloring").toBool() || nickColors.empty()) { return "#000000"; } else if(sender == -1 || nickColors.size() == 1) { return nickColors[nickColors.size()-1]; } else { int n = sender % (nickColors.size()-1); return nickColors[n]; } } void GCMainDlg::appendMessage(const Message &m, bool alert) { updateLastMsgTime(m.timeStamp()); //QString who, color; if (!PsiOptions::instance()->getOption("options.ui.muc.use-highlighting").toBool()) alert=false; QString who, textcolor, nickcolor,alerttagso,alerttagsc; who = m.from().resource(); if (d->trackBar&&m.from().resource() != d->self&&!m.spooled()) d->doTrackBar(); /*if(local) { color = "#FF0000"; } else { color = "#0000FF"; }*/ nickcolor = getNickColor(who); textcolor = ui_.log->palette().windowText().color().name(); if(alert) { textcolor = "#FF0000"; alerttagso = ""; alerttagsc = ""; } if(m.spooled()) { nickcolor = PsiOptions::instance()->getOption("options.ui.look.colors.messages.informational").toString(); } QString timestr = ui_.log->formatTimeStamp(m.timeStamp()); bool emote = false; if(m.body().left(4) == "/me ") emote = true; QString txt; if(emote) txt = TextUtil::plain2rich(m.body().mid(4)); else txt = TextUtil::plain2rich(m.body()); txt = TextUtil::linkify(txt); if(PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool()) txt = TextUtil::emoticonify(txt); if( PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool() ) txt = TextUtil::legacyFormat(txt); if(emote) { //ui_.log->append(QString("").arg(color) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(Qt::escape(who)) + txt + ""); ui_.log->appendText(QString("").arg(nickcolor) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(Qt::escape(who)) + alerttagso + txt + alerttagsc + ""); } else { if(PsiOptions::instance()->getOption("options.ui.chat.use-chat-says-style").toBool()) { //ui_.log->append(QString("").arg(color) + QString("[%1] ").arg(timestr) + QString("%1 says:").arg(Qt::escape(who)) + "
" + txt); ui_.log->appendText(QString("").arg(nickcolor) + QString("[%1] ").arg(timestr) + QString("%1 says:").arg(Qt::escape(who)) + "
" + QString("").arg(textcolor) + alerttagso + txt + alerttagsc + ""); } else { //ui_.log->append(QString("").arg(color) + QString("[%1] <").arg(timestr) + Qt::escape(who) + QString("> ") + txt); ui_.log->appendText(QString("").arg(nickcolor) + QString("[%1] <").arg(timestr) + Qt::escape(who) + QString("> ") + QString("").arg(textcolor) + alerttagso + txt + alerttagsc +""); } } //if(local) if(m.from().resource() == d->self) { d->deferredScroll(); } // if we're not active, notify the user by changing the title if(!isActiveTab() && (who != d->self)) { ++d->pending; invalidateTab(); } //if someone directed their comments to us, notify the user if(alert) doAlert(); //if the message spoke to us, alert the user before closing this window //except that keepopen doesn't seem to be implemented for this class yet. /*if(alert) { d->keepOpen = true; QTimer::singleShot(1000, this, SLOT(setKeepOpenFalse())); }*/ } void GCMainDlg::doAlert() { if(!isActiveTab()) if (PsiOptions::instance()->getOption("options.ui.flash-windows").toBool()) doFlash(true); } QString GCMainDlg::desiredCaption() const { QString cap = ""; if (d->pending > 0) { cap += "* "; if (d->pending > 1) { cap += QString("[%1] ").arg(d->pending); } } cap += jid().full(); return cap; } void GCMainDlg::setLooks() { ui_.vsplitter->optionsChanged(); ui_.mle->optionsChanged(); // update the fonts QFont f; f.fromString(PsiOptions::instance()->getOption("options.ui.look.font.chat").toString()); ui_.log->setFont(f); ui_.mle->chatEdit()->setFont(f); f.fromString(PsiOptions::instance()->getOption("options.ui.look.font.contactlist").toString()); ui_.lv_users->setFont(f); if (PsiOptions::instance()->getOption("options.ui.chat.central-toolbar").toBool()) { ui_.toolbar->show(); ui_.tb_actions->hide(); ui_.tb_emoticons->hide(); } else { ui_.toolbar->hide(); ui_.tb_emoticons->setVisible(PsiOptions::instance()->getOption("options.ui.emoticons.use-emoticons").toBool()); ui_.tb_actions->show(); } setWindowOpacity(double(qMax(MINIMUM_OPACITY,PsiOptions::instance()->getOption("options.ui.chat.opacity").toInt()))/100); // update the widget icon #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/groupChat").icon()); #endif } void GCMainDlg::optionsUpdate() { /*QMimeSourceFactory *m = ui_.log->mimeSourceFactory(); ui_.log->setMimeSourceFactory(PsiIconset::instance()->emoticons.generateFactory()); delete m;*/ setLooks(); setShortcuts(); // update status icons ui_.lv_users->updateAll(); } void GCMainDlg::lv_action(const QString &nick, const Status &s, int x) { if(x == 0) { account()->invokeGCMessage(jid().withResource(nick)); } else if(x == 1) { account()->invokeGCChat(jid().withResource(nick)); } else if(x == 2) { UserListItem u; u.setJid(jid().withResource(nick)); u.setName(nick); // make a resource so the contact appears online UserResource ur; ur.setName(nick); ur.setStatus(s); u.userResourceList().append(ur); StatusShowDlg *w = new StatusShowDlg(u); w->show(); } else if(x == 3) { account()->invokeGCInfo(jid().withResource(nick)); } else if(x == 4) { account()->invokeGCFile(jid().withResource(nick)); } else if(x == 10) { d->mucManager->kick(nick); } else if(x == 11) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); d->mucManager->ban(contact->s.mucItem().jid()); } else if(x == 12) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().role() != MUCItem::Visitor) d->mucManager->setRole(nick, MUCItem::Visitor); } else if(x == 13) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().role() != MUCItem::Participant) d->mucManager->setRole(nick, MUCItem::Participant); } else if(x == 14) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().role() != MUCItem::Moderator) d->mucManager->setRole(nick, MUCItem::Moderator); } else if(x >= 100 && x<300) { // Kick || Ban with reason QString reason; QStringList reasons = PsiOptions::instance()->getOption("options.muc.reasons").toStringList(); if (x==100 || x==200) { // Show custom reason dialog MUCReasonsEditor *editor=new MUCReasonsEditor(this); if (editor->exec()) reason=editor->reason(); delete editor; } else { int idx = (x<200) ? x-101 : x-201; if (idxmucManager->kick(nick, reason); else { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (!contact) return; d->mucManager->ban(contact->s.mucItem().jid(), reason); } } } /*else if(x == 15) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().affiliation() != MUCItem::NoAffiliation) d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::NoAffiliation); } else if(x == 16) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().affiliation() != MUCItem::Member) d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::Member); } else if(x == 17) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().affiliation() != MUCItem::Admin) d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::Admin); } else if(x == 18) { GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick); if (contact->s.mucItem().affiliation() != MUCItem::Owner) d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::Owner); }*/ } void GCMainDlg::contextMenuEvent(QContextMenuEvent *) { d->pm_settings->exec(QCursor::pos()); } void GCMainDlg::buildMenu() { // Dialog menu d->pm_settings->clear(); d->act_clear->addTo( d->pm_settings ); d->act_configure->addTo( d->pm_settings ); #ifdef WHITEBOARDING d->act_whiteboard->addTo( d->pm_settings ); #endif d->pm_settings->addSeparator(); d->pm_settings->addAction(d->act_icon); d->pm_settings->addAction(d->act_nick); } void GCMainDlg::chatEditCreated() { d->mCmdSite.setInput(ui_.mle->chatEdit()); d->mCmdSite.setPrompt(ui_.mini_prompt); d->tabCompletion.setTextEdit(d->mle()); ui_.log->setDialog(this); ui_.mle->chatEdit()->setDialog(this); ui_.mle->chatEdit()->installEventFilter(d); } TabbableWidget::State GCMainDlg::state() const { return TabbableWidget::StateNone; } int GCMainDlg::unreadMessageCount() const { return d->pending; } //---------------------------------------------------------------------------- // GCFindDlg //---------------------------------------------------------------------------- GCFindDlg::GCFindDlg(const QString& str, QWidget* parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(tr("Find")); QVBoxLayout *vb = new QVBoxLayout(this); vb->setMargin(4); QHBoxLayout *hb = new QHBoxLayout; vb->addLayout(hb); QLabel *l = new QLabel(tr("Find:"), this); hb->addWidget(l); le_input = new QLineEdit(this); hb->addWidget(le_input); vb->addStretch(1); QFrame *Line1 = new QFrame(this); Line1->setFrameShape( QFrame::HLine ); Line1->setFrameShadow( QFrame::Sunken ); Line1->setFrameShape( QFrame::HLine ); vb->addWidget(Line1); hb = new QHBoxLayout; vb->addLayout(hb); hb->addStretch(1); QPushButton *pb_close = new QPushButton(tr("&Close"), this); connect(pb_close, SIGNAL(clicked()), SLOT(close())); hb->addWidget(pb_close); QPushButton *pb_find = new QPushButton(tr("&Find"), this); pb_find->setDefault(true); connect(pb_find, SIGNAL(clicked()), SLOT(doFind())); hb->addWidget(pb_find); pb_find->setAutoDefault(true); resize(200, minimumSizeHint().height()); le_input->setText(str); le_input->setFocus(); } GCFindDlg::~GCFindDlg() { } void GCFindDlg::found() { // nothing here to do... } void GCFindDlg::error(const QString &str) { QMessageBox::warning(this, tr("Find"), tr("Search string '%1' not found.").arg(str)); le_input->setFocus(); } void GCFindDlg::doFind() { emit find(le_input->text()); } #include "groupchatdlg.moc" psi-0.14/src/minicmd.h0000644000175000017500000001275311305557613012731 0ustar janjan/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see . * */ // Interfaces for mini command system #ifndef MINICMD_H #define MINICMD_H #include class QString; class QStringList; class MCmdProviderIface; /** unparsed state: this is a state where the whole user input is passed * unparsed as the first part to the handler functions */ #define MCMDSTATE_UNPARSED 1 /** This interface models the methods common to all mini command states. */ class MCmdStateIface { public: /** \return the name of the state */ virtual QString getName()=0; /** \return the prompt of the state */ virtual QString getPrompt()=0; /** \return flags for this state */ virtual int getFlags()=0; /** Called when the state is no longer needed to free associated memory. */ virtual void dispose()=0; /** Called when no more-specific state transition handler handled the command. */ virtual bool unhandled(QStringList command)=0; /** \return additional data for this state */ virtual const QHash &getInfo()=0; virtual ~MCmdStateIface() {}; }; /** Interface for user interface site of an mini command. * For every MCmdManager instance has one instance of this interface to * handle interaction with the user interface. * * The user interface has two states: closed or open. If the user interface * is open, it has a prompt shown to the user and some current input text. */ class MCmdUiSiteIface { // per interaction site public: /** Open user interface. * The site will open the user interface with displaying \a prompt as prompt and * inizialising the input box with \a def. */ virtual void mCmdReady(const QString prompt, const QString def)=0; /** Close user interface. * The site closes the user interface. */ virtual void mCmdClose()=0; virtual ~MCmdUiSiteIface() {}; }; /** Interface for the mini command manager. * This manager implements the core of the mini command state machine. * It uses an MCmdUiSite for it's interactions with the user interface and dispatches * commands and state transitions to MCmdProvider:s registered with it. * * Each manager with has one user interface site. */ class MCmdManagerIface { // per interaction site public: /** Processes a raw command from the user. * This method parses the command \a command and initiates the * state change for it. * \return FIXME needed? */ virtual bool processCommand(QString command)=0; /** Find possible tab complations on the command \a command with cursor on position \a pos. * * \return a list of possible replacements of the text between \a start and \a end. */ virtual QStringList completeCommand(QString &command, int pos, int &start, int &end)=0; /** Starts the state machine in the state \a state with a current * text of \a preset. */ virtual bool open(MCmdStateIface *state, QStringList preset)=0; /** Returns true if the manager is in a non null state; otherwise returns false. */ virtual bool isActive()=0; // Provider registratation /** Registers a provider \a prov with this manager. */ virtual void registerProvider(MCmdProviderIface *prov)=0; virtual ~MCmdManagerIface(){}; }; /** Interface for command providers for a mini command manager. * This interface is used to supply the state transitions and command execution * for a mini command area. * It defines possible states and their transitions. */ class MCmdProviderIface { // multiple independent users possible public: /** Called if a command is executed. * if oldstate is the well known state MCMD_STARTSTATE, the command that * was parsed to the argument list \a command was issued on the start prompt. * If the command is complete this method should set newstate to the well * known state MCMD_DONESTATE, otherwise, it sets \a newstate to the state * for the next prompt and \a preset to text to initially display * in the input box. The provider if \a newstate will get a mCmdInitState * call to setup this state. */ virtual bool mCmdTryStateTransit(MCmdStateIface *oldstate, QStringList command, MCmdStateIface *&newstate, QStringList &preset)=0; /** Called if the user requests tab completion while in state \a state. * \a query is the word to complete (from the start of the word to the * cursor). If the provider needs more context to find the list of * possible completions \a partcommand contains the parsed current * commandline and \a item indicates which part contains the cursor. * * \return a QStringList of all possible completions. If a completion ends with a null char, * an unquoted/unescaped space will be added at the end of the completion. Ordering is irrelevant. */ virtual QStringList mCmdTryCompleteCommand(MCmdStateIface *state, QString query, QStringList partcommand, int item)=0; /** FIXME */ virtual void mCmdSiteDestroyed()=0; // once per registerProvider virtual ~MCmdProviderIface() {}; }; #endif psi-0.14/src/psitoolbar.cpp0000644000175000017500000000774711305557613014031 0ustar janjan/* * psitoolbar.cpp - the Psi toolbar class * Copyright (C) 2003-2008 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psitoolbar.h" #include #include #include #include #include #include #include "iconset.h" #include "iconaction.h" #include "psioptions.h" #include "options/opt_toolbars.h" #include "common.h" Qt::ToolBarArea dockPositionToToolBarArea(Qt3Dock dock) { switch (dock) { case Qt3Dock_Top: return Qt::TopToolBarArea; case Qt3Dock_Bottom: return Qt::BottomToolBarArea; case Qt3Dock_Right: return Qt::RightToolBarArea; case Qt3Dock_Left: return Qt::LeftToolBarArea; case Qt3Dock_Unmanaged: case Qt3Dock_TornOff: case Qt3Dock_Minimized: ; } return Qt::NoToolBarArea; } PsiToolBar::PsiToolBar(const QString& base, QMainWindow* mainWindow, MetaActionList* actionList) : QToolBar(mainWindow) , actionList_(actionList) , base_(base) { Q_ASSERT(mainWindow); Q_ASSERT(actionList_); setIconSize(QSize(16, 16)); customizeAction_ = new QAction(tr("Configure& Toolbar..."), this); connect(customizeAction_, SIGNAL(triggered()), this, SIGNAL(customize())); } PsiToolBar::~PsiToolBar() { } void PsiToolBar::contextMenuEvent(QContextMenuEvent* e) { e->accept(); QMenu menu; menu.addAction(customizeAction_); menu.exec(e->globalPos()); } void PsiToolBar::initialize() { PsiOptions* o = PsiOptions::instance(); if (o->getOption(base_ + ".key").toString().isEmpty()) { o->setOption(base_ + ".key", ToolbarPrefs().id); } setObjectName(QString("mainwin-toolbar-%1").arg(o->getOption(base_ + ".key").toString())); setMovable(!o->getOption(base_ + ".locked").toBool()); setWindowTitle(o->getOption(base_ + ".name").toString()); ActionList actions = actionList_->suitableActions(PsiActionList::Actions_MainWin | PsiActionList::Actions_Common); foreach(QString actionName, o->getOption(base_ + ".actions").toStringList()) { IconAction* action = actions.action(actionName); if (action) { if (action->isSeparator()) { addSeparator(); } else { action->addTo(this); } } else { qWarning("PsiToolBar::initialize(): action %s not found!", qPrintable(actionName)); } } QMainWindow* mainWindow = dynamic_cast(parentWidget()); mainWindow->addToolBar(dockPositionToToolBarArea((Qt3Dock)o->getOption(base_ + ".dock.position").toInt()), this); if (mainWindow && o->getOption(base_ + ".dock.nl").toBool()) { mainWindow->insertToolBarBreak(this); } updateVisibility(); } void PsiToolBar::updateVisibility() { if (PsiOptions::instance()->getOption(base_ + ".visible").toBool()) { show(); } else { hide(); } } void PsiToolBar::structToOptions(PsiOptions* options, const ToolbarPrefs& tb) { Q_ASSERT(!tb.id.isEmpty()); QString base = options->mapPut("options.ui.contactlist.toolbars", tb.id); options->setOption(base + ".name", tb.name); options->setOption(base + ".visible", tb.on); options->setOption(base + ".locked", tb.locked); // options->setOption(base + ".stretchable", tb.stretchable); options->setOption(base + ".actions", tb.keys); options->setOption(base + ".dock.position", tb.dock); // options->setOption(base + ".dock.index", tb.index); options->setOption(base + ".dock.nl", tb.nl); // options->setOption(base + ".dock.extra-offset", tb.extraOffset); } psi-0.14/src/activeprofiles_dbus.cpp0000644000175000017500000001360111305557613015671 0ustar janjan/* * activeprofiles_dbus.cpp - Class for interacting with other psi instances * Copyright (C) 2006-2007 Martin Hostettler * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "activeprofiles.h" #include #include #include #include #include #include #include #include #include #include "applicationinfo.h" #include "dbus.h" /** \brief encodes a string to "[A-Z][a-z][0-9]_-" ascii subset * [A-Z][a-z][0-9] -> [A-Z][a-z][0-9] * / -> _ * everything else to "-XX" with XX hex code of char * (slow) */ static QString encodeAlNumD(QString in) { QString out; QByteArray chars = in.toUtf8(); bool first = true; foreach(char c, chars) { if (('A' <= c) && (c <= 'z')) { out += (char)c; } else if (('0' <= c) && (c <= '9') && !first) { out += (char)c; } else if ('/' == c) { out += "_"; } else { out += QString("-%1").arg(c, 2, 16, QChar('0')); } first = false; } return out; } /** \brief DBus busname registration helper * \param dbusIface interface of bus * \param name busname to register * \param queue try queueing? * \return got dbus name? */ static bool registerBusname(QDBusConnectionInterface *dbusIface, QString name, bool queue) { bool ok = false; QDBusReply reply; reply = dbusIface->registerService(name, queue ? QDBusConnectionInterface::QueueService : QDBusConnectionInterface::DontQueueService, QDBusConnectionInterface::AllowReplacement); if (reply.isValid()) { switch (reply.value()) { case QDBusConnectionInterface::ServiceNotRegistered: qWarning("failed to register dbus name %s:", qPrintable(name)); break; case QDBusConnectionInterface::ServiceQueued: qDebug("dbus name %s already taken, queueing", qPrintable(name)); break; case QDBusConnectionInterface::ServiceRegistered: ok = true; } } else { qWarning("failed to register dbus name %s: %s", qPrintable(name), qPrintable(reply.error().message())); } return ok; } class ActiveProfiles::Private { public: QString profile; QStringList busNames; bool registerBusnames(QString prof); QString dbusName(QString prof); }; QString ActiveProfiles::Private::dbusName(QString prof) { QString name = PSIDBUSNAME; name += "."; name += encodeAlNumD(ApplicationInfo::homeDir()).right(qMax(0,200-name.size())); if (!prof.isEmpty()) { name += "."; name += encodeAlNumD(prof).right(qMax(0,250-name.size())); } return name; } bool ActiveProfiles::Private::registerBusnames(QString prof) { // FIXME move where? if (!QDBusConnection::sessionBus().isConnected()) { qWarning("can't connect to dbus"); return true; } QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface (); QString name = PSIDBUSNAME; registerBusname(dbusIface, name, true); busNames << name; name = dbusName(QString()); registerBusname(dbusIface, name, true); busNames << name; name = dbusName(prof); busNames << name; return registerBusname(dbusIface, name, false); } bool ActiveProfiles::isActive(const QString &profile) const { if (!QDBusConnection::sessionBus().isConnected()) { qWarning("can't connect to dbus"); return false; } QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface (); return dbusIface->isServiceRegistered(d->dbusName(profile)); } bool ActiveProfiles::isAnyActive() const { return isActive(""); } bool ActiveProfiles::setThisProfile(const QString &profile) { if (profile == d->profile) return true; if (profile.isEmpty()) { unsetThisProfile(); return true; } bool ok = d->registerBusnames(profile); if (ok) { d->profile = profile; } else { unsetThisProfile(); } return ok; } void ActiveProfiles::unsetThisProfile() { QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface (); foreach(QString name, d->busNames) { dbusIface->unregisterService(name); } d->busNames.clear(); d->profile = QString::null; } QString ActiveProfiles::thisProfile() const { return d->profile; } ActiveProfiles::ActiveProfiles() : QObject(QCoreApplication::instance()) { d = new ActiveProfiles::Private; } ActiveProfiles::~ActiveProfiles() { delete d; d = 0; } bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const { QDBusInterface(d->dbusName(profile), "/Main", PSIDBUSMAINIF).call(QDBus::NoBlock, "setStatus", status, message); return true; } bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const { QDBusInterface(d->dbusName(profile), "/Main", PSIDBUSMAINIF).call(QDBus::NoBlock, "openURI", uri); return true; } bool ActiveProfiles::raise(const QString &profile, bool withUI) const { QLabel *lab=0; QDBusMessage msg = QDBusMessage::createMethodCall ( d->dbusName(profile), "/Main", PSIDBUSMAINIF, "raise" ); if (withUI) { lab = new QLabel(tr("This psi profile is already running...
please wait...")); QTimer::singleShot(250, lab, SLOT(show())); } QDBusMessage rmsg = QDBusConnection::sessionBus().call(msg, QDBus::BlockWithGui, 10000); if (withUI) { lab->hide(); delete lab; } if (rmsg.type() == QDBusMessage::ReplyMessage) { return true; } else return false; } psi-0.14/src/accountmanage.ui0000644000175000017500000000730011305557613014274 0ustar janjan AccountManage 0 0 540 280 Jabber Accounts 0 false true false true true true Name Server Status &Add psi/addContact &Modify Rem&ove psi/remove Qt::Vertical QSizePolicy::Expanding 20 127 QDialogButtonBox::Close qPixmapFromMimeSource IconButton QWidget
iconbutton.h
buttonBox rejected() AccountManage reject() 372 265 474 210
psi-0.14/src/lastactivitytask.cpp0000644000175000017500000000355111305557613015243 0ustar janjan/* * lastactivitytask.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_task.h" #include "xmpp_jid.h" #include "xmpp_xmlcommon.h" #include "lastactivitytask.h" using namespace XMPP; LastActivityTask::LastActivityTask(const Jid& jid, Task* parent) : Task(parent), jid_(jid) { iq_ = createIQ(doc(), "get", jid_.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:last"); iq_.appendChild(query); } /** * \brief Queried entity's JID. */ const Jid & LastActivityTask::jid() const { return jid_; } void LastActivityTask::onGo() { send(iq_); } bool LastActivityTask::take(const QDomElement &x) { if(!iqVerify(x, jid_, id())) return false; if(x.attribute("type") == "result") { bool ok = false; QDomElement q = queryTag(x); int seconds = q.attribute("seconds").toInt(&ok); if (ok) { last_time_ = QDateTime::currentDateTime().addSecs(-seconds); } last_status_ = q.text(); setSuccess(); } else { setError(x); } return true; } const QString& LastActivityTask::status() const { return last_status_; } const QDateTime& LastActivityTask::time() const { return last_time_; } psi-0.14/src/accountscombobox.cpp0000644000175000017500000000601111305557613015202 0ustar janjan/* * accountscombobox.cpp * Copyright (C) 2001-2008 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psicon.h" #include "accountscombobox.h" #include "psiaccount.h" #include "psicontactlist.h" AccountsComboBox::AccountsComboBox(QWidget* parent) : QComboBox(parent) , controller_(0) , account_(0) , onlineOnly_(false) { setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); connect(this, SIGNAL(activated(int)), this, SLOT(changeAccount())); } AccountsComboBox::~AccountsComboBox() { } PsiAccount* AccountsComboBox::account() const { return account_; } void AccountsComboBox::setAccount(PsiAccount* account) { account_ = account; updateAccounts(); } PsiCon* AccountsComboBox::controller() const { return controller_; } void AccountsComboBox::setController(PsiCon* controller) { if (controller_) { disconnect(controller_, SIGNAL(accountCountChanged()), this, SLOT(updateAccounts())); disconnect(controller_, SIGNAL(accountActivityChanged()), this, SLOT(updateAccounts())); } controller_ = controller; if (controller_) { connect(controller_, SIGNAL(accountCountChanged()), this, SLOT(updateAccounts())); connect(controller_, SIGNAL(accountActivityChanged()), this, SLOT(updateAccounts())); } if (controller_->contactList()->haveEnabledAccounts()) { setAccount(controller_->contactList()->enabledAccounts().first()); } updateAccounts(); } bool AccountsComboBox::onlineOnly() const { return onlineOnly_; } void AccountsComboBox::setOnlineOnly(bool onlineOnly) { onlineOnly_ = onlineOnly; updateAccounts(); } void AccountsComboBox::changeAccount() { account_ = 0; if (currentIndex() >= 0 && currentIndex() < accounts().count()) account_ = accounts().at(currentIndex()); emit activated(account_); } void AccountsComboBox::updateAccounts() { clear(); foreach(PsiAccount* account, accounts()) addItem(account->nameWithJid()); if (accounts().indexOf(account_) == -1) { account_ = accounts().isEmpty() ? 0 : accounts().first(); emit activated(account_); } setCurrentIndex(accounts().indexOf(account_)); } QList AccountsComboBox::accounts() const { QList result; if (controller_) { foreach(PsiAccount* account, controller_->contactList()->enabledAccounts()) if (!onlineOnly_ || account->isAvailable()) result << account; } return result; } psi-0.14/src/rtparse.h0000644000175000017500000000240111305557613012756 0ustar janjan/**************************************************************************** ** rtparse.h - class for manipulating richtext ** Copyright (C) 2001, 2002 Justin Karneges ** ** 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 2 ** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA. ** ****************************************************************************/ #ifndef RTPARSE_H #define RTPARSE_H #include class RTParse { public: RTParse(const QString &); const QString &output() const; QString next(); bool atEnd() const; void putPlain(const QString &); void putRich(const QString &); private: QString in, out; int v_at; bool v_atEnd; }; #endif psi-0.14/src/mucaffiliationsview.h0000644000175000017500000000231211305557613015347 0ustar janjan/* * mucaffiliationsview.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MUCAFFILIATIONSVIEW_H #define MUCAFFILIATIONSVIEW_H #include class MUCAffiliationsView : public QTreeView { Q_OBJECT public: MUCAffiliationsView(QWidget* parent = 0); public slots: void removeCurrent(); bool addToCurrent(const QString&); signals: void addEnabled(bool); void removeEnabled(bool); protected: virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); }; #endif psi-0.14/src/psicli.h0000644000175000017500000000576611305557613012602 0ustar janjan#ifndef PSICLI_H #define PSICLI_H #include "simplecli.h" #include "applicationinfo.h" #include #include #include class PsiCli : public SimpleCli { Q_OBJECT public: PsiCli() { defineParam("profile", tr("PROFILE", "translate in UPPER_CASE with no spaces"), tr("Activate program instance running specified profile. " "Otherwise, open new instance using this profile " "(unless used together with --remote).", "do not translate --remote")); defineSwitch("remote", tr("Force remote-control mode. " "If there is no running instance, " "or --profile was specified but there is no instance using it, " "exit without doing anything. " "Cannot be used with --choose-profile.", "do not translate --profile, --choose-profile")); defineSwitch("choose-profile", tr("Display Choose Profile dialog on startup. " "Cannot be used together with --remote.", "do not translate --remote")); defineParam("uri", tr("URI", "translate in UPPER_CASE with no spaces"), tr("Open XMPP URI. (e.g. xmpp:someone@example.org?chat) " "For security reasons, this must be the last option.")); defineParam("status", tr("STATUS", "translate in UPPER_CASE with no spaces"), tr("Set status. STATUS must be one of `online', `chat', `away', `xa', `dnd', `offline'.", "do not translate `online', `chat', etc; STATUS is the same as in previous string")); defineParam("status-message", tr("MSG", "translate in UPPER_CASE with no spaces"), tr("Set status message. Must be used together with --status.", "do not translate --status")); defineSwitch("help", tr("Show this help message and exit.")); defineAlias("h", "help"); defineAlias("?", "help"); defineSwitch("version", tr("Show version information and exit.")); defineAlias("v", "version"); } void showHelp(int textWidth = 78) { QString u1 = tr("Usage:") + " " + QFileInfo(QApplication::applicationFilePath()).fileName(); QString u2 = "%1 [--profile=%2] [--remote|--choose-profile] [--status=%3\t[--status-message=%4]] [--uri=%5]"; QString output = wrap(u2.arg(u1, tr("PROFILE"), tr("STATUS"), tr("MSG"), tr("URI")), textWidth, u1.length() + 1, 0).replace('\t', ' '); // non-breakable space ;) output += '\n'; output += tr("Psi - The Cross-Platform Jabber/XMPP Client For Power Users"); output += "\n\n"; output += tr("Options:"); output += '\n'; output += optionsHelp(textWidth); output += '\n'; output += tr("Go to for more information about Psi."); show(output); } void showVersion() { show(QString("%1 %2\nQt %3\n") .arg(ApplicationInfo::name()).arg(ApplicationInfo::version()) .arg(qVersion()) +QString(tr("Compiled with Qt %1", "%1 will contain Qt version number")) .arg(QT_VERSION_STR)); } void show(const QString& text) { #ifdef Q_WS_WIN QMessageBox::information(0, ApplicationInfo::name(), text); #else puts(qPrintable(text)); #endif } virtual ~PsiCli() {} }; #endif psi-0.14/src/textutil.h0000644000175000017500000000074011305557613013164 0ustar janjan#ifndef TEXTUTIL_H #define TEXTUTIL_H class QString; namespace TextUtil { QString escape(const QString& unescaped); QString unescape(const QString& escaped); QString quote(const QString &, int width=60, bool quoteEmpty=false); QString plain2rich(const QString &); QString rich2plain(const QString &); QString resolveEntities(const QString &); QString linkify(const QString &); QString legacyFormat(const QString &); QString emoticonify(const QString &in); }; #endif psi-0.14/src/miniclient.h0000644000175000017500000000410211305557613013431 0ustar janjan/* * miniclient.h * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MINICLIENT_H #define MINICLIENT_H #include #include #include "xmpp_jid.h" namespace XMPP { class Client; class ClientStream; class AdvancedConnector; class QCATLSHandler; } namespace QCA { class TLS; } class ProxyManager; class QString; class QByteArray; class MiniClient : public QObject { Q_OBJECT public: MiniClient(QObject *parent=0); ~MiniClient(); void reset(); void connectToServer(const XMPP::Jid &j, bool legacy_ssl_probe, bool legacy_ssl, bool force_ssl, const QString &host, int port, ProxyManager *pm, QString proxy, QString *pass = NULL); void close(); XMPP::Client *client(); void setErrorOnDisconnect(bool); QString tlsOverrideDomain; QByteArray tlsOverrideCert; signals: void handshaken(); void error(); void disconnected(); private slots: void tls_handshaken(); void cs_connected(); void cs_securityLayerActivated(int); void cs_needAuthParams(bool, bool, bool); void cs_authenticated(); void cs_connectionClosed(); void cs_delayedCloseFinished(); void cs_warning(int); void cs_error(int); void sessionStart_finished(); private: XMPP::AdvancedConnector *conn; XMPP::ClientStream *stream; QCA::TLS *tls; XMPP::QCATLSHandler *tlsHandler; XMPP::Client *_client; XMPP::Jid j; QString pass; bool auth, force_ssl, error_disconnect; }; #endif psi-0.14/src/statusdlg.h0000644000175000017500000000276711305557613013327 0ustar janjan/* * statusdlg.h - dialogs for setting and reading status messages * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef STATUSDLG_H #define STATUSDLG_H #include class PsiCon; class PsiAccount; class UserListItem; class QKeyEvent; namespace XMPP { class Status; } using namespace XMPP; class StatusShowDlg : public QDialog { Q_OBJECT public: StatusShowDlg(const UserListItem &); }; class StatusSetDlg : public QDialog { Q_OBJECT public: StatusSetDlg(PsiCon *, const Status &); StatusSetDlg(PsiAccount *, const Status &); ~StatusSetDlg(); signals: void set(const XMPP::Status &, bool withPriority); void cancelled(); private slots: void doButton(); void cancel(); void reject(); void chooseStatusPreset(int); private: class Private; Private *d; void init(); }; #endif psi-0.14/src/registrationdlg.h0000644000175000017500000000272111305557613014504 0ustar janjan/* * registrationdlg.h * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef REGISTRATIONDLG_H #define REGISTRATIONDLG_H #include class QDomElement; class JT_XRegister; class PsiAccount; namespace XMPP { class Jid; class Form; } class RegistrationDlg : public QDialog { Q_OBJECT public: RegistrationDlg(const XMPP::Jid &, PsiAccount *); ~RegistrationDlg(); public slots: void done(int); private slots: void doRegGet(); void doRegSet(); void jt_finished(); private: class Private; Private *d; void setData(JT_XRegister* jt); void updateData(JT_XRegister* jt); void setInstructions(const QString& jid, const QString& instructions); bool processXData(const QDomElement& iq); void processLegacyForm(const XMPP::Form& form); }; #endif psi-0.14/src/filetransdlg.h0000644000175000017500000000577611305557613013776 0ustar janjan#ifndef FILETRANSDLG_H #define FILETRANSDLG_H #include "advwidget.h" #include "ui_filetrans.h" #include "s5b.h" class PsiCon; class PsiAccount; namespace XMPP { class FileTransfer; class Jid; } using namespace XMPP; class FileTransferHandler : public QObject { Q_OBJECT public: enum { ErrReject, ErrTransfer, ErrFile }; enum { Sending, Receiving }; FileTransferHandler(PsiAccount *pa, FileTransfer *ft=0); ~FileTransferHandler(); PsiAccount *account() const; int mode() const; Jid peer() const; QString fileName() const; qlonglong fileSize() const; QString description() const; qlonglong offset() const; int totalSteps() const; bool resumeSupported() const; QString saveName() const; void send(const Jid &to, const QString &fname, const QString &desc); void accept(const QString &saveName, const QString &fileName, qlonglong offset=0); signals: void accepted(); void statusMessage(const QString &s); void connected(); void progress(int p, qlonglong sent); void error(int, int, const QString &s); private slots: // s5b status void s5b_proxyQuery(); void s5b_proxyResult(bool b); void s5b_requesting(); void s5b_accepted(); void s5b_tryingHosts(const StreamHostList &hosts); void s5b_proxyConnect(); void s5b_waitingForActivation(); // ft void ft_accepted(); void ft_connected(); void ft_readyRead(const QByteArray &); void ft_bytesWritten(int); void ft_error(int); void trySend(); void doFinish(); private: class Private; Private *d; void mapSignals(); }; class FileRequestDlg : public QDialog, public Ui::FileTrans { Q_OBJECT public: FileRequestDlg(const Jid &j, PsiCon *psi, PsiAccount *pa); FileRequestDlg(const Jid &j, PsiCon *psi, PsiAccount *pa, const QStringList& files, bool direct = false); FileRequestDlg(const QDateTime &ts, FileTransfer *ft, PsiAccount *pa); ~FileRequestDlg(); protected: void keyPressEvent(QKeyEvent *); public slots: void done(int r); private slots: void updateIdentity(PsiAccount *); void updateIdentityVisibility(); void pa_disconnected(); void chooseFile(); void doStart(); void ft_accepted(); void ft_statusMessage(const QString &s); void ft_connected(); void ft_error(int, int, const QString &); void t_timeout(); private: class Private; Private *d; void blockWidgets(); void unblockWidgets(); }; class FileTransDlg : public AdvancedWidget { Q_OBJECT public: FileTransDlg(PsiCon *); ~FileTransDlg(); int addItem(const QString &filename, qlonglong size, const QString &peer, bool sending); void setProgress(int id, int step, int total, qlonglong sent, int bytesPerSecond, bool updateAll=false); void setError(int id, const QString &reason); void removeItem(int id); void takeTransfer(FileTransferHandler *h, int p, qlonglong sent); void killTransfers(PsiAccount *pa); private slots: void clearFinished(); void ft_progress(int p, qlonglong sent); void ft_error(int, int, const QString &s); void updateItems(); void itemCancel(int); void itemOpenDest(int); void itemClear(int); private: class Private; Private *d; }; #endif psi-0.14/src/psiiconset.cpp0000644000175000017500000004275111305557613014025 0ustar janjan/* * psiiconset.cpp - the Psi iconset class * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "psiiconset.h" #include "psievent.h" #include "common.h" #include "userlist.h" #include "anim.h" #include "applicationinfo.h" #include "psioptions.h" #include #include #include using namespace XMPP; //---------------------------------------------------------------------------- // PsiIconset //---------------------------------------------------------------------------- class PsiIconset::Private { private: PsiIconset *psi; public: Iconset system; QString cur_system, cur_status; QStringList cur_emoticons; QMap cur_service_status; QMap cur_custom_status; Private(PsiIconset *_psi) { psi = _psi; } QString iconsetPath(QString name) { QStringList dirs; dirs << ":"; dirs << "."; dirs << ApplicationInfo::homeDir(); dirs << ApplicationInfo::resourcesDir(); QStringList::Iterator it = dirs.begin(); for ( ; it != dirs.end(); ++it) { QString fileName = *it + "/iconsets/" + name; QFileInfo fi(fileName); if ( fi.exists() ) return fileName; } qWarning("PsiIconset::Private::iconsetPath(\"%s\"): not found", qPrintable(name)); return QString(); } void stripFirstAnimFrame(Iconset &is) { QListIterator it = is.iterator(); while (it.hasNext()) { it.next()->stripFirstAnimFrame(); } } void loadIconset(Iconset *to, Iconset *from) { if ( !to ) { qWarning("PsiIconset::loadIconset(): 'to' iconset is NULL!"); if ( from ) qWarning("from->name() = '%s'", qPrintable(from->name())); return; } if ( !from ) { qWarning("PsiIconset::loadIconset(): 'from' iconset is NULL!"); if ( to ) qWarning("to->name() = '%s'", qPrintable(to->name())); return; } QListIterator it = from->iterator(); while( it.hasNext()) { PsiIcon *icon = it.next(); if ( icon && !icon->name().isEmpty() ) { PsiIcon *toIcon = (PsiIcon *)to->icon(icon->name()); if ( toIcon ) { if ( icon->anim() ) { // setAnim and setImpix both // emit pixmapChanged(), // however we only want this // to happen once, and only // after both functions have // been processed. so we // block signals during the // first call. bool b = toIcon->blockSignals(true); toIcon->setAnim ( *icon->anim(), false ); toIcon->blockSignals(b); toIcon->setImpix ( icon->impix(), false ); } else { // same as above bool b = toIcon->blockSignals(true); toIcon->setAnim ( Anim(), false ); toIcon->blockSignals(b); toIcon->setImpix ( icon->impix(), false ); } } else to->setIcon( icon->name(), *icon ); } } to->setInformation(*from); } PsiIcon *jid2icon(const Jid &jid, const QString &iconName) { // first level -- global default icon PsiIcon *icon = (PsiIcon *)IconsetFactory::iconPtr(iconName); // second level -- transport icon if ( jid.node().isEmpty() || PsiOptions::instance()->getOption("options.ui.contactlist.use-transport-icons").toBool() ) { QMap services; services["aim"] = QRegExp("^aim"); services["gadugadu"] = QRegExp("^gg"); services["icq"] = QRegExp("^icq"); services["msn"] = QRegExp("^msn"); services["yahoo"] = QRegExp("^yahoo"); services["sms"] = QRegExp("^sms"); bool found = false; foreach(QVariant serviceV, PsiOptions::instance()->mapKeyList("options.iconsets.service-status")) { QString service = serviceV.toString(); if (services.contains(service)) { if (services[service].indexIn(jid.domain()) != -1 ) { const Iconset *is = psi->roster.value( PsiOptions::instance()->getOption( PsiOptions::instance()->mapLookup("options.iconsets.service-status", service)+".iconset").toString()); if ( is ) { PsiIcon *i = (PsiIcon *)is->icon(iconName); if ( i ) { icon = i; found = true; break; } } } } } // let's try the default transport iconset then... if ( !found && jid.node().isEmpty() ) { if (PsiOptions::instance()->mapKeyList("options.iconsets.service-status").contains("transport")) { const Iconset *is = psi->roster.value( PsiOptions::instance()->getOption( PsiOptions::instance()->mapLookup("options.iconsets.service-status", "transport")+".iconset").toString()); if ( is ) { PsiIcon *i = (PsiIcon *)is->icon(iconName); if ( i ) icon = i; } } } } // third level -- custom icons QStringList customicons = PsiOptions::instance()->getChildOptionNames("options.iconsets.custom-status", true, true); foreach(QString base, customicons) { QRegExp rx = QRegExp(PsiOptions::instance()->getOption(base + ".regexp").toString()); if ( rx.indexIn(jid.bare()) != -1 ) { const Iconset *is = psi->roster.value(PsiOptions::instance()->getOption(base + ".iconset").toString()); if ( is ) { PsiIcon *i = (PsiIcon *)is->icon(iconName); if ( i ) icon = (PsiIcon *)is->icon(iconName); } } } return icon; } Iconset systemIconset(bool *ok) { Iconset def; *ok = def.load(":/iconsets/system/default"); if ( PsiOptions::instance()->getOption("options.iconsets.system").toString() != "default" ) { Iconset is; is.load ( iconsetPath("system/" + PsiOptions::instance()->getOption("options.iconsets.system").toString()) ); loadIconset(&def, &is); } stripFirstAnimFrame( def ); return def; } Iconset *defaultRosterIconset(bool *ok) { Iconset *def = new Iconset; *ok = def->load (":/iconsets/roster/default"); if ( PsiOptions::instance()->getOption("options.iconsets.status").toString() != "default" ) { Iconset is; is.load ( iconsetPath("roster/" + PsiOptions::instance()->getOption("options.iconsets.status").toString()) ); loadIconset(def, &is); } stripFirstAnimFrame( *def ); return def; } QList emoticons() { QList emo; foreach(QString name, PsiOptions::instance()->getOption("options.iconsets.emoticons").toStringList()) { Iconset *is = new Iconset; if ( is->load ( iconsetPath("emoticons/" + name) ) ) { PsiIconset::removeAnimation(is); is->addToFactory(); emo.append( is ); } else delete is; } return emo; } }; PsiIconset::PsiIconset() : QObject(QCoreApplication::instance()) { d = new Private(this); connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionChanged(const QString&))); } PsiIconset::~PsiIconset() { delete d; } bool PsiIconset::loadSystem() { bool ok = true; QString cur_system = PsiOptions::instance()->getOption("options.iconsets.system").toString(); if (d->cur_system != cur_system) { Iconset sys = d->systemIconset(&ok); d->loadIconset(&d->system, &sys); //d->system = d->systemIconset(); d->system.addToFactory(); d->cur_system = cur_system; } return ok; } bool PsiIconset::loadRoster() { // load roster qDeleteAll(roster); roster.clear(); // default roster iconset bool ok; Iconset *def = d->defaultRosterIconset(&ok); def->addToFactory(); roster.insert(PsiOptions::instance()->getOption("options.iconsets.status").toString(), def); d->cur_status = PsiOptions::instance()->getOption("options.iconsets.status").toString(); // load only necessary roster iconsets QSet rosterIconsets; d->cur_service_status.clear(); foreach(QVariant service, PsiOptions::instance()->mapKeyList("options.iconsets.service-status")) { QString val = PsiOptions::instance()->getOption( PsiOptions::instance()->mapLookup("options.iconsets.service-status", service) + ".iconset").toString(); if (val.isEmpty()) continue; rosterIconsets << val; d->cur_service_status.insert(service.toString(), val); } QStringList customicons = PsiOptions::instance()->getChildOptionNames("options.iconsets.custom-status", true, true); d->cur_custom_status.clear(); foreach(QString base, customicons) { QString regexp = PsiOptions::instance()->getOption(base + ".regexp").toString(); QString iconset = PsiOptions::instance()->getOption(base + ".iconset").toString(); rosterIconsets << iconset; d->cur_custom_status.insert(regexp, iconset); } foreach(QString it2, rosterIconsets) { if (it2 == PsiOptions::instance()->getOption("options.iconsets.status").toString()) { continue; } Iconset *is = new Iconset; if (is->load(d->iconsetPath("roster/" + it2))) { is->addToFactory(); d->stripFirstAnimFrame(*is); roster.insert(it2, is); } else { delete is; } } return ok; } void PsiIconset::loadEmoticons() { QStringList cur_emoticons = PsiOptions::instance()->getOption("options.iconsets.emoticons").toStringList(); if (d->cur_emoticons != cur_emoticons) { qDeleteAll(emoticons); emoticons.clear(); emoticons = d->emoticons(); d->cur_emoticons = cur_emoticons; emit emoticonsChanged(); } } bool PsiIconset::loadAll() { if (!loadSystem() || !loadRoster()) return false; loadEmoticons(); return true; } void PsiIconset::optionChanged(const QString& option) { if (option == "options.iconsets.system") { loadSystem(); } else if (option == "options.iconsets.emoticons") { loadEmoticons(); } // currently we rely on PsiCon calling reloadRoster() when // all options are already applied. otherwise we risk the chance // being called too many times // else if (option == "options.iconsets.status" || // option.startsWith("options.iconsets.service-status.") || // option.startsWith("options.iconsets.custom-status.")) // { // reloadRoster(); // } } void PsiIconset::reloadRoster() { bool ok; QString cur_status = PsiOptions::instance()->getOption("options.iconsets.status").toString(); // default roster iconset if (d->cur_status != cur_status) { Iconset *newDef = d->defaultRosterIconset(&ok); Iconset *oldDef = roster[d->cur_status]; d->loadIconset(oldDef, newDef); roster.remove(d->cur_status); roster.insert(cur_status, oldDef); delete newDef; d->cur_status = cur_status; } QMap cur_service_status; QMap cur_custom_status; foreach(QVariant service, PsiOptions::instance()->mapKeyList("options.iconsets.service-status")) { QString val = PsiOptions::instance()->getOption( PsiOptions::instance()->mapLookup("options.iconsets.service-status", service) + ".iconset").toString(); if (val.isEmpty()) continue; cur_service_status.insert(service.toString(), val); } QStringList customicons = PsiOptions::instance()->getChildOptionNames("options.iconsets.custom-status", true, true); foreach(QString base, customicons) { QString regexp = PsiOptions::instance()->getOption(base + ".regexp").toString(); QString iconset = PsiOptions::instance()->getOption(base + ".iconset").toString(); cur_custom_status.insert(regexp, iconset); } // service&custom roster iconsets if (operator!=(d->cur_service_status, cur_service_status) || operator!=(d->cur_custom_status, cur_custom_status)) { QStringList rosterIconsets; QMap::Iterator it = cur_service_status.begin(); for (; it != cur_service_status.end(); ++it) if (!rosterIconsets.contains(it.value())) rosterIconsets << it.value(); it = cur_custom_status.begin(); for (; it != cur_custom_status.end(); ++it) if (!rosterIconsets.contains(it.value())) rosterIconsets << it.value(); QStringList::Iterator it2 = rosterIconsets.begin(); for (; it2 != rosterIconsets.end(); ++it2) { if (*it2 == PsiOptions::instance()->getOption("options.iconsets.status").toString()) continue; Iconset *is = new Iconset; if (is->load(d->iconsetPath("roster/" + *it2))) { d->stripFirstAnimFrame(*is); Iconset *oldis = roster[*it2]; if (oldis) d->loadIconset(oldis, is); else { is->addToFactory(); roster.insert(*it2, is); } } else delete is; } bool clear = false; while (!clear) { clear = true; QMutableHashIterator it3(roster); while (it3.hasNext()) { it3.next(); QString name = it3.key(); if (name == PsiOptions::instance()->getOption("options.iconsets.status").toString()) continue; if (!rosterIconsets.contains(name)) { // remove redundant iconset delete roster[name]; it3.remove(); clear = false; break; } } } d->cur_service_status = cur_service_status; d->cur_custom_status = cur_custom_status; } } PsiIcon *PsiIconset::event2icon(PsiEvent *e) { QString icon; if(e->type() == PsiEvent::Message) { MessageEvent *me = (MessageEvent *)e; const Message &m = me->message(); if(m.type() == "headline") icon = "psi/headline"; else if(m.type() == "chat") icon = "psi/chat"; else if(m.type() == "error") icon = "psi/system"; else icon = "psi/message"; } else if(e->type() == PsiEvent::File) { icon = "psi/file"; } else if(e->type() == PsiEvent::AvCallType) { icon = "psi/call"; } else { icon = "psi/system"; } return d->jid2icon(e->from(), icon); } static QString status2name(int s) { QString name; switch ( s ) { case STATUS_OFFLINE: name = "status/offline"; break; case STATUS_AWAY: name = "status/away"; break; case STATUS_XA: name = "status/xa"; break; case STATUS_DND: name = "status/dnd"; break; case STATUS_INVISIBLE: name = "status/invisible"; break; case STATUS_CHAT: name = "status/chat"; break; case STATUS_ASK: name = "status/ask"; break; case STATUS_NOAUTH: name = "status/noauth"; break; case STATUS_ERROR: name = "status/error"; break; case -1: name = "psi/connect"; break; case STATUS_ONLINE: default: name = "status/online"; } return name; } PsiIcon *PsiIconset::statusPtr(int s) { return (PsiIcon *)IconsetFactory::iconPtr(status2name(s)); } PsiIcon PsiIconset::status(int s) { PsiIcon *icon = statusPtr(s); if ( icon ) return *icon; return PsiIcon(); } PsiIcon *PsiIconset::statusPtr(const XMPP::Status &s) { return statusPtr(makeSTATUS(s)); } PsiIcon PsiIconset::status(const XMPP::Status &s) { return status(makeSTATUS(s)); } PsiIcon *PsiIconset::transportStatusPtr(QString name, int s) { PsiIcon *icon = 0; QVariantList serviceicons = PsiOptions::instance()->mapKeyList("options.iconsets.service-status"); if (serviceicons.contains(name)) { const Iconset *is = roster.value( PsiOptions::instance()->getOption( PsiOptions::instance()->mapLookup("options.iconsets.service-status", name)+".iconset").toString()); if ( is ) { icon = (PsiIcon *)is->icon(status2name(s)); } } if ( !icon ) icon = statusPtr(s); return icon; } PsiIcon *PsiIconset::transportStatusPtr(QString name, const XMPP::Status &s) { return transportStatusPtr(name, makeSTATUS(s)); } PsiIcon PsiIconset::transportStatus(QString name, int s) { PsiIcon *icon = transportStatusPtr(name, s); if ( icon ) return *icon; return PsiIcon(); } PsiIcon PsiIconset::transportStatus(QString name, const XMPP::Status &s) { PsiIcon *icon = transportStatusPtr(name, s); if ( icon ) return *icon; return PsiIcon(); } PsiIcon *PsiIconset::statusPtr(const XMPP::Jid &jid, int s) { return d->jid2icon(jid, status2name(s)); } PsiIcon *PsiIconset::statusPtr(const XMPP::Jid &jid, const XMPP::Status &s) { return statusPtr(jid, makeSTATUS(s)); } PsiIcon PsiIconset::status(const XMPP::Jid &jid, int s) { PsiIcon *icon = statusPtr(jid, s); if ( icon ) return *icon; return PsiIcon(); } PsiIcon PsiIconset::status(const XMPP::Jid &jid, const XMPP::Status &s) { PsiIcon *icon = statusPtr(jid, s); if ( icon ) return *icon; return PsiIcon(); } PsiIcon *PsiIconset::statusPtr(UserListItem *u) { if ( !u ) return 0; int s = 0; if ( !u->presenceError().isEmpty() ) s = STATUS_ERROR; else if ( u->isTransport() ) { if ( u->isAvailable() ) s = makeSTATUS( (*(u->priority())).status() ); else s = STATUS_OFFLINE; } else if ( u->ask() == "subscribe" && !u->isAvailable() && !u->isTransport() ) s = STATUS_ASK; else if ( (u->subscription().type() == Subscription::From || u->subscription().type() == Subscription::None) && !u->isAvailable() && !u->isPrivate() ) s = STATUS_NOAUTH; else if( !u->isAvailable() ) s = STATUS_OFFLINE; else s = makeSTATUS( (*(u->priority())).status() ); return statusPtr(u->jid(), s); } PsiIcon PsiIconset::status(UserListItem *u) { PsiIcon *icon = statusPtr(u); if ( icon ) return *icon; return PsiIcon(); } const Iconset &PsiIconset::system() const { return d->system; } void PsiIconset::stripFirstAnimFrame(Iconset *is) { if ( is ) d->stripFirstAnimFrame(*is); } void PsiIconset::removeAnimation(Iconset *is) { if ( is ) { QListIterator it = is->iterator(); while (it.hasNext()) { it.next()->removeAnim(false); } } } PsiIconset* PsiIconset::instance() { if (!instance_) instance_ = new PsiIconset(); return instance_; } PsiIconset* PsiIconset::instance_ = NULL; psi-0.14/src/addurl.ui0000644000175000017500000000673011305557613012750 0ustar janjan AddUrl 0 0 337 123 Add URL 11 6 0 6 URL: Description: 16 16 Expanding Vertical 0 203 16 Expanding Horizontal &Close &OK Alt+O true qPixmapFromMimeSource le_url le_desc psi-0.14/src/mucaffiliationsproxymodel.h0000644000175000017500000000052411305557613016602 0ustar janjan#ifndef MUCAFFILIATIONSPROXYMODEL_H #define MUCAFFILIATIONSPROXYMODEL_H #include class MUCAffiliationsProxyModel : public QSortFilterProxyModel { Q_OBJECT public: MUCAffiliationsProxyModel(QObject* parent = 0); protected: bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const; }; #endif psi-0.14/src/gcuserview.cpp0000644000175000017500000003451711305557613014031 0ustar janjan/* * gcuserview.cpp - groupchat roster * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "gcuserview.h" #include #include #include #include #include #include "capsmanager.h" #include "psitooltip.h" #include "psiaccount.h" #include "userlist.h" #include "psiiconset.h" #include "groupchatdlg.h" #include "common.h" #include "psioptions.h" static bool caseInsensitiveLessThan(const QString &s1, const QString &s2) { return s1.toLower() < s2.toLower(); } //---------------------------------------------------------------------------- // GCUserViewItem //---------------------------------------------------------------------------- GCUserViewItem::GCUserViewItem(GCUserViewGroupItem *par) : QObject() , Q3ListViewItem(par) { setDragEnabled(true); } void GCUserViewItem::paintFocus(QPainter *, const QColorGroup &, const QRect &) { // re-implimented to do nothing. selection is enough of a focus } void GCUserViewItem::paintBranches(QPainter *p, const QColorGroup &cg, int w, int, int h) { // paint a square of nothing p->fillRect(0, 0, w, h, cg.base()); } //---------------------------------------------------------------------------- // GCUserViewGroupItem //---------------------------------------------------------------------------- GCUserViewGroupItem::GCUserViewGroupItem(GCUserView *par, const QString& t, int k) :Q3ListViewItem(par,t), key_(k), baseText(t) { setDragEnabled(false); updateText(); } void GCUserViewGroupItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int alignment) { QColorGroup xcg = cg; QFont f = p->font(); f.setPointSize(common_smallFontSize); p->setFont(f); xcg.setColor(QColorGroup::Text, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-foreground").value()); if (!PsiOptions::instance()->getOption("options.ui.look.contactlist.use-slim-group-headings").toBool()) { #if QT_VERSION < 0x040301 xcg.setColor(QColorGroup::Background, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value()); #else xcg.setColor(QColorGroup::Base, PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value()); #endif } Q3ListViewItem::paintCell(p, xcg, column, width, alignment); if (PsiOptions::instance()->getOption("options.ui.look.contactlist.use-slim-group-headings").toBool() && !isSelected()) { QFontMetrics fm(p->font()); int x = fm.width(text(column)) + 8; if(x < width - 8) { int h = (height() / 2) - 1; p->setPen(QPen(PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-background").value())); p->drawLine(x, h, width - 8, h); h++; p->setPen(QPen(PsiOptions::instance()->getOption("options.ui.look.colors.contactlist.grouping.header-foreground").value())); p->drawLine(x, h, width - 8, h); } } } void GCUserViewGroupItem::paintFocus(QPainter *, const QColorGroup &, const QRect &) { // re-implimented to do nothing. selection is enough of a focus } void GCUserViewGroupItem::paintBranches(QPainter *p, const QColorGroup &cg, int w, int, int h) { // paint a square of nothing p->fillRect(0, 0, w, h, cg.base()); } int GCUserViewGroupItem::compare(Q3ListViewItem *i, int col, bool ascending) const { Q_UNUSED(ascending); // Qt docs say: "your code can safely ignore it" if (col == 0) // groups are never compared to users, so static_cast is safe return this->key_ - static_cast(i)->key_; else return Q3ListViewItem::compare(i, col, ascending); } void GCUserViewGroupItem::updateText() { int c = childCount(); setText(0, baseText+(c?QString(" (%1)").arg(c):"")); } //---------------------------------------------------------------------------- // GCUserView //---------------------------------------------------------------------------- GCUserView::GCUserView(QWidget* parent) : Q3ListView(parent) , gcDlg_(0) { setResizeMode(Q3ListView::AllColumns); setTreeStepSize(0); setShowToolTips(false); header()->hide(); addColumn(""); setSortColumn(0); Q3ListViewItem* i; i = new GCUserViewGroupItem(this, tr("Visitors"), 3); i->setOpen(true); i = new GCUserViewGroupItem(this, tr("Participants"), 2); i->setOpen(true); i = new GCUserViewGroupItem(this, tr("Moderators"), 1); i->setOpen(true); connect(this, SIGNAL(doubleClicked(Q3ListViewItem *)), SLOT(qlv_doubleClicked(Q3ListViewItem *))); connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem *, const QPoint &, int)), SLOT(qlv_contextMenuRequested(Q3ListViewItem *, const QPoint &, int))); connect(this, SIGNAL(mouseButtonClicked(int, Q3ListViewItem*, const QPoint&, int)), SLOT(qlv_mouseButtonClicked(int, Q3ListViewItem*, const QPoint&, int))); } GCUserView::~GCUserView() { } void GCUserView::setMainDlg(GCMainDlg* mainDlg) { gcDlg_ = mainDlg; } Q3DragObject* GCUserView::dragObject() { Q3ListViewItem* it = currentItem(); if (it) { // WARNING: We are assuming that group items can never be dragged GCUserViewItem* u = (GCUserViewItem*) it; if (!u->s.mucItem().jid().isEmpty()) return new Q3TextDrag(u->s.mucItem().jid().bare(),this); } return NULL; } void GCUserView::clear() { for (Q3ListViewItem *j = firstChild(); j; j = j->nextSibling()) while (GCUserViewItem* i = (GCUserViewItem*) j->firstChild()) { delete i; } } void GCUserView::updateAll() { for (Q3ListViewItem *j = firstChild(); j; j = j->nextSibling()) for(GCUserViewItem *i = (GCUserViewItem *)j->firstChild(); i; i = (GCUserViewItem *)i->nextSibling()) i->setPixmap(0, PsiIconset::instance()->status(i->s).impix()); } QStringList GCUserView::nickList() const { QStringList list; for (Q3ListViewItem *j = firstChild(); j; j = j->nextSibling()) for(Q3ListViewItem *lvi = j->firstChild(); lvi; lvi = lvi->nextSibling()) list << lvi->text(0); qSort(list.begin(), list.end(), caseInsensitiveLessThan); return list; } bool GCUserView::hasJid(const Jid& jid) { for (Q3ListViewItem *j = firstChild(); j; j = j->nextSibling()) for(GCUserViewItem *lvi = (GCUserViewItem*) j->firstChild(); lvi; lvi = (GCUserViewItem*) lvi->nextSibling()) { if(!lvi->s.mucItem().jid().isEmpty() && lvi->s.mucItem().jid().compare(jid,false)) return true; } return false; } Q3ListViewItem *GCUserView::findEntry(const QString &nick) { for (Q3ListViewItem *j = firstChild(); j; j = j->nextSibling()) for(Q3ListViewItem *lvi = j->firstChild(); lvi; lvi = lvi->nextSibling()) { if(lvi->text(0) == nick) return lvi; } return 0; } void GCUserView::updateEntry(const QString &nick, const Status &s) { GCUserViewGroupItem* gr; GCUserViewItem *lvi = (GCUserViewItem *)findEntry(nick); if (lvi && lvi->s.mucItem().role() != s.mucItem().role()) { gr = findGroup(lvi->s.mucItem().role()); delete lvi; gr->updateText(); lvi = NULL; } if(!lvi) { gr = findGroup(s.mucItem().role()); lvi = new GCUserViewItem(gr); lvi->setText(0, nick); gr->updateText(); } lvi->s = s; lvi->setPixmap(0, PsiIconset::instance()->status(lvi->s).impix()); } GCUserViewGroupItem* GCUserView::findGroup(MUCItem::Role a) const { Role r = Visitor; if (a == MUCItem::Moderator) r = Moderator; else if (a == MUCItem::Participant) r = Participant; int i = 0; for (Q3ListViewItem *j = firstChild(); j; j = j->nextSibling()) { if (i == (int) r) return (GCUserViewGroupItem*) j; i++; } return NULL; } void GCUserView::removeEntry(const QString &nick) { GCUserViewItem *lvi = (GCUserViewItem *)findEntry(nick); if(lvi) { GCUserViewGroupItem* gr = findGroup(lvi->s.mucItem().role()); delete lvi; gr->updateText(); } } bool GCUserView::maybeTip(const QPoint &pos) { Q3ListViewItem *qlvi = itemAt(pos); if(!qlvi || !qlvi->parent()) return false; GCUserViewItem *lvi = (GCUserViewItem *) qlvi; QRect r(itemRect(lvi)); const QString &nick = lvi->text(0); const Status &s = lvi->s; UserListItem u; // SICK SICK SICK SICK GCMainDlg* dlg = gcDlg_; if (!dlg) { qDebug("Calling maybetip on an entity without an owning dialog"); return false; } u.setJid(dlg->jid().withResource(nick)); u.setName(nick); // Find out capabilities info Jid caps_jid(s.mucItem().jid().isEmpty() ? dlg->jid().withResource(nick) : s.mucItem().jid()); QString client_name = dlg->account()->capsManager()->clientName(caps_jid); QString client_version = (client_name.isEmpty() ? QString() : dlg->account()->capsManager()->clientVersion(caps_jid)); // make a resource so the contact appears online UserResource ur; ur.setName(nick); ur.setStatus(s); //ur.setClient(client_name,client_version,""); ur.setClient(QString(),QString(),""); u.userResourceList().append(ur); PsiToolTip::showText(mapToGlobal(pos), u.makeTip(), this); return true; } bool GCUserView::event(QEvent* e) { if (e->type() == QEvent::ToolTip) { QPoint pos = ((QHelpEvent*) e)->pos(); e->setAccepted(maybeTip(pos)); return true; } return Q3ListView::event(e); } void GCUserView::qlv_doubleClicked(Q3ListViewItem *i) { if(!i || !i->parent()) return; GCUserViewItem *lvi = (GCUserViewItem *)i; if(PsiOptions::instance()->getOption("options.messages.default-outgoing-message-type").toString() == "message") action(lvi->text(0), lvi->s, 0); else action(lvi->text(0), lvi->s, 1); } void GCUserView::qlv_contextMenuRequested(Q3ListViewItem *i, const QPoint &pos, int) { if(!i || !i->parent() || !gcDlg_) return; QPointer lvi = (GCUserViewItem *)i; bool self = gcDlg_->nick() == i->text(0); GCUserViewItem* c = (GCUserViewItem*) findEntry(gcDlg_->nick()); if (!c) { qWarning() << QString("groupchatdlg.cpp: Self ('%1') not found in contactlist").arg(gcDlg_->nick()); return; } Q3PopupMenu *pm = new Q3PopupMenu; pm->insertItem(IconsetFactory::icon("psi/sendMessage").icon(), tr("Send &Message"), 0); pm->insertItem(IconsetFactory::icon("psi/start-chat").icon(), tr("Open &Chat Window"), 1); pm->insertSeparator(); // Kick and Ban submenus QStringList reasons = PsiOptions::instance()->getOption("options.muc.reasons").toStringList(); int cntReasons=reasons.count(); if (cntReasons>99) cntReasons=99; // Only first 99 reasons Q3PopupMenu *kickMenu = new Q3PopupMenu(pm); kickMenu->insertItem(tr("No reason"),10); kickMenu->insertItem(tr("Custom reason"),100); kickMenu->insertSeparator(); bool canKick=MUCManager::canKick(c->s.mucItem(),lvi->s.mucItem()); for (int i=0; iinsertItem(reasons[i], 101+i); kickMenu->setEnabled(canKick); Q3PopupMenu *banMenu = new Q3PopupMenu(pm); banMenu->insertItem(tr("No reason"),11); banMenu->insertItem(tr("Custom reason"),200); banMenu->insertSeparator(); bool canBan=MUCManager::canBan(c->s.mucItem(),lvi->s.mucItem()); for (int i=0; iinsertItem(reasons[i], 201+i); banMenu->setEnabled(canBan); pm->insertItem(tr("&Kick"), kickMenu); pm->setItemEnabled(10, canKick); pm->insertItem(tr("&Ban"), banMenu); pm->setItemEnabled(11, canBan); Q3PopupMenu* rm = new Q3PopupMenu(pm); rm->insertItem(tr("Visitor"),12); rm->setItemChecked(12, lvi->s.mucItem().role() == MUCItem::Visitor); rm->setItemEnabled(12, (!self || lvi->s.mucItem().role() == MUCItem::Visitor) && MUCManager::canSetRole(c->s.mucItem(),lvi->s.mucItem(),MUCItem::Visitor)); rm->insertItem(tr("Participant"),13); rm->setItemChecked(13, lvi->s.mucItem().role() == MUCItem::Participant); rm->setItemEnabled(13, (!self || lvi->s.mucItem().role() == MUCItem::Participant) && MUCManager::canSetRole(c->s.mucItem(),lvi->s.mucItem(),MUCItem::Participant)); rm->insertItem(tr("Moderator"),14); rm->setItemChecked(14, lvi->s.mucItem().role() == MUCItem::Moderator); rm->setItemEnabled(14, (!self || lvi->s.mucItem().role() == MUCItem::Moderator) && MUCManager::canSetRole(c->s.mucItem(),lvi->s.mucItem(),MUCItem::Moderator)); pm->insertItem(tr("Change Role"),rm); /*Q3PopupMenu* am = new Q3PopupMenu(pm); am->insertItem(tr("Unaffiliated"),15); am->setItemChecked(15, lvi->s.mucItem().affiliation() == MUCItem::NoAffiliation); am->setItemEnabled(15, (!self || lvi->s.mucItem().affiliation() == MUCItem::NoAffiliation) && MUCManager::canSetAffiliation(c->s.mucItem(),lvi->s.mucItem(),MUCItem::NoAffiliation)); am->insertItem(tr("Member"),16); am->setItemChecked(16, lvi->s.mucItem().affiliation() == MUCItem::Member); am->setItemEnabled(16, (!self || lvi->s.mucItem().affiliation() == MUCItem::Member) && MUCManager::canSetAffiliation(c->s.mucItem(),lvi->s.mucItem(),MUCItem::Member)); am->insertItem(tr("Administrator"),17); am->setItemChecked(17, lvi->s.mucItem().affiliation() == MUCItem::Admin); am->setItemEnabled(17, (!self || lvi->s.mucItem().affiliation() == MUCItem::Admin) && MUCManager::canSetAffiliation(c->s.mucItem(),lvi->s.mucItem(),MUCItem::Admin)); am->insertItem(tr("Owner"),18); am->setItemChecked(18, lvi->s.mucItem().affiliation() == MUCItem::Owner); am->setItemEnabled(18, (!self || lvi->s.mucItem().affiliation() == MUCItem::Owner) && MUCManager::canSetAffiliation(c->s.mucItem(),lvi->s.mucItem(),MUCItem::Owner)); pm->insertItem(tr("Change Affiliation"),am);*/ pm->insertSeparator(); //pm->insertItem(tr("Send &File"), 4); //pm->insertSeparator(); pm->insertItem(tr("Check &Status"), 2); pm->insertItem(IconsetFactory::icon("psi/vCard").icon(), tr("User &Info"), 3); int x = pm->exec(pos); bool enabled = pm->isItemEnabled(x) || rm->isItemEnabled(x) || kickMenu->isItemEnabled(x) || banMenu->isItemEnabled(x); delete pm; if(x == -1 || !enabled || lvi.isNull()) return; action(lvi->text(0), lvi->s, x); } void GCUserView::qlv_mouseButtonClicked(int button, Q3ListViewItem* item, const QPoint& pos, int c) { Q_UNUSED(pos); Q_UNUSED(c); if (!item || !item->parent() || !gcDlg_) return; if (button != Qt::MidButton) return; emit insertNick(item->text(0)); } psi-0.14/src/contactview.h0000644000175000017500000002713611305557613013640 0ustar janjan/* * contactview.h - contact list widget * Copyright (C) 2001, 2002 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CONTACTVIEW_H #define CONTACTVIEW_H #include #include #include #include #include #include #include #include "xmpp_clientstream.h" class IconAction; class UserListItem; class ContactView; class ContactViewItem; class PsiAccount; class PsiIcon; class QTimer; class QPixmap; namespace XMPP { class Status; } using namespace XMPP; class ContactProfile; // ContactProfile: this holds/manipulates a roster profile for an account class ContactProfile : public QObject { Q_OBJECT public: ContactProfile(PsiAccount *, const QString &name, ContactView *, bool unique=false); ~ContactProfile(); void setEnabled(bool e=TRUE); const QString & name() const; void setName(const QString &name); void setState(int); void setUsingSSL(bool); ContactView *contactView() const; ContactViewItem *self() const; PsiAccount *psiAccount() const; void updateEntry(const UserListItem &); void removeEntry(const Jid &); void updateSelf(); void addSelf(); void removeSelf(); void setAlert(const Jid &, const PsiIcon *); void clearAlert(const Jid &); void animateNick(const Jid &); void addAllNeededContactItems(); void removeAllUnneededContactItems(); void resetAllContactItemNames(); void ensureVisible(const Jid &); void clear(); QString makeTip(bool trim, bool doLinkify) const; ContactViewItem *checkGroup(int type); ContactViewItem *checkGroup(const QString &name); void setName(const char *); signals: void actionDefault(const Jid &); void actionRecvEvent(const Jid &); void actionSendMessage(const Jid &); void actionSendMessage(const QList&); void actionSendUrl(const Jid &); void actionRemove(const Jid &); void actionRename(const Jid &, const QString &); void actionGroupRename(const QString &, const QString &); void actionHistory(const Jid &); void actionOpenChat(const Jid &); void actionOpenChatSpecific(const Jid &); #ifdef WHITEBOARDING void actionOpenWhiteboard(const Jid &); void actionOpenWhiteboardSpecific(const Jid &); #endif void actionAgentSetStatus(const Jid &, Status &); void actionInfo(const Jid &); void actionAuth(const Jid &); void actionAuthRequest(const Jid &); void actionAuthRemove(const Jid &); void actionAdd(const Jid &); void actionGroupAdd(const Jid &, const QString &); void actionGroupRemove(const Jid &, const QString &); void actionSendFile(const Jid &); void actionSendFiles(const Jid &, const QStringList &); void actionVoice(const Jid &); void actionExecuteCommand(const Jid &, const QString&); void actionExecuteCommandSpecific(const Jid &, const QString&); void actionDisco(const Jid &, const QString &); void actionInvite(const Jid &, const QString &); void actionAssignKey(const Jid &); void actionUnassignKey(const Jid &); void actionSetMood(); void actionSetAvatar(); void actionUnsetAvatar(); private slots: void updateGroups(); public: class Entry; class Private; private: Private *d; ContactViewItem *addGroup(int type); ContactViewItem *addGroup(const QString &name); ContactViewItem *ensureGroup(int type); ContactViewItem *ensureGroup(const QString &name); void checkDestroyGroup(ContactViewItem *group); void checkDestroyGroup(const QString &group); ContactViewItem *addContactItem(Entry *e, ContactViewItem *group_item); ContactViewItem *ensureContactItem(Entry *e, ContactViewItem *group_item); void removeContactItem(Entry *e, ContactViewItem *i); void addNeededContactItems(Entry *e); void removeUnneededContactItems(Entry *e); void clearContactItems(Entry *e); void removeEntry(Entry *); Entry *findEntry(const Jid &) const; Entry *findEntry(ContactViewItem *) const; void ensureVisible(Entry *); // useful functions to grab groups of users QList contactListFromCVGroup(ContactViewItem *) const; int contactSizeFromCVGroup(ContactViewItem *) const; int contactsOnlineFromCVGroup(ContactViewItem *) const; QList contactListFromGroup(const QString &groupName) const; int contactSizeFromGroup(const QString &groupName) const; void updateGroupInfo(ContactViewItem *group); QStringList groupList() const; void deferredUpdateGroups(); friend class ContactView; void scActionDefault(ContactViewItem *); void scRecvEvent(ContactViewItem *); void scSendMessage(ContactViewItem *); void scRename(ContactViewItem *); void scVCard(ContactViewItem *); void scHistory(ContactViewItem *); void scOpenChat(ContactViewItem *); #ifdef WHITEBOARDING void scOpenWhiteboard(ContactViewItem *); #endif void scAgentSetStatus(ContactViewItem *, Status &); void scRemove(ContactViewItem *); void doItemRenamed(ContactViewItem *, const QString &); void doContextMenu(ContactViewItem *, const QPoint &); friend class ContactViewItem; void dragDrop(const QString &, ContactViewItem *); void dragDropFiles(const QStringList &, ContactViewItem *); }; // ContactView: the actual widget class ContactView : public Q3ListView { Q_OBJECT public: ContactView(QWidget *parent=0, const char *name=0); ~ContactView(); bool isShowOffline() const { return v_showOffline; } bool isShowAgents() const { return v_showAgents; } bool isShowAway() const { return v_showAway; } bool isShowHidden() const { return v_showHidden; } bool isShowSelf() const { return v_showSelf; } bool isShowStatusMsg() const { return v_showStatusMsg; } bool filterContact(ContactViewItem *item, bool refineSearch = false); bool filterGroup(ContactViewItem *item, bool refineSearch = false); void setFilter(QString const &text); void clearFilter(); bool isApplyingFilter() const { return applyingFilter; } void clear(); void resetAnim(); QTimer *animTimer() const; IconAction *qa_send, *qa_chat, *qa_ren, *qa_hist, *qa_logon, *qa_recv, *qa_rem, *qa_vcard; IconAction *qa_assignAvatar, *qa_clearAvatar; #ifdef WHITEBOARDING IconAction *qa_wb; #endif QSize minimumSizeHint() const; QSize sizeHint() const; protected: void setShortcuts(); // reimplemented void keyPressEvent(QKeyEvent *); bool eventFilter( QObject *, QEvent * ); Q3DragObject *dragObject(); signals: void showOffline(bool); void showAway(bool); void showHidden(bool); void showAgents(bool); void showSelf(bool); void showStatusMsg(bool); void searchInput(const QString&); public slots: void setShowOffline(bool); void setShowAgents(bool); void setShowAway(bool); void setShowHidden(bool); void setShowSelf(bool); void setShowStatusMsg(bool); void optionsUpdate(); void recalculateSize(); private slots: void qlv_singleclick(int, Q3ListViewItem *, const QPoint &, int); void qlv_doubleclick(Q3ListViewItem *); void qlv_contextPopup(Q3ListViewItem *, const QPoint &, int); void qlv_contextMenuRequested(Q3ListViewItem *, const QPoint &, int); void qlv_itemRenamed(Q3ListViewItem *, int, const QString &); void leftClickTimeOut(); void doRecvEvent(); void doRename(); void doEnter(); void doContext(); void doSendMessage(); void doOpenChat(); #ifdef WHITEBOARDING void doOpenWhiteboard(); #endif void doHistory(); void doVCard(); void doLogon(); void doRemove(); void doAssignAvatar(); void doClearAvatar(); public: class Private; friend class Private; private: Private *d; QPoint mousePressPos; // store pressed position, idea taken from Licq bool v_showOffline, v_showAgents, v_showAway, v_showHidden, v_showSelf, v_showStatusMsg; bool lcto_active; // double click active? QPoint lcto_pos; Q3ListViewItem *lcto_item; QSize lastSize; QString filterString_; bool applyingFilter; friend class ContactProfile; void link(ContactProfile *); void unlink(ContactProfile *); bool allowResize() const; }; //------------------------------------------------------------------------------ // RichListViewItem: A RichText listview item //------------------------------------------------------------------------------ #include class RichListViewStyleSheet : public Q3StyleSheet { public: static RichListViewStyleSheet* instance(); virtual void scaleFont(QFont& font, int logicalSize) const; private: RichListViewStyleSheet(QObject* parent=0, const char * name=0); static RichListViewStyleSheet* instance_; }; class Q3SimpleRichText; class RichListViewItem : public Q3ListViewItem { public: RichListViewItem( Q3ListView * parent ); RichListViewItem( Q3ListViewItem * parent ); virtual void setText(int column, const QString& text); virtual void setup(); virtual ~RichListViewItem(); int widthUsed(); protected: virtual void paintCell( QPainter * p, const QColorGroup & cg, int column , int width, int align ); private: int v_widthUsed; bool v_selected, v_active; bool v_rich; Q3SimpleRichText* v_rt; }; // ContactViewItem: an entry in the ContactView (profile, group, or contact) class ContactViewItem : public QObject, public RichListViewItem { Q_OBJECT public: enum { Profile, Group, Contact }; enum { gGeneral, gNotInList, gAgents, gPrivate, gUser }; ContactViewItem(const QString &profileName, ContactProfile *, ContactView *parent); ContactViewItem(const QString &groupName, int groupType, ContactProfile *, ContactView *parent); ContactViewItem(const QString &groupName, int groupType, ContactProfile *, ContactViewItem *parent); ContactViewItem(UserListItem *, ContactProfile *, ContactViewItem *parent); ~ContactViewItem(); ContactProfile *contactProfile() const; int type() const; int groupType() const; const QString & groupName() const; const QString & groupInfo() const; UserListItem *u() const; int status() const; bool isAgent() const; bool isAlerting() const; bool isAnimatingNick() const; int parentGroupType() const; // use with contacts: returns grouptype of parent group void setContact(UserListItem *); void setProfileName(const QString &); void setProfileState(int); void setProfileSSL(bool); void setGroupName(const QString &); void setGroupInfo(const QString &); void setAnimateNick(); void setAlert(const PsiIcon *); void clearAlert(); void setIcon(const PsiIcon *, bool alert = false); void resetStatus(); void resetName(bool forceNoStatusMsg = false); // use this to cancel a rename void resetGroupName(); void updatePosition(); void optionsUpdate(); void clearFilter(); // reimplemented functions int rtti() const; void paintFocus(QPainter *, const QColorGroup &, const QRect &); void paintBranches(QPainter *, const QColorGroup &, int, int, int); void paintCell(QPainter *, const QColorGroup & cg, int column, int width, int alignment); void setOpen(bool o); void insertItem(Q3ListViewItem * newChild); void takeItem(Q3ListViewItem * item); int compare(Q3ListViewItem *, int, bool) const; bool acceptDrop(const QMimeSource *) const; public slots: void resetAnim(); void iconUpdated(); void animateNick(); void stopAnimateNick(); protected: void dragEntered(); void dragLeft(); void dropped(QDropEvent *); void cancelRename(int); private: int type_; class Private; Private *d; void cacheValues(); int rankGroup(int groupType) const; void drawGroupIcon(); }; #endif psi-0.14/src/pluginhost.h0000644000175000017500000000506111305557613013477 0ustar janjan/* * (c) 2006 Kevin Smith * (c) 2008 Maciej Niedzielski */ #ifndef PLUGINHOST_H #define PLUGINHOST_H #include #include #include #include #include "stanzasendinghost.h" #include "iqfilteringhost.h" #include "optionaccessinghost.h" class QWidget; class QPluginLoader; class PluginManager; class IqNamespaceFilter; class PluginHost: public QObject, public StanzaSendingHost, public IqFilteringHost, public OptionAccessingHost { Q_OBJECT; Q_INTERFACES(StanzaSendingHost IqFilteringHost OptionAccessingHost); public: PluginHost(PluginManager* manager, const QString& pluginFile); virtual ~PluginHost(); bool isValid() const; const QString& path() const; QWidget* optionsWidget() const; // cached basic info const QString& name() const; const QString& shortName() const; const QString& version() const; // loading bool load(); bool unload(); bool isLoaded() const; // enabling bool enable(); bool disable(); bool isEnabled() const; // for StanzaFilter and IqNamespaceFilter bool incomingXml(int account, const QDomElement& e); // for EventFilter bool processEvent(int account, const QDomElement& e); bool processMessage(int account, const QString& jidFrom, const QString& body, const QString& subject); // StanzaSendingHost void sendStanza(int account, const QDomElement& xml); void sendStanza(int account, const QString& xml); void sendMessage(int account, const QString& to, const QString& body, const QString& subject, const QString& type); QString uniqueId(int account); // IqFilteringHost void addIqNamespaceFilter(const QString& ns, IqNamespaceFilter* filter); void addIqNamespaceFilter(const QRegExp& ns, IqNamespaceFilter* filter); void removeIqNamespaceFilter(const QString& ns, IqNamespaceFilter* filter); void removeIqNamespaceFilter(const QRegExp& ns, IqNamespaceFilter* filter); // OptionAccessingHost void setPluginOption(const QString& option, const QVariant& value); QVariant getPluginOption(const QString& option); void setGlobalOption(const QString& option, const QVariant& value); QVariant getGlobalOption(const QString& option); private: PluginManager* manager_; QObject* plugin_; QString file_; QString name_; QString shortName_; QString version_; QPluginLoader* loader_; bool valid_; bool connected_; bool enabled_; QMultiMap iqNsFilters_; QMultiMap iqNsxFilters_; bool loadPlugin(QObject* pluginObject); // disable copying PluginHost(const PluginHost&); PluginHost& operator=(const PluginHost&); }; #endif psi-0.14/src/statuspreset.h0000644000175000017500000000335011305557613014050 0ustar janjan/* * statuspreset.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef STATUSPRESET_H #define STATUSPRESET_H #include #include "utilities/maybe.h" #include "xmpp_status.h" #include "optionstree.h" class QDomDocument; class QDomElement; class StatusPreset { public: StatusPreset(); StatusPreset(QString name, QString message = QString::null, XMPP::Status::Type status = XMPP::Status::Away); StatusPreset(QString name, int priority, QString message = QString::null, XMPP::Status::Type status = XMPP::Status::Away); StatusPreset(const QDomElement&); QString name() const; void setName(const QString&); QString message() const; void setMessage(const QString&); XMPP::Status::Type status() const; void setStatus(XMPP::Status::Type); Maybe priority() const; void setPriority(int priority); void clearPriority(); void toOptions(OptionsTree *o); QDomElement toXml(QDomDocument&) const; void fromXml(const QDomElement&); private: QString name_, message_; XMPP::Status::Type status_; Maybe priority_; }; #endif psi-0.14/src/mucconfigdlg.h0000644000175000017500000000447311305557613013752 0ustar janjan/* * mucconfigdlg.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MUCCONFIG_H #define MUCCONFIG_H #include #include "ui_mucconfig.h" #include "xmpp_muc.h" class QScrollArea; class XDataWidget; class MUCManager; class MUCAffiliationsModel; class MUCAffiliationsProxyModel; namespace XMPP { class XData; } using namespace XMPP; class MUCConfigDlg : public QDialog { Q_OBJECT public: MUCConfigDlg(MUCManager*, QWidget*); ~MUCConfigDlg(); void setRoleAffiliation(MUCItem::Role, MUCItem::Affiliation); protected: void setRole(MUCItem::Role); void setAffiliation(MUCItem::Affiliation); void refreshGeneral(); void refreshAffiliations(); void removePendingRequest(MUCItem::Affiliation); protected slots: void add(); void apply(); void destroy(); void currentTabChanged(int); void applyFilter(const QString&); void getConfiguration_success( const XData&); void getConfiguration_error(int, const QString&); void setConfiguration_success(); void setConfiguration_error(int, const QString&); void setItems_success(); void setItems_error(int, const QString&); void getItemsByAffiliation_success(MUCItem::Affiliation, const QList&); void getItemsByAffiliation_error(MUCItem::Affiliation, int, const QString&); void destroy_success(); void destroy_error(int, const QString&); private: Ui::MUCConfig ui_; MUCItem::Role role_; MUCItem::Affiliation affiliation_; MUCManager* manager_; QScrollArea* data_container_; XDataWidget* data_; MUCAffiliationsModel* affiliations_model_; MUCAffiliationsProxyModel* affiliations_proxy_model_; QList pending_requests_; }; #endif psi-0.14/src/physicallocation.h0000644000175000017500000000376011305557613014654 0ustar janjan/* * physicallocation.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PHYSICALOCATION_H #define PHYSICALOCATION_H #include class QDomElement; class QDomDocument; class PhysicalLocation { public: PhysicalLocation(); PhysicalLocation(const QDomElement&); const QString& country() const; const QString& region() const; const QString& locality() const; const QString& area() const; const QString& street() const; const QString& building() const; const QString& floor() const; const QString& room() const; const QString& postalcode() const; const QString& text() const; bool isNull() const; void setCountry(const QString& s); void setRegion(const QString& s); void setLocality(const QString& s); void setArea(const QString& s); void setStreet(const QString& s); void setBuilding(const QString& s); void setFloor(const QString& s); void setRoom(const QString& s); void setPostalcode(const QString& s); void setText(const QString& s); QString toString() const; QDomElement toXml(QDomDocument&); bool operator==(const PhysicalLocation&) const; bool operator!=(const PhysicalLocation&) const; protected: void fromXml(const QDomElement&); private: QString country_, region_, locality_, area_, street_, building_, floor_, room_, postalcode_, text_; }; #endif psi-0.14/src/xmlconsole.cpp0000644000175000017500000001374411305557613014030 0ustar janjan/* * xmlconsole.cpp - dialog for interacting manually with Jabber * Copyright (C) 2001, 2002 Justin Karneges, Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include "xmpp_client.h" #include "xmlconsole.h" #include "psiaccount.h" #include "psicon.h" #include "psicontactlist.h" //---------------------------------------------------------------------------- // XmlConsole //---------------------------------------------------------------------------- XmlConsole::XmlConsole(PsiAccount *_pa) :QWidget() { ui_.setupUi(this); pa = _pa; pa->dialogRegister(this); connect(pa, SIGNAL(updatedAccount()), SLOT(updateCaption())); connect(pa->client(), SIGNAL(xmlIncoming(const QString &)), SLOT(client_xmlIncoming(const QString &))); connect(pa->client(), SIGNAL(xmlOutgoing(const QString &)), SLOT(client_xmlOutgoing(const QString &))); connect(pa->psi(), SIGNAL(accountCountChanged()), this, SLOT(updateCaption())); updateCaption(); prompt = 0; ui_.te->setUndoRedoEnabled(false); ui_.te->setReadOnly(true); ui_.te->setAcceptRichText(false); QTextFrameFormat f = ui_.te->document()->rootFrame()->frameFormat(); f.setBackground(QBrush(Qt::black)); ui_.te->document()->rootFrame()->setFrameFormat(f); connect(ui_.pb_clear, SIGNAL(clicked()), SLOT(clear())); connect(ui_.pb_input, SIGNAL(clicked()), SLOT(insertXml())); connect(ui_.pb_close, SIGNAL(clicked()), SLOT(close())); connect(ui_.pb_dumpRingbuf, SIGNAL(clicked()), SLOT(dumpRingbuf())); connect(ui_.ck_enable, SIGNAL(clicked(bool)), ui_.gb_filter, SLOT(setEnabled(bool))); resize(560,400); } XmlConsole::~XmlConsole() { pa->dialogUnregister(this); } void XmlConsole::clear() { ui_.te->clear(); QTextFrameFormat f = ui_.te->document()->rootFrame()->frameFormat(); f.setBackground(QBrush(Qt::black)); ui_.te->document()->rootFrame()->setFrameFormat(f); } void XmlConsole::updateCaption() { if (pa->psi()->contactList()->enabledAccounts().count() > 1) setWindowTitle(pa->name() + ": " + tr("XML Console")); else setWindowTitle(tr("XML Console")); } void XmlConsole::enable() { ui_.ck_enable->setChecked(true); } bool XmlConsole::filtered(const QString& str) const { if(ui_.ck_enable->isChecked()) { // Only do parsing if needed if (!ui_.le_jid->text().isEmpty() || !ui_.ck_iq->isChecked() || !ui_.ck_message->isChecked() || !ui_.ck_presence->isChecked()) { QDomDocument doc; if (!doc.setContent(str)) return true; QDomElement e = doc.documentElement(); if ((e.tagName() == "iq" && !ui_.ck_iq->isChecked()) || (e.tagName() == "message" && !ui_.ck_message->isChecked()) || ((e.tagName() == "presence" && !ui_.ck_presence->isChecked()))) return true; if (!ui_.le_jid->text().isEmpty()) { Jid jid(ui_.le_jid->text()); bool hasResource = !jid.resource().isEmpty(); if (!jid.compare(e.attribute("to"),hasResource) && !jid.compare(e.attribute("from"),hasResource)) return true; } } return false; } return true; } void XmlConsole::dumpRingbuf() { QList buf = pa->dumpRingbuf(); bool enablesave = ui_.ck_enable->isChecked(); ui_.ck_enable->setChecked(true); QString stamp; foreach (PsiAccount::xmlRingElem el, buf) { stamp = ""; if (el.type == PsiAccount::RingXmlOut) { client_xmlOutgoing(stamp + el.xml); } else { client_xmlIncoming(stamp + el.xml); } } ui_.ck_enable->setChecked(enablesave); } void XmlConsole::client_xmlIncoming(const QString &str) { if (!filtered(str)) { ui_.te->setTextColor(Qt::yellow); ui_.te->append(str + '\n'); } } void XmlConsole::client_xmlOutgoing(const QString &str) { if(!filtered(str)) { ui_.te->setTextColor(Qt::red); ui_.te->append(str + '\n'); } } void XmlConsole::insertXml() { if(prompt) bringToFront(prompt); else { prompt = new XmlPrompt(this); connect(prompt, SIGNAL(textReady(const QString &)), SLOT(xml_textReady(const QString &))); prompt->show(); } } void XmlConsole::xml_textReady(const QString &str) { pa->client()->send(str); } //---------------------------------------------------------------------------- // XmlPrompt //---------------------------------------------------------------------------- XmlPrompt::XmlPrompt(QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(tr("XML Input")); QVBoxLayout *vb1 = new QVBoxLayout(this); vb1->setMargin(8); te = new QTextEdit(this); te->setAcceptRichText(false); vb1->addWidget(te); QHBoxLayout *hb1 = new QHBoxLayout; vb1->addLayout(hb1); QPushButton *pb; pb = new QPushButton(tr("&Transmit"), this); pb->setDefault(true); connect(pb, SIGNAL(clicked()), SLOT(doTransmit())); hb1->addWidget(pb); hb1->addStretch(1); pb = new QPushButton(tr("&Close"), this); connect(pb, SIGNAL(clicked()), SLOT(close())); hb1->addWidget(pb); resize(320,240); } XmlPrompt::~XmlPrompt() { } void XmlPrompt::doTransmit() { QString str = te->toPlainText(); // Validate input QDomDocument doc; if (!doc.setContent(str)) { int i = QMessageBox::warning(this, tr("Malformed XML"), tr("You have entered malformed XML input. Are you sure you want to send this ?"), tr("Yes"), tr("No")); if (i != 0) return; } textReady(str); close(); } psi-0.14/src/pepmanager.h0000644000175000017500000000526511305557613013430 0ustar janjan/* * pepmanager.h - Classes for PEP * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PEPMANAGER_H #define PEPMANAGER_H #include namespace XMPP { class Client; class Jid; class Message; class PubSubItem; class PubSubRetraction; } class PubSubSubscription; class QString; class ServerInfoManager; using namespace XMPP; class PEPManager : public QObject { Q_OBJECT public: enum Access { DefaultAccess, PresenceAccess, PublicAccess }; PEPManager(XMPP::Client* client, ServerInfoManager* serverInfo); //void registerNode(const QString&); //void registerNodes(const QStringList&); //bool canPublish(const QString&) const; //void subscribe(const QString&, const QString&); //void unsubscribe(const QString&, const QString&); void publish(const QString& node, const PubSubItem&, Access = DefaultAccess); void retract(const QString& node, const QString& id); void get(const Jid& jid, const QString& node, const QString& id); //void getSubscriptions(const Jid& jid); signals: void publish_success(const QString&, const PubSubItem&); void publish_error(const QString&, const PubSubItem&); void itemPublished(const Jid& jid, const QString& node, const PubSubItem&); void itemRetracted(const Jid& jid, const QString& node, const PubSubRetraction&); //void ready(const QString& node); //void getSubscriptions_success(const Jid& jid, const QList& subscriptions); //void getSubscriptions_error(const Jid&, int, const QString&); //void available(bool); protected slots: void messageReceived(const Message&); void getFinished(); //void serverFeaturesChanged(); //void getSelfSubscriptionsTaskFinished(); //void getSubscriptionsTaskFinished(); void publishFinished(); //void subscribeFinished(); //void unsubscribeFinished(); //void createFinished(); protected: //void createNode(const QString& node); //void saveSubscriptions(); private: XMPP::Client* client_; ServerInfoManager* serverInfo_; //QStringList nodes_, ensured_nodes_; }; #endif psi-0.14/src/tasklist.h0000644000175000017500000000401111305557613013133 0ustar janjan/**************************************************************************** ** tasklist.h - A small, but useful Task List ** Copyright (C) 2003 Michail Pishchagin ** ** 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 2 ** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA. ** ****************************************************************************/ #ifndef TASKLIST_H #define TASKLIST_H #include #include "xmpp_task.h" using namespace XMPP; //---------------------------------------------------------------------------- // TaskList -- read some comments inline //---------------------------------------------------------------------------- class TaskList : public QObject, public QList { Q_OBJECT public: TaskList() { } ~TaskList() { qDeleteAll(*this); } void append(Task *d) { if ( isEmpty() ) emit started(); connect(d, SIGNAL(destroyed(QObject *)), SLOT(taskDestroyed(QObject *))); QList::append(d); } signals: // started() is emitted, when TaskList doesn't have any tasks in it, // and append() is called, indicating, that TaskList contains at least one // running Task void started(); // finished() is emitted when TaskList contains one Task, and it suddenly // terminates, indicating, that TaskList is empty now void finished(); private slots: void taskDestroyed(QObject *p) { removeAll(static_cast(p)); if ( isEmpty() ) emit finished(); } }; #endif psi-0.14/src/tabcompletion.h0000644000175000017500000000356511305557613014152 0ustar janjan/* * Copyright (C) 2001-2008 Justin Karneges, Martin Hostettler * * 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 2 * 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, see . * */ // Generic tab completion support code. #ifndef TABCOMPLETION_H #define TABCOMPLETION_H #include #include "msgmle.h" class TabCompletion : public QObject { Q_OBJECT public: TabCompletion(QObject *parent = 0); ~TabCompletion(); void setTextEdit(QTextEdit* mle); QTextEdit* getTextEdit(); virtual void reset(); void tryComplete(); protected: QString toComplete_; bool atStart_; virtual void setup(QString str, int pos, int &start, int &end); virtual QStringList possibleCompletions()=0; virtual QStringList allChoices(QString &guess)=0; virtual void highlight(bool set); QColor highlight_; private: QString longestCommonPrefix(QStringList list); QString suggestCompletion(bool *replaced); void moveCursorToOffset(QTextCursor &cur, int offset, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor); enum TypingStatus { Typing_Normal, Typing_TabPressed, // initial completion Typing_TabbingCompletions, // switch to tab through multiple Typing_MultipleSuggestions }; QTextCursor replacementCursor_; TypingStatus typingStatus_; QStringList suggestedCompletion_; int suggestedIndex_; QTextEdit* textEdit_; }; #endif psi-0.14/src/resourcemenu.h0000644000175000017500000000217111305557613014016 0ustar janjan/* * resourcemenu.h - helper class for displaying contact's resources * Copyright (C) 2006 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef RESOURCEMENU_H #define RESOURCEMENU_H #include class UserResource; class ResourceMenu : public QMenu { Q_OBJECT public: ResourceMenu(QWidget *parent); void addResource(const UserResource &r, int id); void addResource(int status, QString name, int id); }; #endif /* RESOURCEMENU_H */ psi-0.14/src/googleftmanager.h0000644000175000017500000000703711305557613014451 0ustar janjan/* * googleftmanager.h * Copyright (C) 2007 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GOOGLEFTMANAGER_H #define GOOGLEFTMANAGER_H #include "talk/base/scoped_ptr.h" #include "filetransfer.h" #include #include namespace cricket { class HttpPortAllocator; class SessionManager; class FileShareSessionClient; class FileShareSession; } namespace talk_base { class NetworkManager; class PhysicalSocketServer; class Thread; } namespace XMPP { class Jid; class Client; } class GoogleSessionListener; class GoogleFileTransferListener; class GoogleFTManager; class GoogleFileTransfer : public QObject/*: public XMPP::AbstractFileTransfer*/ { Q_OBJECT friend class GoogleFileTransferListener; public: GoogleFileTransfer(cricket::FileShareSession*, GoogleFTManager* manager); virtual ~GoogleFileTransfer() {}; virtual XMPP::Jid peer() const; virtual QString fileName() const; virtual qlonglong fileSize() const; virtual QString description() const; virtual void accept(qlonglong offset=0, qlonglong length=0); virtual void reject(); virtual void cancel(); signals: void progressChanged(qlonglong, const QString&); private: cricket::FileShareSession* session_; GoogleFTManager* manager_; GoogleFileTransferListener* listener_; }; class GoogleFTManager : public QObject { Q_OBJECT friend class GoogleSessionListener; friend class GoogleFileTransferListener; public: GoogleFTManager(XMPP::Client* client); ~GoogleFTManager(); signals: void incomingFileTransfer(GoogleFileTransfer*); protected: void sendStanza(const QString&); protected slots: void receiveStanza(const QString&); virtual void initialize(); virtual void deinitialize(); private: bool initialized_; XMPP::Client* client_; GoogleSessionListener* listener_; static talk_base::PhysicalSocketServer *socket_server_; static talk_base::Thread *thread_; static talk_base::NetworkManager* network_manager_; static talk_base::scoped_ptr port_allocator_; talk_base::scoped_ptr session_manager_; talk_base::scoped_ptr file_share_session_client_; }; #include class GoogleFileTransferProgressDialog : public QProgressDialog { Q_OBJECT public: GoogleFileTransferProgressDialog(GoogleFileTransfer* ft) : QProgressDialog(NULL,Qt::WDestructiveClose), ft_(ft) { connect(ft,SIGNAL(progressChanged(qlonglong, const QString&)),SLOT(update(qlonglong, const QString&))); connect(this,SIGNAL(canceled()),SLOT(cancel())); setLabelText("Initializing"); setRange(0,(int) ft->fileSize()); } public slots: void cancel() { ft_->cancel(); QProgressDialog::cancel(); } protected slots: void update(qlonglong progress, const QString& name) { setLabelText(QString(tr("Transferring %1")).arg(name)); setValue(progress); } private: GoogleFileTransfer* ft_; }; #endif psi-0.14/src/mucconfigdlg.cpp0000644000175000017500000002357211305557613014306 0ustar janjan/* * mucconfigdlg.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include "mucmanager.h" #include "mucaffiliationsmodel.h" #include "mucaffiliationsproxymodel.h" #include "mucconfigdlg.h" #include "xdata_widget.h" using namespace XMPP; MUCConfigDlg::MUCConfigDlg(MUCManager* manager, QWidget* parent) : QDialog(parent), manager_(manager) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); setModal(false); QVBoxLayout *data_layout = new QVBoxLayout(ui_.pg_general_data); data_layout->setMargin(0); data_container_ = new QScrollArea(ui_.pg_general_data); data_layout->addWidget(data_container_); data_container_->setWidgetResizable(true); connect(ui_.tabs,SIGNAL(currentChanged(int)),SLOT(currentTabChanged(int))); connect(ui_.pb_apply,SIGNAL(clicked()),SLOT(apply())); ui_.pb_close->setDefault(true); // General tab data_ = NULL; connect(manager_, SIGNAL(getConfiguration_success(const XData&)), SLOT(getConfiguration_success(const XData&))); connect(manager_, SIGNAL(getConfiguration_error(int, const QString&)), SLOT(getConfiguration_error(int, const QString&))); connect(manager_, SIGNAL(setConfiguration_success()), SLOT(setConfiguration_success())); connect(manager_, SIGNAL(setConfiguration_error(int, const QString&)), SLOT(setConfiguration_error(int, const QString&))); connect(manager_, SIGNAL(getItemsByAffiliation_success(MUCItem::Affiliation, const QList&)), SLOT(getItemsByAffiliation_success(MUCItem::Affiliation, const QList&))); connect(manager_, SIGNAL(setItems_success()), SLOT(setItems_success())); connect(manager_, SIGNAL(setItems_error(int, const QString&)), SLOT(setItems_error(int, const QString&))); connect(manager_, SIGNAL(getItemsByAffiliation_error(MUCItem::Affiliation, int, const QString&)), SLOT(getItemsByAffiliation_error(MUCItem::Affiliation, int, const QString&))); connect(manager_, SIGNAL(destroy_success()), SLOT(destroy_success())); connect(manager_, SIGNAL(destroy_error(int, const QString&)), SLOT(destroy_error(int, const QString&))); connect(ui_.pb_destroy, SIGNAL(clicked()), SLOT(destroy())); // Affiliations tab ui_.pb_add->setEnabled(false); ui_.pb_remove->setEnabled(false); connect(ui_.tv_affiliations,SIGNAL(addEnabled(bool)),ui_.pb_add,SLOT(setEnabled(bool))); connect(ui_.tv_affiliations,SIGNAL(removeEnabled(bool)),ui_.pb_remove,SLOT(setEnabled(bool))); connect(ui_.pb_add,SIGNAL(clicked()),SLOT(add())); connect(ui_.pb_remove,SIGNAL(clicked()),ui_.tv_affiliations,SLOT(removeCurrent())); connect(ui_.le_filter, SIGNAL(textChanged(const QString&)), SLOT(applyFilter(const QString&))); affiliations_model_ = new MUCAffiliationsModel(); affiliations_proxy_model_ = new MUCAffiliationsProxyModel(affiliations_model_); affiliations_proxy_model_->setSourceModel(affiliations_model_); ui_.tv_affiliations->setModel(affiliations_proxy_model_); for (int i = 0; i < affiliations_proxy_model_->rowCount(); i++) ui_.tv_affiliations->setExpanded(affiliations_proxy_model_->index(i, 0), true); // Roles & affiliations setRole(MUCItem::NoRole); setAffiliation(MUCItem::NoAffiliation); } MUCConfigDlg::~MUCConfigDlg() { delete affiliations_model_; } void MUCConfigDlg::setRoleAffiliation(MUCItem::Role role, MUCItem::Affiliation affiliation) { if (role_ != role) { setRole(role); } if (affiliation_ != affiliation) { setAffiliation(affiliation); } } void MUCConfigDlg::setRole(MUCItem::Role role) { role_ = role; } void MUCConfigDlg::setAffiliation(MUCItem::Affiliation affiliation) { affiliation_ = affiliation; ui_.tabs->setTabEnabled(ui_.tabs->indexOf(ui_.tab_general),affiliation == MUCItem::Owner); if (ui_.tabs->currentWidget() == ui_.tab_general) { refreshGeneral(); } else if (ui_.tabs->currentWidget() == ui_.tab_affiliations) { refreshAffiliations(); } } void MUCConfigDlg::refreshGeneral() { if (affiliation_ == MUCItem::Owner) { delete data_; data_ = NULL; ui_.lb_general_message->setText(tr("Requesting room configuration ...")); ui_.sw_general->setCurrentWidget(ui_.pg_general_message); ui_.busy->start(); manager_->getConfiguration(); } else { ui_.lb_general_message->setText(tr("You are not an owner of this room")); ui_.sw_general->setCurrentWidget(ui_.pg_general_message); if (ui_.tabs->currentWidget() == ui_.tab_general) ui_.tabs->setCurrentWidget(ui_.tab_affiliations); } } void MUCConfigDlg::refreshAffiliations() { affiliations_model_->resetAffiliationLists(); if (affiliation_ >= MUCItem::Member) { ui_.busy->start(); pending_requests_.clear(); pending_requests_ += MUCItem::Outcast; manager_->getItemsByAffiliation(MUCItem::Outcast); pending_requests_ += MUCItem::Member; manager_->getItemsByAffiliation(MUCItem::Member); pending_requests_ += MUCItem::Admin; manager_->getItemsByAffiliation(MUCItem::Admin); pending_requests_ += MUCItem::Owner; manager_->getItemsByAffiliation(MUCItem::Owner); } ui_.tv_affiliations->clearSelection(); } void MUCConfigDlg::add() { bool ok; QString text = QInputDialog::getText(this, tr("Add affiliation"), tr("Enter the JID of the user:"), QLineEdit::Normal, "", &ok); if (ok) { if (text.isEmpty() || !ui_.tv_affiliations->addToCurrent(text)) QMessageBox::critical(this, tr("Error"), tr("You have entered an invalid JID.")); } } void MUCConfigDlg::apply() { if (ui_.tabs->currentWidget() == ui_.tab_general) { if (affiliation_ == MUCItem::Owner && data_) { XData data; data.setFields(data_->fields()); ui_.busy->start(); manager_->setConfiguration(data); } } else if (ui_.tabs->currentWidget() == ui_.tab_affiliations) { QList changes = affiliations_model_->changes(); if (!changes.isEmpty()) { ui_.busy->start(); manager_->setItems(changes); } } } void MUCConfigDlg::destroy() { int i = QMessageBox::warning(this, tr("Destroy room"), tr("Are you absolutely certain you want to destroy this room?"),tr("Yes"),tr("No")); if (i == 0) { manager_->destroy(); } } void MUCConfigDlg::currentTabChanged(int) { ui_.busy->stop(); if (ui_.tabs->currentWidget() == ui_.tab_affiliations) refreshAffiliations(); else refreshGeneral(); } void MUCConfigDlg::applyFilter(const QString& s) { affiliations_proxy_model_->setFilterFixedString(s); } void MUCConfigDlg::getConfiguration_success(const XData& d) { if (affiliation_ == MUCItem::Owner) { ui_.busy->stop(); delete data_; data_ = new XDataWidget(ui_.pg_general_data); data_->setFields(d.fields()); data_container_->setWidget(data_); data_container_->updateGeometry(); ui_.sw_general->setCurrentWidget(ui_.pg_general_data); } } void MUCConfigDlg::getConfiguration_error(int, const QString& e) { ui_.busy->stop(); QString text = tr("There was an error retrieving the room configuration"); if (!e.isEmpty()) text += QString(":\n") + e; ui_.lb_general_message->setText(text); ui_.sw_general->setCurrentWidget(ui_.pg_general_message); } void MUCConfigDlg::setConfiguration_success() { if (affiliation_ == MUCItem::Owner && ui_.tabs->currentWidget() == ui_.tab_general) { ui_.busy->stop(); } } void MUCConfigDlg::setConfiguration_error(int, const QString& e) { if (ui_.tabs->currentWidget() == ui_.tab_general) { ui_.busy->stop(); QString text = tr("There was an error changing the room configuration"); if (!e.isEmpty()) text += QString(":\n") + e; ui_.lb_general_message->setText(text); ui_.sw_general->setCurrentWidget(ui_.pg_general_message); } } void MUCConfigDlg::getItemsByAffiliation_success(MUCItem::Affiliation a, const QList& items) { if (pending_requests_.contains(a) && ui_.tabs->currentWidget() == ui_.tab_affiliations) { ui_.tv_affiliations->setUpdatesEnabled(false); bool dynamicSortFilter = affiliations_proxy_model_->dynamicSortFilter(); affiliations_proxy_model_->setDynamicSortFilter(false); affiliations_model_->setAffiliationListEnabled(a); affiliations_model_->addItems(items); removePendingRequest(a); affiliations_proxy_model_->setDynamicSortFilter(dynamicSortFilter); ui_.tv_affiliations->setUpdatesEnabled(true); } } void MUCConfigDlg::getItemsByAffiliation_error(MUCItem::Affiliation a, int, const QString&) { if (pending_requests_.contains(a) && ui_.tabs->currentWidget() == ui_.tab_affiliations) { affiliations_model_->setAffiliationListEnabled(a,false); removePendingRequest(a); } } void MUCConfigDlg::setItems_success() { if (ui_.tabs->currentWidget() == ui_.tab_affiliations) { ui_.busy->stop(); refreshAffiliations(); } } void MUCConfigDlg::setItems_error(int, const QString&) { if (ui_.tabs->currentWidget() == ui_.tab_affiliations) { ui_.busy->stop(); QMessageBox::critical(this, tr("Error"), tr("There was an error setting modifying the affiliations.")); refreshAffiliations(); } } void MUCConfigDlg::removePendingRequest(MUCItem::Affiliation a) { pending_requests_.removeAll(a); if (pending_requests_.count() == 0) ui_.busy->stop(); } void MUCConfigDlg::destroy_success() { if (ui_.tabs->currentWidget() == ui_.tab_general) { ui_.busy->stop(); } } void MUCConfigDlg::destroy_error(int, const QString&) { if (ui_.tabs->currentWidget() == ui_.tab_general) { ui_.busy->stop(); QMessageBox::critical(this, tr("Error"), tr("There was an error destroying the room.")); } } psi-0.14/src/mcmdsimplesite.h0000644000175000017500000000277711305557613014335 0ustar janjan/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see . * */ // simple UI integration for mini command system. #ifndef MINICMDSIMPLESITE_H #define MINICMDSIMPLESITE_H #include "minicmd.h" #include class QLabel; class QTextEdit; class QString; class MCmdSimpleSite : public MCmdUiSiteIface { public: MCmdSimpleSite(QLabel *p, QTextEdit *i) : promptWidget(p), inputWidget(i), open(false) {}; MCmdSimpleSite() : promptWidget(0), inputWidget(0), open(false) {}; ~MCmdSimpleSite() {}; virtual void mCmdReady(const QString prompt, const QString preset); virtual void mCmdClose(); bool isActive() { return open; }; void setPrompt(QLabel *p) {promptWidget = p;}; void setInput(QTextEdit *i); protected: QLabel *promptWidget; QTextEdit *inputWidget; bool open; QString mini_msg_swap; int cursorPos; // FIXME save cursor position... QPalette palette, cmdPalette; }; #endif psi-0.14/src/tipdlg.cpp0000644000175000017500000002065411305557613013126 0ustar janjan/* * tipdlg.cpp - Handles Tip of the Day * Copyright (C) 2001-2006 Michail Pishchagin * * 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 2 * of the License, or (at your option) any later version. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "tipdlg.h" #include "psioptions.h" #include "psicon.h" void TipDlg::show(PsiCon* psi) { QWidget* dlg = psi->dialogFind(TipDlg::staticMetaObject.className()); if (!dlg) dlg = new TipDlg(psi); Q_ASSERT(dlg); bringToFront(dlg); } /** * \class TipDlg * \brief A 'Tip Of The Day' dialog */ TipDlg::TipDlg(PsiCon* psi) : QDialog(0) , psi_(psi) { setAttribute(Qt::WA_DeleteOnClose); setupUi(this); setModal(false); psi_->dialogRegister(this); //ck_showTips->hide(); connect(pb_close,SIGNAL(clicked()),SLOT(accept())); connect(pb_previous,SIGNAL(clicked()),SLOT(previous())); connect(pb_next,SIGNAL(clicked()),SLOT(next())); connect(ck_showTips,SIGNAL(toggled(bool)),SLOT(showTipsChanged(bool))); // add useful tips here addTip( tr("Hello! Thank you for downloading Psi!\nWe hope that you will enjoy using it as we have enjoyed making it!\n" "

If you want to download another language translation, iconset or a new version of Psi, then you need to visit the Psi HomePage.\n" "

If you think, that you have found a bug or you just want to chat with other Psi users, then visit the Psi Forums.\n" "

the Psi Team
"), "" ); addTip( tr("You can select multiple emoticon iconsets, and assign them priorities using the options dialog."), "" ); addTip( tr("You can use multiple useful shortcuts while typing chat messages:
\n" "
    \n" "
  • Ctrl+Enter to send message
  • \n" "
  • Ctrl+M to add newline character
  • \n" "
  • Ctrl+H to display message history dialog
  • \n" "
  • Alt+S to send message
  • \n" "
  • Ctrl+U to clear edit buffer
  • \n" "
  • Ctrl+PgUp/PgDn to scroll chat view
  • \n" "
"), "" ); addTip( tr("You can type these special commands in chat and groupchat dialogs:\n" "
    \n" "
  • \"/clear\" to clear chat view
  • \n" "
  • \"/me <message>\" '/me' is replaced by your nick
  • \n" "
\n" "And these work only in groupchat dialog:\n" "
    \n" "
  • \"/nick <new_nickname>\" to change your nickname
  • \n" "
"), "" ); addTip( tr("Did you know that you can register multiple Jabber accounts with Psi? If you like to separate your work from your personal account, you can. If you are a power user who wants to test the latest Jabber features on an unstable server, you can do that -- without running a second client to connect to your stable server. Just click Add in the Account Setup screen."), "Hal Rottenberg" ); addTip( tr("Do you chat on third-party IM networks such as AIM and ICQ? Try enabling the \"transport-specific icons\" option. This will allow you to quickly see at a glance which network your buddy is using. Then you can convince him to switch to Jabber. "), "Hal Rottenberg" ); addTip( tr("Did you know that you can use checkboxes in Account Setup dialog to enable/disable accounts? This may be useful in the case of an account that you use rarely, so it will not clutter your roster."), "Iain MacDonnell" ); addTip( tr("Don't like the buttons where they are? Want a shortcut button to change your status to Away? Check out the Configure Toolbars window, it's available through toolbars' context menu. You can even make a toolbar that floats!"), "Hal Rottenberg" ); addTip( tr("Did you know that Psi is one of the only Jabber clients that allows you to connect to multiple servers at the same time? You can be known as \"mrcool@jabber.org\" to your friends, and \"John.J.Smith_the_fourth@mycompany.com\" to business associates."), "Hal Rottenberg" ); addTip( tr("Have you converted over from Gadu-Gadu or Trillian and you miss the cool emoticons? Fear not, we have you covered! Check out http://jisp.netflint.net for tons of \"Iconsets\" that can be added to Psi to make it look the way you like!"), "Hal Rottenberg" ); addTip( tr("Did you know that a middle-click (the middle mouse button on a 3-button mouse) will \"perform the default action\" on many objects within Psi? Try middle-clicking on a contact or a popup."), "Hal Rottenberg" ); addTip( tr("In order to add contacts from different IM networks, you need to add a corresponding agent from your Jabber server. Take a look at Psi Menu -> Service Discovery."), "Philipp Droessler" ); addTip( tr("You can right-click on the server name in your roster to perform several different actions. You can change status, modify account settings, perform administrative options (if you have permission), and more."), "Hal Rottenberg" ); addTip( tr("Looking for a transport or chatroom, but your server provides nothing appropriate? Use Psi Menu -> Service Discovery to look on any Jabber Server for nice services by typing its domain in the address field.\n

\nNote: Some server may disable transport registration to users from different servers, but that's not common yet."), "Patrick Hanft" ); addTip( tr("If you're chatting in groupchats quite frequently, nick completion is an invaluable feature. The most useful shortcut is Tab-Tab; when used on beginning of new line or after a step it inserts the nickname of the person who last addressed you directly. You can then continue to press Tab and it will loop on the nicks of all the people in the room.

For a more complicated scenario: mblsha, Monster and mbl-revolution are all sitting in same room. If you write m and press Tab it will not result in any noticeable action. This is because there are multiple nicks that start with m, and you can either continue to Tab to loop through all nicks that start with m or write more letters until there is a unique completion. When you press the b button, and then press Tab it would complete to mbl. The more you use this feature, the more you are likely to come to like it and rely upon it. Try nick completion on someone and you'll realise how powerful it is."), "Michail Pishchagin and Kevin Smith" ); // this MUST be the last tip addTip( tr("This is the last tip.\n

If you want to contribute your own \"tip of the day\", please publish it on the Psi Forums (or mail it to the one of the developers), and we'll be happy to integrate it for the next release."), "" ); updateTip(); ck_showTips->setChecked( PsiOptions::instance()->getOption("options.ui.tip.show").toBool()); } TipDlg::~TipDlg() { psi_->dialogUnregister(this); } void TipDlg::updateTip() { int num = PsiOptions::instance()->getOption("options.ui.tip.number").toInt(); if ( num < 0 ) num = tips.count() - 1; else if ( num >= (int)tips.count() ) num = 0; tv_psi->setText( tips[num] ); PsiOptions::instance()->setOption("options.ui.tip.number", num+1); } void TipDlg::next() { updateTip(); } void TipDlg::previous() { int num = PsiOptions::instance()->getOption("options.ui.tip.number").toInt(); PsiOptions::instance()->setOption("options.ui.tip.number", num-2); updateTip(); } void TipDlg::showTipsChanged( bool e ) { PsiOptions::instance()->setOption("options.ui.tip.show", e); } void TipDlg::addTip(const QString& tip, const QString& author ) { QString t = tip; if ( !author.isEmpty() ) t += "

" + tr("Contributed by") + " " + author + ""; tips += "" + t + ""; } psi-0.14/src/rc.cpp0000644000175000017500000002167511305557613012253 0ustar janjan/* * rc.cpp - Implementation of JEP-146 (Remote Controlling Clients) * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconaction.h" #include "psiaccount.h" #include "psiactionlist.h" #include "psicon.h" #include "psioptions.h" #include "rc.h" #include "xmpp_xdata.h" #include "ahcservermanager.h" #include "ahcommand.h" using namespace XMPP; bool RCCommandServer::isAllowed(const Jid& j) const { return manager()->account()->jid().compare(j,false); } AHCommand RCSetStatusServer::execute(const AHCommand& c, const Jid&) { // Check if the session ID is correct //if (c.sessionId() != "") // return AHCommand::errorReply(c,AHCError::AHCError(AHCError::BadSessionID)); if (!c.hasData()) { // Initial set status form XData form; form.setTitle(QObject::tr("Set Status")); form.setInstructions(QObject::tr("Choose the status and status message")); form.setType(XData::Data_Form); XData::FieldList fields; XData::Field type_field; type_field.setType(XData::Field::Field_Hidden); type_field.setVar("FORM_TYPE"); type_field.setValue(QStringList("http://jabber.org/protocol/rc")); type_field.setRequired(false); fields += type_field; XData::Field status_field; status_field.setType(XData::Field::Field_ListSingle); status_field.setVar("status"); status_field.setLabel(QObject::tr("Status")); status_field.setRequired(true); status_field.setValue(QStringList(manager()->account()->status().typeString())); XData::Field::OptionList status_options; if (PsiOptions::instance()->getOption("options.ui.menu.status.chat").toBool()) { XData::Field::Option chat_option; chat_option.label = QObject::tr("Chat"); chat_option.value = "chat"; status_options += chat_option; } XData::Field::Option online_option; online_option.label = QObject::tr("Online"); online_option.value = "online"; status_options += online_option; XData::Field::Option away_option; away_option.label = QObject::tr("Away"); away_option.value = "away"; status_options += away_option; if (PsiOptions::instance()->getOption("options.ui.menu.status.xa").toBool()) { XData::Field::Option xa_option; xa_option.label = QObject::tr("Extended Away"); xa_option.value = "xa"; status_options += xa_option; } XData::Field::Option dnd_option; dnd_option.label = QObject::tr("Do Not Disturb"); dnd_option.value = "dnd"; status_options += dnd_option; if (PsiOptions::instance()->getOption("options.ui.menu.status.invisible").toBool()) { XData::Field::Option invisible_option; invisible_option.label = QObject::tr("Invisible"); invisible_option.value = "invisible"; status_options += invisible_option; } XData::Field::Option offline_option; offline_option.label = QObject::tr("Offline"); offline_option.value = "offline"; status_options += offline_option; status_field.setOptions(status_options); fields += status_field; XData::Field priority_field; priority_field.setType(XData::Field::Field_TextSingle); priority_field.setLabel(QObject::tr("Priority")); priority_field.setVar("status-priority"); priority_field.setRequired(false); priority_field.setValue(QStringList(QString::number(manager()->account()->status().priority()))); fields += priority_field; XData::Field statusmsg_field; statusmsg_field.setType(XData::Field::Field_TextMulti); statusmsg_field.setLabel(QObject::tr("Message")); statusmsg_field.setVar("status-message"); statusmsg_field.setRequired(false); statusmsg_field.setValue(QStringList(manager()->account()->status().status())); fields += statusmsg_field; form.setFields(fields); return AHCommand::formReply(c, form); } else { // Set the status Status s; bool foundStatus = false; XData::FieldList fl = c.data().fields(); for (int i=0; i < fl.count(); i++) { if (fl[i].var() == "status" && !(fl[i].value().isEmpty())) { foundStatus = true; s.setType(fl[i].value().first()); } else if (fl[i].var() == "status-message" && !fl[i].value().isEmpty()) { s.setStatus(fl[i].value().join("\n")); } else if (fl[i].var() == "status-priority" && !fl[i].value().isEmpty()) { s.setPriority(fl[i].value().first().toInt()); } } if (foundStatus) { manager()->account()->setStatus(s,true); } return AHCommand::completedReply(c); } } AHCommand RCForwardServer::execute(const AHCommand& c, const Jid& j) { int messageCount = manager()->account()->forwardPendingEvents(j); XData form; form.setTitle(QObject::tr("Forward Messages")); form.setInstructions(QObject::tr("Forwarded %1 messages").arg(messageCount)); form.setType(XData::Data_Form); return AHCommand::completedReply(c,form); } AHCommand RCSetOptionsServer::execute(const AHCommand& c, const Jid&) { if (!c.hasData()) { // Initial set options form XData form; form.setTitle(QObject::tr("Set Options")); form.setInstructions(QObject::tr("Set the desired options")); form.setType(XData::Data_Form); XData::FieldList fields; XData::Field type_field; type_field.setType(XData::Field::Field_Hidden); type_field.setVar("FORM_TYPE"); type_field.setValue(QStringList("http://jabber.org/protocol/rc")); type_field.setRequired(false); fields += type_field; XData::Field sounds_field; sounds_field.setType(XData::Field::Field_Boolean); sounds_field.setLabel(QObject::tr("Play sounds")); sounds_field.setVar("sounds"); sounds_field.setValue(QStringList((PsiOptions::instance()->getOption("options.ui.notifications.sounds.enable").toBool() ? "1" : "0"))); sounds_field.setRequired(false); fields += sounds_field; XData::Field auto_offline_field; auto_offline_field.setType(XData::Field::Field_Boolean); auto_offline_field.setLabel(QObject::tr("Automatically go offline when idle")); auto_offline_field.setVar("auto-offline"); auto_offline_field.setValue(QStringList((PsiOptions::instance()->getOption("options.status.auto-away.use-offline").toBool() ? "1" : "0"))); auto_offline_field.setRequired(false); fields += auto_offline_field; XData::Field auto_auth_field; auto_auth_field.setType(XData::Field::Field_Boolean); auto_auth_field.setLabel(QObject::tr("Auto-authorize contacts")); auto_auth_field.setVar("auto-auth"); auto_auth_field.setValue(QStringList((PsiOptions::instance()->getOption("options.subscriptions.automatically-allow-authorization").toBool() ? "1" : "0"))); auto_auth_field.setRequired(false); fields += auto_auth_field; XData::Field auto_open_field; auto_open_field.setType(XData::Field::Field_Boolean); auto_open_field.setLabel(QObject::tr("Auto-open new messages")); auto_open_field.setVar("auto-open"); auto_open_field.setValue(QStringList((PsiOptions::instance()->getOption("options.ui.message.auto-popup").toBool() ? "1" : "0"))); auto_open_field.setRequired(false); fields += auto_open_field; form.setFields(fields); return AHCommand::formReply(c, form); } else { // Set the options XData::FieldList fl = c.data().fields(); for (int i=0; i < fl.count(); i++) { if (fl[i].var() == "sounds") { QString v = fl[i].value().first(); IconAction* soundact = psiCon_->actionList()->suitableActions(PsiActionList::ActionsType( PsiActionList::Actions_MainWin | PsiActionList::Actions_Common)).action("menu_play_sounds"); if (v == "1") soundact->setChecked(true); else if (v == "0") soundact->setChecked(false); } else if (fl[i].var() == "auto-offline") { QString v = fl[i].value().first(); if (v == "1") PsiOptions::instance()->setOption("options.status.auto-away.use-offline", (bool) true); else if (v == "0") PsiOptions::instance()->setOption("options.status.auto-away.use-offline", (bool) false); } else if (fl[i].var() == "auto-auth") { QString v = fl[i].value().first(); if (v == "1") PsiOptions::instance()->setOption("options.subscriptions.automatically-allow-authorization", (bool) true); else if (v == "0") PsiOptions::instance()->setOption("options.subscriptions.automatically-allow-authorization", (bool) false); } else if (fl[i].var() == "auto-open") { QString v = fl[i].value().first(); if (v == "1") PsiOptions::instance()->setOption("options.ui.message.auto-popup", (bool) true); else if (v == "0") PsiOptions::instance()->setOption("options.ui.message.auto-popup", (bool) false); } } return AHCommand::completedReply(c); } } psi-0.14/src/mucaffiliationsmodel.cpp0000644000175000017500000001625411305557613016042 0ustar janjan/* * mucaffiliationsmodel.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "mucaffiliationsmodel.h" using namespace XMPP; MUCAffiliationsModel::MUCAffiliationsModel() : QStandardItemModel(Unknown,1) { QFont font; font.setBold(true); QVariant font_variant = qVariantFromValue(font); for (int i = 0; i < Unknown; i++) { QModelIndex ind = index(i, 0, QModelIndex()); setData(ind,QVariant(affiliationlistindexToString((AffiliationListIndex) i))); setData(ind,font_variant,Qt::FontRole); insertColumns(0,1,ind); enabled_[(AffiliationListIndex) i] = false; } } Qt::ItemFlags MUCAffiliationsModel::flags(const QModelIndex &index) const { Qt::ItemFlags a; if (!index.parent().isValid()) { // List headers if (enabled_[(AffiliationListIndex) index.row()]) { a |= Qt::ItemIsDropEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; } } else { a |= Qt::ItemIsDropEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled; } return a; } Qt::DropActions MUCAffiliationsModel::supportedDropActions() const { return Qt::MoveAction; } bool MUCAffiliationsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int, const QModelIndex &parent) { if (!data || action != Qt::MoveAction || !(data->hasFormat("application/vnd.text.list") || data->hasFormat("text/plain"))) return false; // Decode the data QStringList newItems; int nb_rows = 0; if (data->hasFormat("application/vnd.text.list")) { QByteArray encodedData = data->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { QString text; stream >> text; newItems << text; nb_rows++; } } else if (data->hasFormat("text/plain")) { QString item(data->data("text/plain")); if (Jid(item).isValid()) { newItems += item; nb_rows++; } } if (nb_rows == 0) return false; // Determine the correct index QModelIndex real_index; if (parent.isValid()) { real_index = (parent.parent().isValid() ? parent.parent() : parent); } else { if (row > 0) real_index = index(row-1,0,parent); else if (row == 0) real_index = index(0,0,parent); else real_index = index(Outcast,0,parent); } int real_row = rowCount(real_index); // Insert the data insertRows(real_row, nb_rows, real_index); foreach (QString text, newItems) { QModelIndex idx = index(real_row, 0, real_index); setData(idx, text); real_row++; } return true; } QStringList MUCAffiliationsModel::mimeTypes() const { QStringList types; types << "application/vnd.text.list"; types << "text/plain"; return types; } QMimeData* MUCAffiliationsModel::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); foreach (QModelIndex index, indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; } void MUCAffiliationsModel::resetAffiliationLists() { items_.clear(); resetAffiliationList(MUCItem::Outcast); resetAffiliationList(MUCItem::Member); resetAffiliationList(MUCItem::Admin); resetAffiliationList(MUCItem::Owner); } void MUCAffiliationsModel::resetAffiliationList(MUCItem::Affiliation a) { enabled_[(AffiliationListIndex) affiliationToIndex(a)] = false; QModelIndex index = affiliationListIndex(a); if (hasChildren(index)) { removeRows(0,rowCount(index),index); } } void MUCAffiliationsModel::setAffiliationListEnabled(MUCItem::Affiliation a, bool b) { QModelIndex index = affiliationListIndex(a); enabled_[(AffiliationListIndex) index.row()] = b; emit layoutChanged(); } QString MUCAffiliationsModel::affiliationlistindexToString(AffiliationListIndex list) { if (list == Members) return tr("Members"); else if (list == Admins) return tr("Administrators"); else if (list == Owners) return tr("Owners"); else if (list == Outcast) return tr("Banned"); return QString(); } QModelIndex MUCAffiliationsModel::affiliationListIndex(MUCItem::Affiliation a) { AffiliationListIndex i = affiliationToIndex(a); if (i == Unknown) { qWarning("mucconfigdlg.cpp: Unexpected affiliation"); return QModelIndex(); } return index(i, 0, QModelIndex()); } MUCAffiliationsModel::AffiliationListIndex MUCAffiliationsModel::affiliationToIndex(MUCItem::Affiliation a) { if (a == MUCItem::Member) return Members; else if (a == MUCItem::Admin) return Admins; else if (a == MUCItem::Owner) return Owners; else if (a == MUCItem::Outcast) return Outcast; else return Unknown; } void MUCAffiliationsModel::addItems(const QList& items) { bool dirty = false; foreach(MUCItem item, items) { QModelIndex list = affiliationListIndex(item.affiliation()); if (list.isValid() && !item.jid().isEmpty()) { int row = rowCount(list); if (row == 0) { enabled_[(AffiliationListIndex) list.row()] = true; } insertRows(row,1,list); setData(index(row,0,list),QVariant(item.jid().full())); MUCItem i(MUCItem::UnknownRole,item.affiliation()); i.setJid(item.jid()); items_ += i; dirty = true; } else { qDebug("Unexpected item"); } } if (dirty) emit layoutChanged(); } QList MUCAffiliationsModel::changes() const { QList items_old = items_; QList items_delta; // Add all new items for (int i = 0; i < rowCount(QModelIndex()); i++) { QModelIndex list = index(i,0,QModelIndex()); for(int j = 0; j < rowCount(list); j++) { Jid jid(data(index(j,0,list)).toString()); MUCItem item(MUCItem::UnknownRole,indexToAffiliation(i)); item.setJid(jid); if (!items_.contains(item)) { items_delta += item; } else items_old.removeAll(item); } } // Remove all old items not present in the delta foreach(MUCItem item_old, items_old) { bool found = false; foreach(MUCItem item_new, items_delta) { if (item_new.jid().compare(item_old.jid(),false)) { found = true; break; } } if (!found) { MUCItem item(MUCItem::UnknownRole,MUCItem::NoAffiliation); item.setJid(item_old.jid()); items_delta += item; } } return items_delta; } MUCItem::Affiliation MUCAffiliationsModel::indexToAffiliation(int li) { if (li == Members) return MUCItem::Member; else if (li == Admins) return MUCItem::Admin; else if (li == Owners) return MUCItem::Owner; else if (li == Outcast) return MUCItem::Outcast; else return MUCItem::UnknownAffiliation; } psi-0.14/src/mainwin.h0000644000175000017500000000742311305557613012751 0ustar janjan/* * mainwin.h - the main window. holds contactlist and buttons. * Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MAINWIN_H #define MAINWIN_H #include #include #include #include #include #include "advwidget.h" class QMenuBar; class QAction; class QPixmap; class QPoint; class QMenu; class PsiCon; class PsiToolBar; class PsiAccount; class IconAction; class PsiIcon; class ContactView; namespace XMPP { class Status; } class MainWin : public AdvancedWidget { Q_OBJECT public: MainWin(bool onTop, bool asTool, PsiCon *); ~MainWin(); void setWindowOpts(bool onTop, bool asTool); void setUseDock(bool); void buildToolbars(); // evil stuff! remove ASAP!! QStringList actionList; QMap actions; ContactView *cvlist; PsiCon *psiCon() const; protected: // reimplemented void closeEvent(QCloseEvent *); void keyPressEvent(QKeyEvent *); QMenuBar* mainMenuBar() const; #ifdef Q_WS_WIN bool winEvent(MSG *, long *); #endif signals: void statusChanged(int); void changeProfile(); void blankMessage(); void closeProgram(); void doOptions(); void doToolbars(); void doManageAccounts(); void doGroupChat(); void doFileTransDlg(); void accountInfo(); void recvNextEvent(); private slots: void buildStatusMenu(); void buildOptionsMenu(); void buildTrayMenu(); void buildMainMenu(); void buildToolsMenu(); void setTrayToolTip(int); void activatedStatusAction(int); void trayClicked(const QPoint &, int); void trayDoubleClicked(); void trayShow(); void trayHide(); void doRecvNextEvent(); void statusClicked(int); void try2tryCloseProgram(); void tryCloseProgram(); void numAccountsChanged(); void accountFeaturesChanged(); void activatedAccOption(PsiAccount *, int); void actReadmeActivated (); void actOnlineHelpActivated (); void actOnlineWikiActivated (); void actOnlineHomeActivated (); void actOnlineForumActivated (); void actJoinPsiMUCActivated(); void actBugReportActivated (); void actAboutActivated (); void actAboutQtActivated (); void actAboutPsiMediaActivated (); void actPlaySoundsActivated (bool); void actPublishTuneActivated (bool); void actTipActivated(); void actDiagQCAPluginActivated(); void actDiagQCAKeyStoreActivated(); bool showDockMenu(const QPoint &); void dockActivated(); void searchClearClicked(); void searchTextEntered(QString const &text); void searchTextStarted(QString const &text); void registerAction( IconAction * ); public slots: void setWindowIcon(const QPixmap&); void showNoFocus(); void decorateButton(int); void updateReadNext(PsiIcon *nextAnim, int nextAmount); void optionsUpdate(); void setTrayToolTip(const XMPP::Status &, bool usePriority = false); void toggleVisible(); void avcallConfig(); private: void buildGeneralMenu(QMenu *); QString numEventsString(int) const; bool askQuit(); void updateCaption(); void updateTray(); void saveToolbarsState(); void loadToolbarsState(); private: class Private; Private *d; friend class Private; QList toolbars_; }; #endif psi-0.14/src/profiledlg.cpp0000644000175000017500000002266611305557613013777 0ustar janjan/* * profiledlg.cpp - dialogs for manipulating profiles * Copyright (C) 2001-2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "profiledlg.h" #include "applicationinfo.h" #include "iconset.h" #include "psioptions.h" #include #include #include #include #include #include #include #include #include #include #include "profiles.h" #include "common.h" #include "iconwidget.h" #include class StretchLogoLabel : public QLabel { public: StretchLogoLabel(QPixmap pix, QWidget *label) : QLabel(label->parentWidget()) , pixmap_(pix) { replaceWidget(label, this); setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum)); } // reimplemented QSize sizeHint() const { QSize sh = QLabel::sizeHint(); sh.setHeight(pixmap_.height()); return sh; } void paintEvent(QPaintEvent *event) { QPainter p(this); p.fillRect(rect(), Qt::red); p.drawTiledPixmap(0, 0, width(), height(), pixmap_); } private: QPixmap pixmap_; }; //---------------------------------------------------------------------------- // ProfileOpenDlg //---------------------------------------------------------------------------- ProfileOpenDlg::ProfileOpenDlg(const QString &def, const VarList &_langs, const QString &curLang, QWidget *parent) :QDialog(parent) { setupUi(this); setModal(true); setWindowTitle(CAP(windowTitle())); pb_open->setDefault(true); langs = _langs; QPixmap logo = (QPixmap)IconsetFactory::icon("psi/psiLogo").pixmap(); lb_logo->setPixmap(logo); lb_logo->setFixedSize(logo.width(), logo.height()); lb_logo->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); //setFixedWidth(logo->width()); QImage logoImg = logo.toImage(); new StretchLogoLabel(QPixmap::fromImage( logoImg.copy(0, 0, 1, logoImg.height()) ), lb_left); new StretchLogoLabel(QPixmap::fromImage( logoImg.copy(logoImg.width()-1, 0, 1, logoImg.height()) ), lb_right); connect(pb_open, SIGNAL(clicked()), SLOT(accept())); connect(pb_close, SIGNAL(clicked()), SLOT(reject())); connect(pb_profiles, SIGNAL(clicked()), SLOT(manageProfiles())); connect(cb_lang, SIGNAL(activated(int)), SLOT(langChange(int))); int x = 0; langSel = x; for(VarList::ConstIterator it = langs.begin(); it != langs.end(); ++it) { cb_lang->addItem((*it).data()); if((curLang.isEmpty() && x == 0) || (curLang == (*it).key())) { cb_lang->setCurrentIndex(x); langSel = x; } ++x; } cb_profile->setWhatsThis( tr("Select a profile to open from this list.")); cb_lang->setWhatsThis( tr("Select a language you would like Psi to use from this " "list. You can download extra language packs from the Psi homepage.")); ck_auto->setWhatsThis( tr("Automatically open this profile when Psi is started. Useful if " "you only have one profile.")); reload(def); } ProfileOpenDlg::~ProfileOpenDlg() { } void ProfileOpenDlg::reload(const QString &choose) { QStringList list = getProfilesList(); cb_profile->clear(); if(list.count() == 0) { gb_open->setEnabled(false); pb_open->setEnabled(false); pb_profiles->setFocus(); } else { int x = 0; for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { cb_profile->addItem(*it); if((choose.isEmpty() && x == 0) || (choose == *it)) { cb_profile->setCurrentIndex(x); } ++x; } gb_open->setEnabled(true); pb_open->setEnabled(true); pb_open->setFocus(); } } void ProfileOpenDlg::manageProfiles() { ProfileManageDlg *w = new ProfileManageDlg(cb_profile->currentText(), this); w->exec(); QString last = w->lbx_profiles->currentItem()->text(); delete w; reload(last); } void ProfileOpenDlg::langChange(int x) { if(x == langSel) return; langSel = x; VarList::Iterator it = langs.findByNum(x); newLang = (*it).key(); done(10); } //---------------------------------------------------------------------------- // ProfileManageDlg //---------------------------------------------------------------------------- ProfileManageDlg::ProfileManageDlg(const QString &choose, QWidget *parent) :QDialog(parent) { setupUi(this); setModal(true); setWindowTitle(CAP(windowTitle())); // setup signals connect(pb_new, SIGNAL(clicked()), SLOT(slotProfileNew())); connect(pb_rename, SIGNAL(clicked()), SLOT(slotProfileRename())); connect(pb_delete, SIGNAL(clicked()), SLOT(slotProfileDelete())); connect(lbx_profiles, SIGNAL(currentRowChanged(int)), SLOT(updateSelection())); // load the listing QStringList list = getProfilesList(); int x = 0; for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { lbx_profiles->addItem(*it); if(*it == choose) lbx_profiles->setCurrentRow(x); ++x; } updateSelection(); } void ProfileManageDlg::slotProfileNew() { QString name; ProfileNewDlg *w = new ProfileNewDlg(this); int r = w->exec(); if(r == QDialog::Accepted) { name = w->name; lbx_profiles->addItem(name); lbx_profiles->setCurrentRow(lbx_profiles->count()-1); } delete w; if(r == QDialog::Accepted) { close(); } } void ProfileManageDlg::slotProfileRename() { int x = lbx_profiles->currentRow(); if(x == -1) return; QString oldname = lbx_profiles->item(x)->text(); QString name; while(1) { bool ok = false; name = QInputDialog::getText(this, CAP(tr("Rename Profile")), tr("Please enter a new name for the profile. Keep it simple.\nOnly use letters or numbers. No punctuation or spaces."), QLineEdit::Normal, name, &ok); if(!ok) return; if(profileExists(name)) { QMessageBox::information(this, CAP(tr("Rename Profile")), tr("There is already another profile with this name. Please choose another.")); continue; } else if(!profileRename(oldname, name)) { QMessageBox::information(this, CAP(tr("Rename Profile")), tr("Unable to rename the profile. Please do not use any special characters.")); continue; } break; } lbx_profiles->item(x)->setText(name); } void ProfileManageDlg::slotProfileDelete() { int x = lbx_profiles->currentRow(); if(x == -1) return; QString name = lbx_profiles->item(x)->text(); QString path = ApplicationInfo::profilesDir() + "/" + name; // prompt first int r = QMessageBox::warning(this, CAP(tr("Delete Profile")), tr( "Are you sure you want to delete the \"%1\" profile? " "This will delete all of the profile's message history as well as associated settings!" ).arg(name), tr("No, I changed my mind"), tr("Delete it!")); if(r != 1) return; r = QMessageBox::information(this, CAP(tr("Delete Profile")), tr( "As a precaution, you are being asked one last time if this is what you really want. " "The following folder will be deleted!

\n" "  %1

\n" "Proceed?" ).arg(path), tr("&No"), tr("&Yes")); if(r == 1) { if(!profileDelete(path)) { QMessageBox::critical(this, CAP("Error"), tr("Unable to delete the folder completely. Ensure you have the proper permission.")); return; } // FIXME delete lbx_profiles->item(x); } } void ProfileManageDlg::updateSelection() { int x = lbx_profiles->currentRow(); if(x == -1) { // pb_rename->setEnabled(false); pb_delete->setEnabled(false); } else { // pb_rename->setEnabled(true); pb_delete->setEnabled(true); } } //---------------------------------------------------------------------------- // ProfileNewDlg //---------------------------------------------------------------------------- ProfileNewDlg::ProfileNewDlg(QWidget *parent) :QDialog(parent) { setupUi(this); setModal(true); setWindowTitle(CAP(windowTitle())); buttonGroup_ = new QButtonGroup(this); buttonGroup_->addButton(rb_message, 0); buttonGroup_->addButton(rb_chat, 1); rb_chat->setChecked(true); le_name->setFocus(); connect(pb_create, SIGNAL(clicked()), SLOT(slotCreate())); connect(pb_close, SIGNAL(clicked()), SLOT(reject())); connect(le_name, SIGNAL(textChanged(const QString &)), SLOT(nameModified())); nameModified(); } void ProfileNewDlg::slotCreate() { name = le_name->text(); if(profileExists(name)) { QMessageBox::information(this, CAP(tr("New Profile")), tr("There is already an existing profile with this name. Please choose another.")); return; } if(!profileNew(name)) { QMessageBox::information(this, CAP(tr("New Profile")), tr("Unable to create the profile. Please do not use any special characters.")); return; } // save config PsiOptions o; if (!o.newProfile()) { qWarning("ERROR: Failed to new profile default options"); } o.setOption("options.messages.default-outgoing-message-type" ,rb_message->isChecked() ? "message": "chat"); o.setOption("options.ui.emoticons.use-emoticons" ,ck_useEmoticons->isChecked()); o.save(pathToProfile(name) + "/options.xml"); accept(); } void ProfileNewDlg::nameModified() { pb_create->setEnabled(!le_name->text().isEmpty()); } psi-0.14/src/tabs/0000755000175000017500000000000011305557613012061 5ustar janjanpsi-0.14/src/tabs/tabbablewidget.h0000644000175000017500000000373111305557613015176 0ustar janjan/* * tabbable.h * Copyright (C) 2007 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TABBABLE_H #define TABBABLE_H #include "advwidget.h" #include "im.h" // ChatState namespace XMPP { class Jid; class Message; } using namespace XMPP; class PsiAccount; class TabManager; class TabDlg; class TabbableWidget : public AdvancedWidget { Q_OBJECT public: TabbableWidget(const Jid &, PsiAccount *, TabManager *tabManager); ~TabbableWidget(); virtual Jid jid() const; virtual const QString & getDisplayName(); virtual bool readyToHide(); TabDlg* getManagingTabDlg(); bool isTabbed(); bool isActiveTab(); // reimplemented virtual void doFlash(bool on); virtual void invalidateTab(); enum State { StateNone = 0, StateComposing }; virtual State state() const = 0; virtual int unreadMessageCount() const = 0; virtual QString desiredCaption() const = 0; signals: void invalidateTabInfo(); void updateFlashState(); void eventsRead(const Jid &); public slots: virtual void deactivated(); virtual void activated(); void bringToFront(); virtual void ensureTabbedCorrectly(); protected: virtual void setJid(const Jid&); PsiAccount* account() const; // reimplemented void changeEvent(QEvent* e); private: Jid jid_; PsiAccount *pa_; TabManager *tabManager_; }; #endif psi-0.14/src/tabs/tabbablewidget.cpp0000644000175000017500000001066111305557613015531 0ustar janjan/* * tabbable.cpp * Copyright (C) 2007 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "tabbablewidget.h" #include "tabmanager.h" #include "tabdlg.h" #include "jidutil.h" #include "groupchatdlg.h" #include "psioptions.h" #include #ifdef Q_WS_WIN #include #endif //---------------------------------------------------------------------------- // TabbableWidget //---------------------------------------------------------------------------- TabbableWidget::TabbableWidget(const Jid &jid, PsiAccount *pa, TabManager *tabManager) : AdvancedWidget(0) , jid_(jid) , pa_(pa) , tabManager_(tabManager) { QTimer::singleShot(0, this, SLOT(ensureTabbedCorrectly())); } void TabbableWidget::ensureTabbedCorrectly() { if (tabManager_->shouldBeTabbed(this)) { if (!isTabbed()) { tabManager_->getTabs(this)->addTab(this); } } else { if (PsiOptions::instance()->getOption("options.ui.tabs.tab-singles").toString().contains(tabManager_->tabKind(this))) { if (isTabbed()) { if (getManagingTabDlg()->tabCount() > 1) { getManagingTabDlg()->closeTab(this, false); tabManager_->newTabs(this)->addTab(this); } } else { tabManager_->newTabs(this)->addTab(this); } } else { if (isTabbed()) { getManagingTabDlg()->closeTab(this, false); } // FIXME: showWithoutActivation() works on all // platforms, but bringToFront() (which might be // called immediately after) does not work on all // platforms if it follows a call to // showWithoutActivation(). As a temporary fix, we // will only call showWithoutActivation() on // platforms where both calls can be made in // succession. #ifdef Q_WS_WIN showWithoutActivation(); #else show(); #endif } } } void TabbableWidget::bringToFront() { if (isTabbed()) { getManagingTabDlg()->selectTab(this); } ::bringToFront(this); } TabbableWidget::~TabbableWidget() { if (isTabbed()) { getManagingTabDlg()->removeTabWithNoChecks(this); } } /** * Checks if the dialog is in a tabset */ bool TabbableWidget::isTabbed() { return tabManager_->isChatTabbed(this); } TabDlg* TabbableWidget::getManagingTabDlg() { return tabManager_->getManagingTabs(this); } /** * Runs any gumph necessary before hiding a tab. * (checking new messages, setting the autodelete, cancelling composing etc) * \return TabbableWidget is ready to be hidden. */ bool TabbableWidget::readyToHide() { return true; } Jid TabbableWidget::jid() const { return jid_; } void TabbableWidget::setJid(const Jid& j) { jid_ = j; } const QString& TabbableWidget::getDisplayName() { return jid_.node(); } void TabbableWidget::deactivated() { } void TabbableWidget::activated() { } /** * Returns true if this tab is active in the active window. */ bool TabbableWidget::isActiveTab() { if (isHidden()) { return false; } if (!isTabbed()) { return isActiveWindow() && !isMinimized(); } return getManagingTabDlg()->isActiveWindow() && getManagingTabDlg()->tabOnTop(this) && !getManagingTabDlg()->isMinimized(); } void TabbableWidget::doFlash(bool on) { AdvancedWidget::doFlash(on); emit updateFlashState(); } TabbableWidget::State TabbableWidget::state() const { return TabbableWidget::StateNone; } int TabbableWidget::unreadMessageCount() const { return 0; } /** * Use this to invalidate tab state. */ void TabbableWidget::invalidateTab() { setWindowTitle(desiredCaption()); emit invalidateTabInfo(); } PsiAccount* TabbableWidget::account() const { return pa_; } void TabbableWidget::changeEvent(QEvent* event) { AdvancedWidget::changeEvent(event); if (event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowStateChange) { if (isActiveTab()) { activated(); } else { deactivated(); } } } psi-0.14/src/tabs/tabdlg.h0000644000175000017500000001100011305557613013457 0ustar janjan/* * tabdlg.h - dialog for handling tabbed chats * Copyright (C) 2005 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TABDLG_H #define TABDLG_H #include #include #include #include #include "advwidget.h" #include "tabbablewidget.h" class PsiCon; class ChatTabs; class ChatDlg; class QPushButton; class QMenu; class QString; class QContextMenuEvent; class PsiTabWidget; class TabManager; class TabDlg; class TabDlgDelegate : public QObject { Q_OBJECT public: TabDlgDelegate(QObject *parent = 0); ~TabDlgDelegate(); virtual Qt::WindowFlags initWindowFlags() const; virtual void create(QWidget *widget); virtual void destroy(QWidget *widget); virtual void tabWidgetCreated(QWidget *widget, PsiTabWidget *tabWidget); virtual bool paintEvent(QWidget *widget, QPaintEvent *event); virtual bool resizeEvent(QWidget *widget, QResizeEvent *event); virtual bool mousePressEvent(QWidget *widget, QMouseEvent *event); virtual bool mouseMoveEvent(QWidget *widget, QMouseEvent *event); virtual bool mouseReleaseEvent(QWidget *widget, QMouseEvent *event); virtual bool changeEvent(QWidget *widget, QEvent *event); virtual bool event(QWidget *widget, QEvent *event); virtual bool eventFilter(QWidget *widget, QObject *obj, QEvent *event); }; class TabDlg : public AdvancedWidget { Q_OBJECT public: TabDlg(TabManager* tabManager, QSize size, TabDlgDelegate *delegate = 0); ~TabDlg(); bool managesTab(const TabbableWidget*) const; bool tabOnTop(const TabbableWidget*) const; TabbableWidget *getTab(int i) const; void removeTabWithNoChecks(TabbableWidget *tab); TabbableWidget* getTabPointer(QString fullJid); virtual QString desiredCaption() const; QString captionForTab(TabbableWidget* tab) const; int tabCount() const; void setUserManagementEnabled(bool enabled); // default enabled void setTabBarShownForSingles(bool enabled); // default enabled void setSimplifiedCaptionEnabled(bool enabled); // default disabled protected: void setShortcuts(); // reimplemented void closeEvent(QCloseEvent*); void changeEvent(QEvent *event); void resizeEvent(QResizeEvent *); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); // delegate-only virtual void paintEvent(QPaintEvent *event); virtual void mousePressEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual bool event(QEvent *event); virtual bool eventFilter(QObject *obj, QEvent *event); protected slots: void detachCurrentTab(); void mouseDoubleClickTab(QWidget*); public slots: void addTab(TabbableWidget *tab); void setLooks(); void closeCurrentTab(); void closeTab(TabbableWidget*, bool doclose = true); void selectTab(TabbableWidget*); void activated(); void optionsUpdate(); void detachTab(TabbableWidget*); void sendTabTo(TabbableWidget*, TabDlg *); signals: void resized(QSize size); private slots: void updateFlashState(); void tabSelected(QWidget* selected); void checkHasChats(); void updateTab(); void updateTab(TabbableWidget*); void nextTab(); void previousTab(); void tab_aboutToShowMenu(QMenu *menu); void setAsDefaultForChat(); void setAsDefaultForMuc(); void menu_sendTabTo(QAction *act); void queuedSendTabTo(TabbableWidget* chat, TabDlg *dest); void showTabMenu(int tab, QPoint pos, QContextMenuEvent * event); private: TabDlgDelegate *delegate_; QList tabs_; PsiTabWidget *tabWidget_; QPushButton *detachButton_; QPushButton *closeButton_; QPushButton *closeCross_; QMenu *tabMenu_; QAction *act_close_; QAction *act_next_; QAction *act_prev_; TabManager *tabManager_; QPointer selectedTab_; bool userManagement_; bool tabBarSingles_; bool simplifiedCaption_; QSize chatSize_; void extinguishFlashingTabs(); void updateCaption(); void updateTabBar(); }; #endif psi-0.14/src/tabs/tabdlg.cpp0000644000175000017500000004422311305557613014027 0ustar janjan/* * tabdlg.cpp - dialog for handling tabbed chats * Copyright (C) 2005 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "tabdlg.h" #include "iconwidget.h" #include "iconset.h" #include "psicon.h" #include #include #include #include #include #include #include #include #include "psitabwidget.h" #include "psioptions.h" #include "shortcutmanager.h" #include "chatdlg.h" #include "tabmanager.h" #ifdef Q_WS_WIN #include #endif //---------------------------------------------------------------------------- // TabDlgDelegate //---------------------------------------------------------------------------- TabDlgDelegate::TabDlgDelegate(QObject *parent) : QObject(parent) { } TabDlgDelegate::~TabDlgDelegate() { } Qt::WindowFlags TabDlgDelegate::initWindowFlags() const { return (Qt::WindowFlags)0; } void TabDlgDelegate::create(QWidget *) { } void TabDlgDelegate::destroy(QWidget *) { } void TabDlgDelegate::tabWidgetCreated(QWidget *, PsiTabWidget *) { } bool TabDlgDelegate::paintEvent(QWidget *, QPaintEvent *) { return false; } bool TabDlgDelegate::resizeEvent(QWidget *, QResizeEvent *) { return false; } bool TabDlgDelegate::mousePressEvent(QWidget *, QMouseEvent *) { return false; } bool TabDlgDelegate::mouseMoveEvent(QWidget *, QMouseEvent *) { return false; } bool TabDlgDelegate::mouseReleaseEvent(QWidget *, QMouseEvent *) { return false; } bool TabDlgDelegate::changeEvent(QWidget *, QEvent *) { return false; } bool TabDlgDelegate::event(QWidget *, QEvent *) { return false; } bool TabDlgDelegate::eventFilter(QWidget *, QObject *, QEvent *) { return false; } //---------------------------------------------------------------------------- // TabDlg //---------------------------------------------------------------------------- /** * Constructs a TabDlg * * \param tabManager The tabManager that will manage this TabDlg * \param delegate If non-zero, this is a pointer to a TabDlgDelegate that * will manage some aspects of the TabDlg behavior. Ownership is not * passed. */ TabDlg::TabDlg(TabManager* tabManager, QSize size, TabDlgDelegate *delegate) : AdvancedWidget(0, delegate ? delegate->initWindowFlags() : (Qt::WindowFlags)0) , delegate_(delegate) , tabWidget_(0) , detachButton_(0) , closeButton_(0) , closeCross_(0) , tabMenu_(new QMenu(this)) , act_close_(0) , act_next_(0) , act_prev_(0) , tabManager_(tabManager) , userManagement_(true) , tabBarSingles_(true) , simplifiedCaption_(false) { if (delegate_) { delegate_->create(this); } if (PsiOptions::instance()->getOption("options.ui.mac.use-brushed-metal-windows").toBool()) { setAttribute(Qt::WA_MacMetalStyle); } // FIXME qRegisterMetaType("TabDlg*"); qRegisterMetaType("TabbableWidget*"); tabWidget_ = new PsiTabWidget(this); tabWidget_->setCloseIcon(IconsetFactory::icon("psi/closetab").icon()); connect(tabWidget_, SIGNAL(mouseDoubleClickTab(QWidget*)), SLOT(mouseDoubleClickTab(QWidget*))); connect(tabWidget_, SIGNAL(aboutToShowMenu(QMenu*)), SLOT(tab_aboutToShowMenu(QMenu*))); connect(tabWidget_, SIGNAL(tabContextMenu(int, QPoint, QContextMenuEvent*)), SLOT(showTabMenu(int, QPoint, QContextMenuEvent*))); connect(tabWidget_, SIGNAL(closeButtonClicked()), SLOT(closeCurrentTab())); connect(tabWidget_, SIGNAL(currentChanged(QWidget*)), SLOT(tabSelected(QWidget*))); if(delegate_) delegate_->tabWidgetCreated(this, tabWidget_); QVBoxLayout *vert1 = new QVBoxLayout(this); vert1->setMargin(1); vert1->addWidget(tabWidget_); setAcceptDrops(true); X11WM_CLASS("tabs"); setLooks(); act_close_ = new QAction(this); addAction(act_close_); connect(act_close_,SIGNAL(triggered()), SLOT(closeCurrentTab())); act_prev_ = new QAction(this); addAction(act_prev_); connect(act_prev_,SIGNAL(triggered()), SLOT(previousTab())); act_next_ = new QAction(this); addAction(act_next_); connect(act_next_,SIGNAL(triggered()), SLOT(nextTab())); setShortcuts(); if (size.isValid()) { resize(size); } else { resize(ChatDlg::defaultSize()); //TODO: no! } } TabDlg::~TabDlg() { // TODO: make sure that TabDlg is properly closed and its closeEvent() is invoked, // so it could cancel an application quit // Q_ASSERT(tabs_.isEmpty()); // ensure all tabs are closed at this moment foreach(TabbableWidget* tab, tabs_) { delete tab; } if (delegate_) { delegate_->destroy(this); } } // FIXME: This is a bad idea to store pointers in QMimeData Q_DECLARE_METATYPE(TabDlg*); Q_DECLARE_METATYPE(TabbableWidget*); void TabDlg::setShortcuts() { act_close_->setShortcuts(ShortcutManager::instance()->shortcuts("common.close")); act_prev_->setShortcuts(ShortcutManager::instance()->shortcuts("chat.previous-tab")); act_next_->setShortcuts(ShortcutManager::instance()->shortcuts("chat.next-tab")); } void TabDlg::resizeEvent(QResizeEvent *e) { AdvancedWidget::resizeEvent(e); emit resized(e->size()); // delegate may want to act on resize event if (delegate_) { delegate_->resizeEvent(this, e); } } void TabDlg::showTabMenu(int tab, QPoint pos, QContextMenuEvent * event) { Q_UNUSED(event); tabMenu_->clear(); if (tab != -1) { QAction *d = 0; if(userManagement_) { d = tabMenu_->addAction(tr("Detach Tab")); } QAction *c = tabMenu_->addAction(tr("Close Tab")); QMap sentTos; if(userManagement_) { QMenu* sendTo = new QMenu(tabMenu_); sendTo->setTitle(tr("Send Tab To")); foreach(TabDlg* tabSet, tabManager_->tabSets()) { QAction *act = sendTo->addAction(tabSet->desiredCaption()); if (tabSet == this) act->setEnabled(false); sentTos[act] = tabSet; } tabMenu_->addMenu(sendTo); } QAction *act = tabMenu_->exec(pos); if (!act) return; if (act == c) { closeTab(getTab(tab)); } else if (act == d) { detachTab(getTab(tab)); } else { TabDlg* target = sentTos[act]; if (target) queuedSendTabTo(getTab(tab), target); } } } void TabDlg::tab_aboutToShowMenu(QMenu *menu) { menu->addSeparator(); menu->addAction(tr("Detach Current Tab"), this, SLOT(detachCurrentTab())); menu->addAction(tr("Close Current Tab"), this, SLOT(closeCurrentTab())); QMenu* sendTo = new QMenu(menu); sendTo->setTitle(tr("Send Current Tab To")); int tabDlgMetaType = qRegisterMetaType("TabDlg*"); foreach(TabDlg* tabSet, tabManager_->tabSets()) { QAction *act = sendTo->addAction(tabSet->desiredCaption()); act->setData(QVariant(tabDlgMetaType, &tabSet)); act->setEnabled(tabSet != this); } connect(sendTo, SIGNAL(triggered(QAction*)), SLOT(menu_sendTabTo(QAction*))); menu->addMenu(sendTo); menu->addSeparator(); QAction *act; act = menu->addAction(tr("Use for New Chats"), this, SLOT(setAsDefaultForChat())); act->setCheckable(true); act->setChecked(tabManager_->preferredTabsForKind('C') == this); act = menu->addAction(tr("Use for New Mucs"), this, SLOT(setAsDefaultForMuc())); act->setCheckable(true); act->setChecked(tabManager_->preferredTabsForKind('M') == this); } void TabDlg::setAsDefaultForChat() { tabManager_->setPreferredTabsForKind('C', this); } void TabDlg::setAsDefaultForMuc() { tabManager_->setPreferredTabsForKind('M', this); } void TabDlg::menu_sendTabTo(QAction *act) { queuedSendTabTo(static_cast(tabWidget_->currentPage()), act->data().value()); } void TabDlg::sendTabTo(TabbableWidget* tab, TabDlg* otherTabs) { Q_ASSERT(otherTabs); if (otherTabs == this) return; closeTab(tab, false); otherTabs->addTab(tab); } void TabDlg::queuedSendTabTo(TabbableWidget* tab, TabDlg *dest) { Q_ASSERT(tab); Q_ASSERT(dest); QMetaObject::invokeMethod(this, "sendTabTo", Qt::QueuedConnection, Q_ARG(TabbableWidget*, tab), Q_ARG(TabDlg*, dest)); } void TabDlg::optionsUpdate() { setShortcuts(); } void TabDlg::setLooks() { //set the widget icon #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/start-chat").icon()); #endif tabWidget_->setTabPosition(QTabWidget::North); if (PsiOptions::instance()->getOption("options.ui.tabs.put-tabs-at-bottom").toBool()) tabWidget_->setTabPosition(QTabWidget::South); setWindowOpacity(double(qMax(MINIMUM_OPACITY,PsiOptions::instance()->getOption("options.ui.chat.opacity").toInt()))/100); } void TabDlg::tabSelected(QWidget* _selected) { // _selected could be null when TabDlg is closing and deleting all its tabs TabbableWidget* selected = _selected ? qobject_cast(_selected) : 0; if (!selectedTab_.isNull()) { selectedTab_->deactivated(); } selectedTab_ = selected; if (selected) { selected->activated(); } updateCaption(); } bool TabDlg::managesTab(const TabbableWidget* tab) const { return tabs_.contains(const_cast(tab)); } bool TabDlg::tabOnTop(const TabbableWidget* tab) const { return tabWidget_->currentPage() == tab; } void TabDlg::addTab(TabbableWidget* tab) { setUpdatesEnabled(false); tabs_.append(tab); tabWidget_->addTab(tab, captionForTab(tab)); connect(tab, SIGNAL(invalidateTabInfo()), SLOT(updateTab())); connect(tab, SIGNAL(updateFlashState()), SLOT(updateFlashState())); this->showWithoutActivation(); updateTab(tab); setUpdatesEnabled(true); } void TabDlg::detachCurrentTab() { detachTab(static_cast(tabWidget_->currentPage())); } void TabDlg::mouseDoubleClickTab(QWidget* widget) { if(userManagement_) detachTab(static_cast(widget)); } void TabDlg::detachTab(TabbableWidget* tab) { if (tabWidget_->count() == 1 || !tab) return; TabDlg *newTab = tabManager_->newTabs(tab); sendTabTo(tab, newTab); } /** * Call this when you want a tab to be removed immediately with no readiness checks * or reparenting, hiding etc (Such as on tab destruction). */ void TabDlg::removeTabWithNoChecks(TabbableWidget *tab) { disconnect(tab, SIGNAL(invalidateTabInfo()), this, SLOT(updateTab())); disconnect(tab, SIGNAL(updateFlashState()), this, SLOT(updateFlashState())); tabs_.removeAll(tab); tabWidget_->removePage(tab); checkHasChats(); } /** * Removes the chat from the tabset, 'closing' it if specified. * The method is used without closing tabs when transferring from one * tabset to another. * \param chat Chat to remove. * \param doclose Whether the chat is 'closed' while removing it. */ void TabDlg::closeTab(TabbableWidget* chat, bool doclose) { if (!chat || (doclose && !chat->readyToHide())) { return; } setUpdatesEnabled(false); chat->hide(); removeTabWithNoChecks(chat); chat->setParent(0); if (tabWidget_->count() > 0) { updateCaption(); } //moved to NoChecks //checkHasChats(); if (doclose && chat->testAttribute(Qt::WA_DeleteOnClose)) { chat->close(); } setUpdatesEnabled(true); } void TabDlg::selectTab(TabbableWidget* chat) { setUpdatesEnabled(false); tabWidget_->showPage(chat); setUpdatesEnabled(true); } void TabDlg::checkHasChats() { if (tabWidget_->count() > 0) return; deleteLater(); } void TabDlg::activated() { updateCaption(); extinguishFlashingTabs(); } QString TabDlg::desiredCaption() const { QString cap = ""; uint pending = 0; foreach(TabbableWidget* tab, tabs_) { pending += tab->unreadMessageCount(); } if (pending > 0) { cap += "* "; if (!simplifiedCaption_ && pending > 1) { cap += QString("[%1] ").arg(pending); } } if (tabWidget_->currentPage()) { if (simplifiedCaption_ && tabs_.count() > 1) { cap += tr("%1 Conversations").arg(tabs_.count()); } else { cap += qobject_cast(tabWidget_->currentPage())->getDisplayName(); if (qobject_cast(tabWidget_->currentPage())->state() == TabbableWidget::StateComposing) { cap += tr(" is composing"); } } } return cap; } void TabDlg::updateCaption() { setWindowTitle(desiredCaption()); // FIXME: this probably shouldn't be in here, but it works easily updateTabBar(); } void TabDlg::closeEvent(QCloseEvent* closeEvent) { foreach(TabbableWidget* tab, tabs_) { if (!tab->readyToHide()) { closeEvent->ignore(); return; } } foreach(TabbableWidget* tab, tabs_) { closeTab(tab); } } TabbableWidget *TabDlg::getTab(int i) const { return static_cast(tabWidget_->page(i)); } TabbableWidget* TabDlg::getTabPointer(QString fullJid) { foreach(TabbableWidget* tab, tabs_) { if (tab->jid().full() == fullJid) { return tab; } } return 0; } void TabDlg::updateTab() { TabbableWidget *tab = qobject_cast(sender()); updateTab(tab); } QString TabDlg::captionForTab(TabbableWidget* tab) const { QString label, prefix; if (!tab->unreadMessageCount()) { prefix = ""; } else if (tab->unreadMessageCount() == 1) { prefix = "* "; } else { prefix = QString("[%1] ").arg(tab->unreadMessageCount()); } label = prefix + tab->getDisplayName(); label.replace("&", "&&"); return label; } void TabDlg::updateTab(TabbableWidget* chat) { tabWidget_->setTabText(chat, captionForTab(chat)); //now set text colour based upon whether there are new messages/composing etc if (chat->state() == TabbableWidget::StateComposing) { tabWidget_->setTabTextColor(chat, Qt::darkGreen); } else if (chat->unreadMessageCount()) { tabWidget_->setTabTextColor(chat, Qt::red); } else { tabWidget_->setTabTextColor(chat, palette().windowText().color()); } updateCaption(); } void TabDlg::nextTab() { int page = tabWidget_->currentPageIndex()+1; if ( page >= tabWidget_->count() ) page = 0; tabWidget_->setCurrentPage( page ); } void TabDlg::previousTab() { int page = tabWidget_->currentPageIndex()-1; if ( page < 0 ) page = tabWidget_->count() - 1; tabWidget_->setCurrentPage( page ); } void TabDlg::closeCurrentTab() { closeTab(static_cast(tabWidget_->currentPage())); } void TabDlg::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat(PSITABDRAGMIMETYPE)) { event->setDropAction(Qt::MoveAction); event->accept(); } } void TabDlg::dropEvent(QDropEvent *event) { if (!event->mimeData()->hasFormat(PSITABDRAGMIMETYPE)) { return; } QByteArray data = event->mimeData()->data(PSITABDRAGMIMETYPE); int remoteTab = data.toInt(); event->acceptProposedAction(); //the event's been and gone, now do something about it PsiTabBar* source = dynamic_cast(event->source()); if (source) { PsiTabWidget* barParent = source->psiTabWidget(); if (remoteTab >= barParent->count()) return; QWidget* widget = barParent->widget(remoteTab); TabbableWidget* chat = dynamic_cast(widget); TabDlg *dlg = tabManager_->getManagingTabs(chat); if (!chat || !dlg) return; dlg->queuedSendTabTo(chat, this); } } void TabDlg::extinguishFlashingTabs() { foreach(TabbableWidget* tab, tabs_) { if (tab->flashing()) { tab->blockSignals(true); tab->doFlash(false); tab->blockSignals(false); } } updateFlashState(); } void TabDlg::updateFlashState() { bool flash = false; foreach(TabbableWidget* tab, tabs_) { if (tab->flashing()) { flash = true; break; } } flash = flash && !isActiveWindow(); doFlash(flash); } void TabDlg::paintEvent(QPaintEvent *event) { // delegate if possible, otherwise use default if (delegate_ && delegate_->paintEvent(this, event)) { return; } else { AdvancedWidget::paintEvent(event); } } void TabDlg::mousePressEvent(QMouseEvent *event) { // delegate if possible, otherwise use default if (delegate_ && delegate_->mousePressEvent(this, event)) { return; } else { AdvancedWidget::mousePressEvent(event); } } void TabDlg::mouseMoveEvent(QMouseEvent *event) { // delegate if possible, otherwise use default if (delegate_ && delegate_->mouseMoveEvent(this, event)) { return; } else { AdvancedWidget::mouseMoveEvent(event); } } void TabDlg::mouseReleaseEvent(QMouseEvent *event) { // delegate if possible, otherwise use default if (delegate_ && delegate_->mouseReleaseEvent(this, event)) { return; } else { AdvancedWidget::mouseReleaseEvent(event); } } void TabDlg::changeEvent(QEvent *event) { if (event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowStateChange) { if (tabWidget_->currentPage()) { QCoreApplication::sendEvent(tabWidget_->currentPage(), event); } if (isActiveWindow()) { activated(); } } // delegate if possible, otherwise use default if (delegate_ && delegate_->changeEvent(this, event)) { return; } else { AdvancedWidget::changeEvent(event); } } bool TabDlg::event(QEvent *event) { // delegate if possible, otherwise use default if (delegate_ && delegate_->event(this, event)) { return true; } else { return AdvancedWidget::event(event); } } bool TabDlg::eventFilter(QObject *obj, QEvent *event) { // delegate if possible, otherwise use default if (delegate_ && delegate_->eventFilter(this, obj, event)) { return true; } else { return AdvancedWidget::eventFilter(obj, event); } } int TabDlg::tabCount() const { return tabs_.count(); } void TabDlg::setUserManagementEnabled(bool enabled) { if (userManagement_ == enabled) { return; } userManagement_ = enabled; tabWidget_->setTabButtonsShown(enabled); tabWidget_->setDragsEnabled(enabled); } void TabDlg::setTabBarShownForSingles(bool enabled) { if (tabBarSingles_ == enabled) { return; } tabBarSingles_ = enabled; updateTabBar(); } void TabDlg::updateTabBar() { if (tabBarSingles_) { tabWidget_->setTabBarShown(true); } else { if (tabWidget_->count() > 1) tabWidget_->setTabBarShown(true); else tabWidget_->setTabBarShown(false); } } void TabDlg::setSimplifiedCaptionEnabled(bool enabled) { if (simplifiedCaption_ == enabled) { return; } simplifiedCaption_ = enabled; updateCaption(); } psi-0.14/src/tabs/tabs.pri0000644000175000017500000000040011305557613013520 0ustar janjanINCLUDEPATH *= $$PWD DEPENDPATH *= $$PWD HEADERS += $$PWD/tabdlg.h HEADERS += $$PWD/tabmanager.h HEADERS += $$PWD/tabbablewidget.h SOURCES += $$PWD/tabdlg.cpp SOURCES += $$PWD/tabmanager.cpp SOURCES += $$PWD/tabbablewidget.cpp #INTERFACES += $$PWD/.ui psi-0.14/src/tabs/tabmanager.cpp0000644000175000017500000001216711305557613014675 0ustar janjan#include "tabmanager.h" #include #include "tabdlg.h" #include "tabbablewidget.h" #include "groupchatdlg.h" #include "chatdlg.h" #include "psioptions.h" TabManager::TabManager(PsiCon* psiCon, QObject *parent) : QObject(parent) , psiCon_(psiCon) , tabDlgDelegate_(0) , userManagement_(true) , tabSingles_(true) , simplifiedCaption_(false) { } TabManager::~TabManager() { deleteAll(); } PsiCon* TabManager::psiCon() const { return psiCon_; } TabDlg* TabManager::getTabs(QWidget *widget) { QChar kind = tabKind(widget); if (preferedTabsetForKind_.contains(kind)) { return preferedTabsetForKind_[kind]; } else { return newTabs(widget); } } QChar TabManager::tabKind(QWidget *widget) { QChar retval = 0; if (qobject_cast (widget)) { retval = 'C'; } else if (qobject_cast (widget)) { retval = 'M'; } else { qDebug("Checking if widget should be tabbed: Unknown type"); } return retval; } bool TabManager::shouldBeTabbed(QWidget *widget) { if (!PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool()) { return false; } QString grouping = PsiOptions::instance()->getOption("options.ui.tabs.grouping").toString(); if (grouping.contains(tabKind(widget))) { return true; } return false; } void TabManager::tabResized(QSize size) { if (PsiOptions::instance()->getOption("options.ui.remember-window-sizes").toBool()) { PsiOptions::instance()->mapPut("options.ui.tabs.group-state", tabsetToKinds_[static_cast(sender())], "size", size); } } TabDlg* TabManager::newTabs(QWidget *widget) { QChar kind = tabKind(widget); QString group, grouping = PsiOptions::instance()->getOption("options.ui.tabs.grouping").toString(); foreach(QString g, grouping.split(':')) { if (g.contains(kind)) { group = g; break; } } QVariantList savedSizes = PsiOptions::instance()->mapKeyList("options.ui.tabs.group-state"); QSize size = PsiOptions::instance()->getOption("options.ui.tabs.size").toSize(); if (savedSizes.contains(group)) { size = PsiOptions::instance()->mapGet("options.ui.tabs.group-state", group, "size").toSize(); } else { foreach(QVariant v, savedSizes) { if (v.toString().contains(kind)) { size = PsiOptions::instance()->mapGet("options.ui.tabs.group-state", v.toString(), "size").toSize(); } } } TabDlg *tab = new TabDlg(this, size, tabDlgDelegate_); tab->setUserManagementEnabled(userManagement_); tab->setTabBarShownForSingles(tabSingles_); tab->setSimplifiedCaptionEnabled(simplifiedCaption_); tabsetToKinds_.insert(tab, group); for (int i=0; i < group.length(); i++) { QChar k = group.at(i); if (!preferedTabsetForKind_.contains(k)) { preferedTabsetForKind_.insert(k, tab); } } tabs_.append(tab); connect(tab, SIGNAL(destroyed(QObject*)), SLOT(tabDestroyed(QObject*))); connect(tab, SIGNAL(resized(QSize)), SLOT(tabResized(QSize))); connect(psiCon_, SIGNAL(emitOptionsUpdate()), tab, SLOT(optionsUpdate())); return tab; } void TabManager::tabDestroyed(QObject* obj) { Q_ASSERT(tabs_.contains(static_cast(obj))); tabs_.removeAll(static_cast(obj)); tabsetToKinds_.remove(static_cast(obj)); QMutableMapIterator it(preferedTabsetForKind_); while (it.hasNext()) { it.next(); if (preferedTabsetForKind_[it.key()] != obj) continue; bool ok = false; foreach(TabDlg* tabDlg, tabs_) { // currently destroyed tab is removed from the list a few lines above if (tabsetToKinds_[tabDlg].contains(it.key())) { preferedTabsetForKind_[it.key()] = tabDlg; ok = true; break; } } if (!ok) it.remove(); } } TabDlg *TabManager::preferredTabsForKind(QChar kind) { return preferedTabsetForKind_.value(kind); } void TabManager::setPreferredTabsForKind(QChar kind, TabDlg *tab) { Q_ASSERT(tabs_.contains(tab)); preferedTabsetForKind_[kind] = tab; } bool TabManager::isChatTabbed(const TabbableWidget* chat) const { foreach(TabDlg* tabDlg, tabs_) { if (tabDlg->managesTab(chat)) { return true; } } return false; } TabDlg* TabManager::getManagingTabs(const TabbableWidget* chat) const { //FIXME: this looks like it could be broken to me (KIS) //Does this mean that opening two chats to the same jid will go wrong? foreach(TabDlg* tabDlg, tabs_) { if (tabDlg->managesTab(chat)) { return tabDlg; } } return 0; } const QList& TabManager::tabSets() { return tabs_; } void TabManager::deleteAll() { qDeleteAll(tabs_); tabs_.clear(); } void TabManager::setTabDlgDelegate(TabDlgDelegate *delegate) { tabDlgDelegate_ = delegate; } void TabManager::setUserManagementEnabled(bool enabled) { if (userManagement_ == enabled) { return; } userManagement_ = enabled; foreach (TabDlg *tab, tabs_) { tab->setUserManagementEnabled(enabled); } } void TabManager::setTabBarShownForSingles(bool enabled) { if (tabSingles_ == enabled) { return; } tabSingles_ = enabled; foreach (TabDlg *tab, tabs_) { tab->setTabBarShownForSingles(enabled); } } void TabManager::setSimplifiedCaptionEnabled(bool enabled) { if (simplifiedCaption_ == enabled) { return; } simplifiedCaption_ = enabled; foreach (TabDlg *tab, tabs_) { tab->setSimplifiedCaptionEnabled(enabled); } } psi-0.14/src/tabs/tabmanager.h0000644000175000017500000000610611305557613014336 0ustar janjan/* * tabmanager.h - Controller for tab dialogs. * Copyright (C) 2007 Kevin 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _TABMANAGER_H_ #define _TABMANAGER_H_ #include #include #include "psicon.h" class TabbableWidget; class TabDlg; class TabDlgDelegate; class TabManager : public QObject { Q_OBJECT public: TabManager(PsiCon *psiCon, QObject *parent = 0); ~TabManager(); PsiCon* psiCon() const; /** * Get the default tabset for this widget (created if needed). */ TabDlg* getTabs(QWidget *widget); /** * Return a new tabset (for this widget). */ TabDlg* newTabs(QWidget *widget=0); /** * Checks if a tabset manages this widget. */ bool isChatTabbed(const TabbableWidget*) const; /** * Returns the tab dialog that owns the supplied widget. */ TabDlg* getManagingTabs(const TabbableWidget*) const; /** * Returns all active tabsets (could be empty). */ const QList& tabSets(); /** * Checks if a given widget should be in a tabset * (depends on set options and widget type). */ bool shouldBeTabbed(QWidget *widget); /** * removes and deletes all tabsets */ void deleteAll(); /** * Returns the Kind of the given widget. */ QChar tabKind(QWidget *widget); /** * return the preferred tabset for a given kind of tabs(0 for none). */ TabDlg *preferredTabsForKind(QChar kind); /** * set the preferred tabset for a given kind of tabs */ void setPreferredTabsForKind(QChar kind, TabDlg *tabs); /** * set the delegate to be used for all created TabDlgs */ void setTabDlgDelegate(TabDlgDelegate *delegate); /** * enable/disable user dragging/detach/assignment of tabs * * the default is enabled */ void setUserManagementEnabled(bool enabled); /** * enable/disable display of PsiTabBar when there is only one tab * * the default is enabled */ void setTabBarShownForSingles(bool enabled); /** * enable/disable simplified caption mode * * the default is disabled */ void setSimplifiedCaptionEnabled(bool enabled); public slots: void tabDestroyed(QObject*); void tabResized(QSize); private: QMap preferedTabsetForKind_; QMap tabsetToKinds_; QList tabs_; QList tabControlledChats_; PsiCon *psiCon_; TabDlgDelegate *tabDlgDelegate_; bool userManagement_; bool tabSingles_; bool simplifiedCaption_; }; #endif /* _TABMANAGER_H_ */ psi-0.14/src/privacy/0000755000175000017500000000000011305557613012605 5ustar janjanpsi-0.14/src/privacy/privacyruledlg.cpp0000644000175000017500000000712411305557613016351 0ustar janjan/* * privacyruledlg.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "privacyruledlg.h" #include "privacylistitem.h" PrivacyRuleDlg::PrivacyRuleDlg() { ui_.setupUi(this); ui_.cb_action->addItem(tr("Deny"), PrivacyListItem::Deny); ui_.cb_action->addItem(tr("Allow"), PrivacyListItem::Allow); ui_.cb_type->addItem(tr("JID"), PrivacyListItem::JidType); ui_.cb_type->addItem(tr("Group"), PrivacyListItem::GroupType); ui_.cb_type->addItem(tr("Subscription"), PrivacyListItem::SubscriptionType); ui_.cb_type->addItem(tr("*"), PrivacyListItem::FallthroughType); connect(ui_.cb_type,SIGNAL(currentIndexChanged(const QString&)),SLOT(type_selected(const QString&))); connect(ui_.pb_cancel,SIGNAL(clicked()),SLOT(reject())); connect(ui_.pb_ok,SIGNAL(clicked()),SLOT(accept())); } void PrivacyRuleDlg::setRule(const PrivacyListItem& item) { // Type if (item.type() == PrivacyListItem::SubscriptionType) { ui_.cb_type->setCurrentIndex(ui_.cb_type->findData(item.type())); ui_.cb_value->setCurrentIndex(ui_.cb_value->findData(item.value())); } else { ui_.cb_type->setCurrentIndex(ui_.cb_type->findData(item.type())); ui_.cb_value->setItemText(ui_.cb_value->currentIndex(), item.value()); } // Action ui_.cb_action->setCurrentIndex(ui_.cb_action->findData(item.action())); // Selection ui_.ck_messages->setChecked(item.message()); ui_.ck_queries->setChecked(item.iq()); ui_.ck_presenceIn->setChecked(item.presenceIn()); ui_.ck_presenceOut->setChecked(item.presenceOut()); } PrivacyListItem PrivacyRuleDlg::rule() const { PrivacyListItem item; // Type & value PrivacyListItem::Type t = (PrivacyListItem::Type)ui_.cb_type->itemData(ui_.cb_type->currentIndex()).toInt(); if(t == PrivacyListItem::SubscriptionType) { item.setType(t); item.setValue(ui_.cb_value->itemData(ui_.cb_value->currentIndex()).toString()); } else { item.setType(t); item.setValue(ui_.cb_value->currentText()); } // Action item.setAction((PrivacyListItem::Action)ui_.cb_action->itemData(ui_.cb_action->currentIndex()).toInt()); // Selection item.setMessage(ui_.ck_messages->isChecked()); item.setIQ(ui_.ck_queries->isChecked()); item.setPresenceIn(ui_.ck_presenceIn->isChecked()); item.setPresenceOut(ui_.ck_presenceOut->isChecked()); return item; } void PrivacyRuleDlg::type_selected(const QString& type) { ui_.cb_value->clear(); ui_.cb_value->setItemText(ui_.cb_value->currentIndex(), ""); PrivacyListItem::Type t = (PrivacyListItem::Type)ui_.cb_type->itemData(ui_.cb_type->currentIndex()).toInt(); if (t == PrivacyListItem::SubscriptionType) { ui_.cb_value->addItem(tr("None"), "none"); ui_.cb_value->addItem(tr("Both"), "both"); ui_.cb_value->addItem(tr("From"), "from"); ui_.cb_value->addItem(tr("To"), "to"); ui_.cb_value->setEditable(false); } else { ui_.cb_value->setEditable(true); } if (type == tr("*")) { ui_.cb_value->setEnabled(false); } else { ui_.cb_value->setEnabled(true); } } psi-0.14/src/privacy/privacylistmodel.h0000644000175000017500000000340711305557613016354 0ustar janjan/* * privacylistmodel.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYLISTMODEL_H #define PRIVACYLISTMODEL_H #include #include "privacylist.h" class QObject; class PrivacyListModel : public QAbstractListModel { public: enum { TextColumn = 0, ValueColumn }; enum { BlockedRole = Qt::UserRole + 0 }; PrivacyListModel(const PrivacyList& list = PrivacyList(""), QObject* parent = NULL); // Overridden from QAbstractListModel int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()); void reset() { QAbstractListModel::reset(); } // Not really clean // Own functions PrivacyList& list() { return list_; } void setList(const PrivacyList& list); bool moveUp(const QModelIndex& index); bool moveDown(const QModelIndex& index); bool edit(const QModelIndex& index); bool add(); private: PrivacyList list_; }; #endif psi-0.14/src/privacy/privacylistblockedmodel.h0000644000175000017500000000237211305557613017700 0ustar janjan/* * privacylistblockedmodel.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYLISTBLOCKEDMODEL #define PRIVACYLISTBLOCKEDMODEL #include class PrivacyListBlockedModel : public QSortFilterProxyModel { public: PrivacyListBlockedModel(QObject* parent = NULL); bool lessThan(const QModelIndex & left, const QModelIndex & right ) const; bool filterAcceptsColumn(int source_column, const QModelIndex & source_parent ) const; bool filterAcceptsRow(int source_row, const QModelIndex & source_parent ) const; }; #endif psi-0.14/src/privacy/privacymanager.h0000644000175000017500000000337311305557613015774 0ustar janjan/* * privacymanager.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYMANAGER_H #define PRIVACYMANAGER_H #include #include class QString; class PrivacyList; class PrivacyManager : public QObject { Q_OBJECT public: virtual void requestListNames() = 0; virtual void changeDefaultList(const QString& name) = 0; virtual void changeActiveList(const QString& name) = 0; virtual void changeList(const PrivacyList& list) = 0; virtual void getDefaultList() = 0; virtual void requestList(const QString& name) = 0; signals: void changeDefaultList_success(); void changeDefaultList_error(); void changeActiveList_success(); void changeActiveList_error(); void changeList_success(); void changeList_error(); void defaultListAvailable(const PrivacyList&); void defaultListError(); void listChangeSuccess(); void listChangeError(); void listReceived(const PrivacyList& p); void listError(); void listsReceived(const QString& defaultList, const QString& activeList, const QStringList& lists); void listsError(); }; #endif psi-0.14/src/privacy/unittest/0000755000175000017500000000000011305557613014464 5ustar janjanpsi-0.14/src/privacy/unittest/unittest.pri0000644000175000017500000000005411305557613017056 0ustar janjanSOURCES += \ $$PWD/privacylistitemtest.cpp psi-0.14/src/privacy/unittest/privacylistitemtest.cpp0000644000175000017500000001716211305557613021327 0ustar janjan/** * Copyright (C) 2007, Remko Troncon */ #include #include #include #include #include "unittestutil.h" #include "privacylistitem.h" class PrivacyListItemTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PrivacyListItemTest); CPPUNIT_TEST(testFromXml_JidType); CPPUNIT_TEST(testFromXml_GroupType); CPPUNIT_TEST(testFromXml_SubscriptionType); CPPUNIT_TEST(testFromXml_NoType); CPPUNIT_TEST(testFromXml_AllowAction); CPPUNIT_TEST(testFromXml_DenyAction); CPPUNIT_TEST(testFromXml_Order); CPPUNIT_TEST(testFromXml_MessageChild); CPPUNIT_TEST(testFromXml_PresenceInChild); CPPUNIT_TEST(testFromXml_PresenceOutChild); CPPUNIT_TEST(testFromXml_IQChild); CPPUNIT_TEST(testFromXml_AllChildren); CPPUNIT_TEST(testFromXml_NoChildren); CPPUNIT_TEST(testToXml); CPPUNIT_TEST(testIsBlock); CPPUNIT_TEST(testIsBlock_NoBlock); CPPUNIT_TEST(testBlockItem); CPPUNIT_TEST_SUITE_END(); public: PrivacyListItemTest(); virtual ~PrivacyListItemTest(); void testFromXml_JidType(); void testFromXml_GroupType(); void testFromXml_SubscriptionType(); void testFromXml_NoType(); void testFromXml_AllowAction(); void testFromXml_DenyAction(); void testFromXml_Order(); void testFromXml_MessageChild(); void testFromXml_PresenceInChild(); void testFromXml_PresenceOutChild(); void testFromXml_IQChild(); void testFromXml_AllChildren(); void testFromXml_NoChildren(); void testToXml(); void testIsBlock(); void testIsBlock_NoBlock(); void testBlockItem(); PrivacyListItem createItem(); PrivacyListItem createItemFromXml(const QString&); PrivacyListItem createItemFromXmlWithTypeValue(const QString& type, const QString& value); PrivacyListItem createItemFromXmlWithoutType(); PrivacyListItem createItemFromXmlWithAction(const QString&); PrivacyListItem createItemFromXmlWithOrder(const QString&); PrivacyListItem createItemFromXmlWithChildren(const QStringList& children); }; CPPUNIT_TEST_SUITE_REGISTRATION(PrivacyListItemTest); // ----------------------------------------------------------------------------- PrivacyListItemTest::PrivacyListItemTest() { } PrivacyListItemTest::~PrivacyListItemTest() { } PrivacyListItem PrivacyListItemTest::createItemFromXml(const QString& xml) { QDomElement e = UnitTestUtil::createElement(xml); PrivacyListItem item; item.fromXml(e); return item; } PrivacyListItem PrivacyListItemTest::createItem() { return createItemFromXml(""); } PrivacyListItem PrivacyListItemTest::createItemFromXmlWithTypeValue(const QString& type, const QString& value) { return createItemFromXml(QString("").arg(type).arg(value)); } PrivacyListItem PrivacyListItemTest::createItemFromXmlWithAction(const QString& action) { return createItemFromXml(QString("").arg(action)); } PrivacyListItem PrivacyListItemTest::createItemFromXmlWithOrder(const QString& order) { return createItemFromXml(QString("").arg(order)); } PrivacyListItem PrivacyListItemTest::createItemFromXmlWithoutType() { return createItemFromXml(""); } PrivacyListItem PrivacyListItemTest::createItemFromXmlWithChildren(const QStringList& children) { QString xml(""); foreach(QString child, children) { xml += "<" + child + "/>"; } xml += ""; return createItemFromXml(xml); } // ----------------------------------------------------------------------------- void PrivacyListItemTest::testFromXml_JidType() { PrivacyListItem item = createItemFromXmlWithTypeValue("jid", "user@example.com"); CPPUNIT_ASSERT_EQUAL(PrivacyListItem::JidType, item.type()); CPPUNIT_ASSERT(QString("user@example.com") == item.value()); } void PrivacyListItemTest::testFromXml_GroupType() { PrivacyListItem item = createItemFromXmlWithTypeValue("group", "mygroup"); CPPUNIT_ASSERT_EQUAL(PrivacyListItem::GroupType, item.type()); CPPUNIT_ASSERT(QString("mygroup") == item.value()); } void PrivacyListItemTest::testFromXml_SubscriptionType() { PrivacyListItem item = createItemFromXmlWithTypeValue("subscription", "to"); CPPUNIT_ASSERT_EQUAL(PrivacyListItem::SubscriptionType, item.type()); CPPUNIT_ASSERT(QString("to") == item.value()); } void PrivacyListItemTest::testFromXml_NoType() { PrivacyListItem item = createItemFromXmlWithoutType(); CPPUNIT_ASSERT_EQUAL(PrivacyListItem::FallthroughType, item.type()); } void PrivacyListItemTest::testFromXml_AllowAction() { PrivacyListItem item = createItemFromXmlWithAction("allow"); CPPUNIT_ASSERT_EQUAL(PrivacyListItem::Allow, item.action()); } void PrivacyListItemTest::testFromXml_DenyAction() { PrivacyListItem item = createItemFromXmlWithAction("deny"); CPPUNIT_ASSERT_EQUAL(PrivacyListItem::Deny, item.action()); } void PrivacyListItemTest::testFromXml_Order() { PrivacyListItem item = createItemFromXmlWithOrder("13"); CPPUNIT_ASSERT_EQUAL(13U, item.order()); } void PrivacyListItemTest::testFromXml_MessageChild() { PrivacyListItem item = createItemFromXmlWithChildren(QStringList("message")); CPPUNIT_ASSERT(item.message()); CPPUNIT_ASSERT(!item.presenceIn()); CPPUNIT_ASSERT(!item.presenceOut()); CPPUNIT_ASSERT(!item.iq()); } void PrivacyListItemTest::testFromXml_PresenceInChild() { PrivacyListItem item = createItemFromXmlWithChildren(QStringList("presence-in")); CPPUNIT_ASSERT(!item.message()); CPPUNIT_ASSERT(item.presenceIn()); CPPUNIT_ASSERT(!item.presenceOut()); CPPUNIT_ASSERT(!item.iq()); } void PrivacyListItemTest::testFromXml_PresenceOutChild() { PrivacyListItem item = createItemFromXmlWithChildren(QStringList("presence-out")); CPPUNIT_ASSERT(!item.message()); CPPUNIT_ASSERT(!item.presenceIn()); CPPUNIT_ASSERT(item.presenceOut()); CPPUNIT_ASSERT(!item.iq()); } void PrivacyListItemTest::testFromXml_IQChild() { PrivacyListItem item = createItemFromXmlWithChildren(QStringList("iq")); CPPUNIT_ASSERT(!item.message()); CPPUNIT_ASSERT(!item.presenceIn()); CPPUNIT_ASSERT(!item.presenceOut()); CPPUNIT_ASSERT(item.iq()); } void PrivacyListItemTest::testFromXml_AllChildren() { QStringList children; children << "message" << "presence-in" << "presence-out" << "iq"; PrivacyListItem item = createItemFromXmlWithChildren(children); CPPUNIT_ASSERT(item.all()); CPPUNIT_ASSERT(item.message()); CPPUNIT_ASSERT(item.presenceIn()); CPPUNIT_ASSERT(item.presenceOut()); CPPUNIT_ASSERT(item.iq()); } void PrivacyListItemTest::testFromXml_NoChildren() { PrivacyListItem item = createItemFromXmlWithChildren(QStringList()); CPPUNIT_ASSERT(item.all()); CPPUNIT_ASSERT(item.message()); CPPUNIT_ASSERT(item.presenceIn()); CPPUNIT_ASSERT(item.presenceOut()); CPPUNIT_ASSERT(item.iq()); } void PrivacyListItemTest::testToXml() { PrivacyListItem item1 = createItem(); QDomDocument doc; QDomElement e = item1.toXml(doc); doc.appendChild(e); PrivacyListItem item2 = createItemFromXml(doc.toString()); CPPUNIT_ASSERT(item1 == item2); } void PrivacyListItemTest::testIsBlock() { PrivacyListItem item = createItemFromXml(""); CPPUNIT_ASSERT(item.isBlock()); } void PrivacyListItemTest::testIsBlock_NoBlock() { PrivacyListItem item = createItemFromXml(""); CPPUNIT_ASSERT(!item.isBlock()); } void PrivacyListItemTest::testBlockItem() { PrivacyListItem item = PrivacyListItem::blockItem("me@example.com"); CPPUNIT_ASSERT(item.isBlock()); CPPUNIT_ASSERT("me@example.com" == item.value()); } psi-0.14/src/privacy/unittest/unittest.pro0000644000175000017500000000015511305557613017066 0ustar janjaninclude(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$MYMODULE) include(unittest.pri) psi-0.14/src/privacy/privacy.pri0000644000175000017500000000105711305557613015001 0ustar janjanINCLUDEPATH *= $$PWD DEPENDPATH *= $$PWD HEADERS += \ $$PWD/privacylistitem.h \ $$PWD/privacylist.h \ $$PWD/privacylistmodel.h \ $$PWD/privacylistblockedmodel.h \ $$PWD/privacymanager.h \ $$PWD/psiprivacymanager.h \ $$PWD/privacydlg.h \ $$PWD/privacyruledlg.h SOURCES += \ $$PWD/privacylistitem.cpp \ $$PWD/privacylist.cpp \ $$PWD/privacylistmodel.cpp \ $$PWD/privacylistblockedmodel.cpp \ $$PWD/psiprivacymanager.cpp \ $$PWD/privacydlg.cpp \ $$PWD/privacyruledlg.cpp INTERFACES += \ $$PWD/privacy.ui \ $$PWD/privacyrule.ui psi-0.14/src/privacy/privacylistmodel.cpp0000644000175000017500000000537211305557613016712 0ustar janjan/* * privacylistmodel.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "privacylist.h" #include "privacylistmodel.h" #include "privacyruledlg.h" PrivacyListModel::PrivacyListModel(const PrivacyList& list, QObject* parent) : QAbstractListModel(parent), list_(list) { } int PrivacyListModel::rowCount(const QModelIndex&) const { return list_.items().count(); } int PrivacyListModel::columnCount(const QModelIndex&) const { return 2; } QVariant PrivacyListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= list_.items().count()) return QVariant(); if (role == Qt::DisplayRole) { if (index.column() == TextColumn) return list_.item(index.row()).toString(); else if (index.column() == ValueColumn) return list_.item(index.row()).value(); } else if (role == BlockedRole) { return list_.item(index.row()).isBlock(); } return QVariant(); } void PrivacyListModel::setList(const PrivacyList& list) { list_ = list; reset(); } bool PrivacyListModel::moveUp(const QModelIndex& index) { if (index.isValid() && list_.moveItemUp(index.row())) { reset(); return true; } return false; } bool PrivacyListModel::moveDown(const QModelIndex& index) { if (index.isValid() && list_.moveItemDown(index.row())) { reset(); return true; } return false; } bool PrivacyListModel::removeRows(int row, int count, const QModelIndex&) { //qDebug("PrivacyListModel::removeRows"); beginRemoveRows(QModelIndex(), row, row+count-1); while(count > 0) { list_.removeItem(row); count--; } endRemoveRows(); return true; } bool PrivacyListModel::add() { PrivacyRuleDlg d; if (d.exec() == QDialog::Accepted) { list_.insertItem(0,d.rule()); reset(); return true; } return false; } bool PrivacyListModel::edit(const QModelIndex& index) { if (index.isValid()) { PrivacyRuleDlg d; d.setRule(list_.item(index.row())); if (d.exec() == QDialog::Accepted) { list_.updateItem(index.row(),d.rule()); reset(); return true; } } return false; } psi-0.14/src/privacy/privacy.ui0000644000175000017500000001447211305557613014631 0ustar janjan Privacy 0 0 733 562 Settings Qt::Horizontal 40 20 Qt::Horizontal 40 20 QComboBox::AdjustToContents Default List (all sessions): Active List (current session): QComboBox::AdjustToContents List Editor List: QComboBox::AdjustToContents Qt::Horizontal 40 20 New List Delete List Automatically activate this list on connect Rules Add Remove Up Down Edit ... Qt::Horizontal 111 20 Apply QDialogButtonBox::Close cb_active cb_default cb_lists pb_newList pb_deleteList ck_autoActivate lv_rules pb_add pb_remove pb_up pb_down pb_edit pb_apply psi-0.14/src/privacy/privacydlg.h0000644000175000017500000000375011305557613015127 0ustar janjan/* * privacydlg.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYDLG_H #define PRIVACYDLG_H #include #include #include "ui_privacy.h" #include "privacylistmodel.h" class QWidget; class QString; class QStringList; class PrivacyManager; class PrivacyDlg : public QDialog { Q_OBJECT public: PrivacyDlg(const QString&, PrivacyManager* manager, QWidget* parent = NULL); ~PrivacyDlg() { }; protected: void rememberSettings(); void revertSettings(); void listChanged(); protected slots: void setWidgetsEnabled(bool); void setEditRuleEnabled(bool); void updateLists(const QString&, const QString&, const QStringList&); void refreshList(const PrivacyList&); void active_selected(int); void default_selected(int); void list_selected(int i); void list_changed(int); void list_failed(); void changeList_succeeded(); void changeList_failed(); void change_succeeded(); void change_failed(); void close(); void addRule(); void editCurrentRule(); void removeCurrentRule(); void moveCurrentRuleUp(); void moveCurrentRuleDown(); void applyList(); void newList(); void removeList(); private: Ui::Privacy ui_; int previousActive_, previousDefault_, previousList_; QPointer manager_; PrivacyListModel model_; bool newList_; }; #endif psi-0.14/src/privacy/privacylist.h0000644000175000017500000000352111305557613015330 0ustar janjan/* * privacylist.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYLIST_H #define PRIVACYLIST_H #include #include #include "privacylistitem.h" class QDomElement; class QDomDocument; class PrivacyList { public: PrivacyList(const QString& name, const QList& items = QList()); PrivacyList(const QDomElement&); const QString& name() const { return name_; } void setName(const QString& name) { name_ = name; } bool isEmpty() const { return items_.isEmpty(); } void clear() { items_.clear(); } const QList& items() const { return items_; } const PrivacyListItem& item(int index) const { return items_.at(index); } void removeItem(int index) { items_.removeAt(index); } void insertItem(int index, const PrivacyListItem& item); bool moveItemUp(int index); bool moveItemDown(int index); bool onlyBlockItems() const; void updateItem(int index, const PrivacyListItem& item); QDomElement toXml(QDomDocument&) const; void fromXml(const QDomElement& e); QString toString() const; private: void reNumber(); QString name_; QList items_; }; #endif psi-0.14/src/privacy/privacylistitem.h0000644000175000017500000000513711305557613016214 0ustar janjan/* * privacylistitem.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYLISTITEM_H #define PRIVACYLISTITEM_H #include class QDomElement; class QDomDocument; class PrivacyListItem { public: typedef enum { FallthroughType, JidType, GroupType, SubscriptionType } Type; typedef enum { Allow, Deny } Action; PrivacyListItem(); PrivacyListItem(const QDomElement& e); Type type() const { return type_; } Action action() const { return action_; } bool message() const { return message_; } bool presenceIn() const { return presenceIn_; } bool presenceOut() const { return presenceOut_; } bool iq() const { return iq_; } bool all() const { return iq_ && presenceIn_ && presenceOut_ && message_; } const QString& value() const { return value_; } unsigned int order() const { return order_; } void setType(Type type) { type_ = type; } void setAction(Action action) { action_ = action; } void setMessage(bool b) { message_ = b; } void setPresenceIn(bool b) { presenceIn_ = b; } void setPresenceOut(bool b) { presenceOut_ = b; } void setIQ(bool b) { iq_ = b; } void setAll() { iq_ = presenceIn_ = presenceOut_ = message_ = true; } void setValue(const QString& value) { value_ = value; } void setOrder(unsigned int order) { order_ = order; } bool isBlock() const; QString toString() const; QDomElement toXml(QDomDocument&) const; void fromXml(const QDomElement& e); bool operator<(const PrivacyListItem& it) const { return order() < it.order(); } bool operator==(const PrivacyListItem& o) const { return type_ == o.type_ && action_ == o.action_ && message_ == o.message_ && presenceIn_ == o.presenceIn_ && presenceOut_ == o.presenceOut_ && iq_ == o.iq_ && order_ == o.order_ && value_ == o.value_; } static PrivacyListItem blockItem(const QString& jid); private: Type type_; Action action_; bool message_, presenceIn_, presenceOut_, iq_; unsigned int order_; QString value_; }; #endif psi-0.14/src/privacy/guitest/0000755000175000017500000000000011305557613014271 5ustar janjanpsi-0.14/src/privacy/guitest/guitest.pri0000644000175000017500000000024611305557613016473 0ustar janjanDEPENDPATH += $$PWD SOURCES += \ $$PWD/mockprivacymanager.cpp \ $$PWD/privacyruledlgtest.cpp \ $$PWD/privacydlgtest.cpp HEADERS += \ $$PWD/mockprivacymanager.h psi-0.14/src/privacy/guitest/privacyruledlgtest.cpp0000644000175000017500000000076511305557613020741 0ustar janjan#include "guitest.h" #include "guitestmanager.h" #include "privacyruledlg.h" #include class PrivacyRuleDlgTest : public GUITest { public: PrivacyRuleDlgTest(); QString name() { return "PrivacyRuleDlgTest"; } bool run(); }; PrivacyRuleDlgTest::PrivacyRuleDlgTest() { GUITestManager::instance()->registerTest(this); } bool PrivacyRuleDlgTest::run() { PrivacyRuleDlg dlg; dlg.exec(); return false; } static PrivacyRuleDlgTest* privacyRuleDlgTestInstance = new PrivacyRuleDlgTest(); psi-0.14/src/privacy/guitest/mockprivacymanager.h0000644000175000017500000000271411305557613020330 0ustar janjan/* * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MOCKPRIVACYMANAGER_H #define MOCKPRIVACYMANAGER_H #include #include #include "privacymanager.h" #include "privacylistitem.h" class MockPrivacyManager : public PrivacyManager { Q_OBJECT public: MockPrivacyManager(); virtual void requestListNames(); virtual void changeDefaultList(const QString& name); virtual void changeActiveList(const QString& name); virtual void changeList(const PrivacyList& list); virtual void getDefaultList(); virtual void requestList(const QString& name); private: PrivacyListItem createItem(PrivacyListItem::Type type, const QString& value, PrivacyListItem::Action action, bool message, bool presence_in, bool presence_out, bool iq); }; #endif psi-0.14/src/privacy/guitest/mockprivacymanager.cpp0000644000175000017500000000531611305557613020664 0ustar janjan/* * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "mockprivacymanager.h" #include "privacylist.h" #include "privacylistitem.h" MockPrivacyManager::MockPrivacyManager() { } void MockPrivacyManager::requestListNames() { qDebug() << "requestListNames()"; QStringList lists; lists << "a" << "b" << "c"; emit listsReceived("a","c",lists); } void MockPrivacyManager::changeDefaultList(const QString& name) { qDebug() << "changeDefaultList(" << name << ")"; } void MockPrivacyManager::changeActiveList(const QString& name) { qDebug() << "changeActiveList(" << name << ")"; } void MockPrivacyManager::changeList(const PrivacyList& list) { qDebug() << "changeList(" << list.name() << ")"; } void MockPrivacyManager::getDefaultList() { qDebug() << "getDefaultList()"; } void MockPrivacyManager::requestList(const QString& name) { qDebug() << "requestList(" << name << ")"; QList items; if (name == "a") { items += createItem(PrivacyListItem::JidType, "me@example.com", PrivacyListItem::Deny, true, true, false, false); items += createItem(PrivacyListItem::FallthroughType, "", PrivacyListItem::Allow, true, true, true, true); } else if (name == "b") { items += createItem(PrivacyListItem::GroupType, "mygroup", PrivacyListItem::Deny, false, false, true, true); } else if (name == "c") { items += createItem(PrivacyListItem::SubscriptionType, "to", PrivacyListItem::Allow, false, false, false, false); items += createItem(PrivacyListItem::FallthroughType, "", PrivacyListItem::Deny, true, true, true, true); } PrivacyList list(name, items); emit listReceived(list); } PrivacyListItem MockPrivacyManager::createItem(PrivacyListItem::Type type, const QString& value, PrivacyListItem::Action action, bool message, bool presence_in, bool presence_out, bool iq) { PrivacyListItem item; item.setType(type); item.setValue(value); item.setAction(action); item.setMessage(message); item.setPresenceIn(presence_in); item.setPresenceOut(presence_out); item.setIQ(iq); return item; } psi-0.14/src/privacy/guitest/privacydlgtest.cpp0000644000175000017500000000104411305557613020040 0ustar janjan#include #include "guitest.h" #include "guitestmanager.h" #include "mockprivacymanager.h" #include "privacydlg.h" class PrivacyDlgTest : public GUITest { public: PrivacyDlgTest(); QString name() { return "PrivacyDlgTest"; } bool run(); }; PrivacyDlgTest::PrivacyDlgTest() { GUITestManager::instance()->registerTest(this); } bool PrivacyDlgTest::run() { PrivacyDlg* dlg = new PrivacyDlg("MyAccount", new MockPrivacyManager()); dlg->exec(); return false; } static PrivacyDlgTest* privacyDlgTestInstance = new PrivacyDlgTest(); psi-0.14/src/privacy/privacylistblockedmodel.cpp0000644000175000017500000000276311305557613020237 0ustar janjan/* * privacylistblockedmodel.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "privacylistblockedmodel.h" #include "privacylistmodel.h" PrivacyListBlockedModel::PrivacyListBlockedModel(QObject* parent) : QSortFilterProxyModel(parent) { } bool PrivacyListBlockedModel::lessThan(const QModelIndex & left, const QModelIndex & right ) const { return left.row() < right.row(); } bool PrivacyListBlockedModel::filterAcceptsColumn(int source_column, const QModelIndex &) const { return source_column == PrivacyListModel::ValueColumn; } bool PrivacyListBlockedModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent ) const { return sourceModel()->data(sourceModel()->index(source_row,0,source_parent),PrivacyListModel::BlockedRole).toBool(); } psi-0.14/src/privacy/privacylist.cpp0000644000175000017500000000732611305557613015672 0ustar janjan/* * privacylist.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include "privacylist.h" #define ORDER_INCREMENT 10 PrivacyList::PrivacyList(const QString& name, const QList& items) : name_(name), items_(items) { qSort(items_); }; PrivacyList::PrivacyList(const QDomElement& e) { fromXml(e); } void PrivacyList::updateItem(int index, const PrivacyListItem& item) { unsigned int order = items_[index].order(); items_[index] = item; items_[index].setOrder(order); } void PrivacyList::insertItem(int index, const PrivacyListItem& item) { items_.insert(index,item); reNumber(); } void PrivacyList::reNumber() { unsigned int order = 100; for (int i = 0; i < items_.size(); ++i) { items_[i].setOrder(order); order += ORDER_INCREMENT; } } bool PrivacyList::moveItemUp(int index) { if (index < items().count() && index > 0) { unsigned int order =items_[index].order(); if (order == items_[index-1].order()) { reNumber(); return true; } items_[index].setOrder(items_[index-1].order()); items_[index-1].setOrder(order); items_.swap(index,index-1); return true; } else { return false; } } bool PrivacyList::moveItemDown(int index) { if (index >= 0 && index < items().count()-1) { unsigned int order =items_[index].order(); if (order == items_[index+1].order()) { reNumber(); return true; } items_[index].setOrder(items_[index+1].order()); items_[index+1].setOrder(order); items_.swap(index,index+1); return true; } else { return false; } } bool PrivacyList::onlyBlockItems() const { bool allBlocked = true; bool fallThrough = false; QList::ConstIterator it; for (it = items_.begin(); it != items_.end() && allBlocked; ++it ) { if ((*it).type() == PrivacyListItem::FallthroughType && (*it).action() == PrivacyListItem::Allow && (*it).all()) { fallThrough = true; } else if ((*it).isBlock()) { if (fallThrough) allBlocked = false; } else { allBlocked = false; } } return allBlocked; } QDomElement PrivacyList::toXml(QDomDocument& doc) const { QDomElement list = doc.createElement("list"); list.setAttribute("name",name()); for (QList::ConstIterator it = items_.begin() ; it != items_.end(); it++) { list.appendChild((*it).toXml(doc)); } return list; } void PrivacyList::fromXml(const QDomElement& el) { //qDebug("privacy.cpp: Parsing privacy list"); if (el.isNull() || el.tagName() != "list") { qWarning("privacy.cpp: Invalid root tag for privacy list."); return; } setName(el.attribute("name")); for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (!e.isNull()) items_.append(PrivacyListItem(e)); } qSort(items_); } QString PrivacyList::toString() const { QString s; for (QList::ConstIterator it = items_.begin() ; it != items_.end(); it++) { s += QString("%1 (%2)\n").arg((*it).toString()).arg((*it).order()); } return s; } psi-0.14/src/privacy/psiprivacymanager.h0000644000175000017500000000417711305557613016513 0ustar janjan/* * privacymanager.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PSIPRIVACYMANAGER_H #define PSIPRIVACYMANAGER_H #include #include #include "privacymanager.h" class QString; class PrivacyList; class PrivacyListListener; namespace XMPP { class Task; } class PsiPrivacyManager : public PrivacyManager { Q_OBJECT public: PsiPrivacyManager(XMPP::Task* rootTask); virtual ~PsiPrivacyManager(); void requestListNames(); void changeDefaultList(const QString& name); void changeActiveList(const QString& name); void changeList(const PrivacyList& list); void getDefaultList(); void requestList(const QString& name); // Convenience void block(const QString&); protected: static QStringList blockedContacts(const PrivacyList&, bool* allBlocked); // Can these be private ? protected slots: void receiveLists(); void receiveList(); void changeDefaultList_finished(); void changeActiveList_finished(); void changeList_finished(); void getDefault_listsReceived(const QString&, const QString&, const QStringList&); void getDefault_listsError(); void getDefault_listReceived(const PrivacyList&); void getDefault_listError(); void block_getDefaultList_success(const PrivacyList&); void block_getDefaultList_error(); private: XMPP::Task* rootTask_; PrivacyListListener* listener_; bool getDefault_waiting_; QString getDefault_default_; QStringList block_targets_; bool block_waiting_; }; #endif psi-0.14/src/privacy/psiprivacymanager.cpp0000644000175000017500000002741011305557613017041 0ustar janjan/* * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "xmpp_xmlcommon.h" #include "xmpp_task.h" #include "xmpp_jid.h" #include "psiprivacymanager.h" #include "privacymanager.h" #include "privacylist.h" #define PRIVACY_NS "jabber:iq:privacy" using namespace XMPP; // ----------------------------------------------------------------------------- // class PrivacyListListener : public Task { Q_OBJECT public: PrivacyListListener(Task* parent) : Task(parent) { } bool take(const QDomElement &e) { if(e.tagName() != "iq" || e.attribute("type") != "set") return false; QString ns = queryNS(e); if(ns == "jabber:iq:privacy") { // TODO: Do something with update // Confirm receipt QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); send(iq); return true; } return false; } }; // ----------------------------------------------------------------------------- class GetPrivacyListsTask : public Task { Q_OBJECT private: QDomElement iq_; QStringList lists_; QString default_, active_; public: GetPrivacyListsTask(Task* parent) : Task(parent) { iq_ = createIQ(doc(), "get", "", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns",PRIVACY_NS); iq_.appendChild(query); } void onGo() { send(iq_); } bool take(const QDomElement &x) { if(!iqVerify(x, "", id())) return false; //qDebug("privacy.cpp: Got reply for privacy lists."); if (x.attribute("type") == "result") { QDomElement tag, q = queryTag(x); for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (e.tagName() == "active") active_ = e.attribute("name"); else if (e.tagName() == "default") default_ = e.attribute("name"); else if (e.tagName() == "list") lists_.append(e.attribute("name")); else qWarning("privacy.cpp: Unknown tag in privacy lists."); } setSuccess(); } else { setError(x); } return true; } const QStringList& lists() { return lists_; } const QString& defaultList() { return default_; } const QString& activeList() { return active_; } }; class SetPrivacyListsTask : public Task { Q_OBJECT private: bool changeDefault_, changeActive_, changeList_; PrivacyList list_; QString value_; public: SetPrivacyListsTask(Task* parent) : Task(parent), changeDefault_(false), changeActive_(false), changeList_(false), list_("") { } void onGo() { QDomElement iq_ = createIQ(doc(), "set", "", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns",PRIVACY_NS); iq_.appendChild(query); QDomElement e; if (changeDefault_) { //qDebug("privacy.cpp: Changing default privacy list."); e = doc()->createElement("default"); if (!value_.isEmpty()) e.setAttribute("name",value_); } else if (changeActive_) { //qDebug("privacy.cpp: Changing active privacy list."); e = doc()->createElement("active"); if (!value_.isEmpty()) e.setAttribute("name",value_); } else if (changeList_) { //qDebug("privacy.cpp: Changing privacy list."); e = list_.toXml(*doc()); } else { qWarning("privacy.cpp: Empty active/default list change request."); return; } query.appendChild(e); send(iq_); } void setActive(const QString& active) { value_ = active; changeDefault_ = false; changeActive_ = true; changeList_ = false; } void setDefault(const QString& d) { value_ = d; changeDefault_ = true; changeActive_ = false; changeList_ = true; } void setList(const PrivacyList& list) { //qDebug() << "setList: " << list.toString(); list_ = list; changeDefault_ = false; changeActive_ = false; changeList_ = true; } bool take(const QDomElement &x) { if(!iqVerify(x, "", id())) return false; if (x.attribute("type") == "result") { //qDebug("privacy.cpp: Got succesful reply for list change."); setSuccess(); } else { qWarning("privacy.cpp: Got error reply for list change."); setError(x); } return true; } }; class GetPrivacyListTask : public Task { Q_OBJECT private: QDomElement iq_; QString name_; PrivacyList list_; public: GetPrivacyListTask(Task* parent, const QString& name) : Task(parent), name_(name), list_(PrivacyList("")) { iq_ = createIQ(doc(), "get", "", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns",PRIVACY_NS); iq_.appendChild(query); QDomElement list = doc()->createElement("list"); list.setAttribute("name",name); query.appendChild(list); } void onGo() { //qDebug() << "privacy.cpp: Requesting privacy list %1." << name_; send(iq_); } bool take(const QDomElement &x) { if(!iqVerify(x, "", id())) return false; //qDebug() << QString("privacy.cpp: Got privacy list %1 reply.").arg(name_); if (x.attribute("type") == "result") { QDomElement q = queryTag(x); bool found; QDomElement listTag = findSubTag(q,"list",&found); if (found) { list_ = PrivacyList(listTag); } else { qWarning("privacy.cpp: No valid list found."); } setSuccess(); } else { setError(x); } return true; } const PrivacyList& list() { return list_; } }; // ----------------------------------------------------------------------------- PsiPrivacyManager::PsiPrivacyManager(XMPP::Task* rootTask) : rootTask_(rootTask), getDefault_waiting_(false), block_waiting_(false) { listener_ = new PrivacyListListener(rootTask_); } PsiPrivacyManager::~PsiPrivacyManager() { delete listener_; } void PsiPrivacyManager::requestListNames() { GetPrivacyListsTask* t = new GetPrivacyListsTask(rootTask_); connect(t,SIGNAL(finished()),SLOT(receiveLists())); t->go(true); } void PsiPrivacyManager::requestList(const QString& name) { GetPrivacyListTask* t = new GetPrivacyListTask(rootTask_, name); connect(t,SIGNAL(finished()),SLOT(receiveList())); t->go(true); } void PsiPrivacyManager::block(const QString& target) { block_targets_.push_back(target); if (!block_waiting_) { block_waiting_ = true; connect(this,SIGNAL(defaultListAvailable(const PrivacyList&)),SLOT(block_getDefaultList_success(const PrivacyList&))); connect(this,SIGNAL(defaultListError()),SLOT(block_getDefaultList_error())); getDefaultList(); } } void PsiPrivacyManager::block_getDefaultList_success(const PrivacyList& l_) { PrivacyList l = l_; disconnect(this,SIGNAL(defaultListAvailable(const PrivacyList&)),this,SLOT(block_getDefault_success(const PrivacyList&))); disconnect(this,SIGNAL(defaultListError()),this,SLOT(block_getDefault_error())); block_waiting_ = false; while (!block_targets_.isEmpty()) l.insertItem(0,PrivacyListItem::blockItem(block_targets_.takeFirst())); changeList(l); } void PsiPrivacyManager::block_getDefaultList_error() { disconnect(this,SIGNAL(defaultListAvailable(const PrivacyList&)),this,SLOT(block_getDefault_success(const PrivacyList&))); disconnect(this,SIGNAL(defaultListError()),this,SLOT(block_getDefault_error())); block_waiting_ = false; block_targets_.clear(); } void PsiPrivacyManager::getDefaultList() { connect(this,SIGNAL(listsReceived(const QString&, const QString&, const QStringList&)),SLOT(getDefault_listsReceived(const QString&, const QString&, const QStringList&))); connect(this,SIGNAL(listsError()),SLOT(getDefault_listsError())); requestListNames(); } void PsiPrivacyManager::getDefault_listsReceived(const QString& defaultList, const QString&, const QStringList&) { disconnect(this,SIGNAL(listsReceived(const QString&, const QString&, const QStringList&)),this,SLOT(getDefault_listsReceived(const QString&, const QString&, const QStringList&))); disconnect(this,SIGNAL(listsError()),this,SLOT(getDefault_listsError())); getDefault_default_ = defaultList; if (!defaultList.isEmpty()) { getDefault_waiting_ = true; connect(this,SIGNAL(listReceived(const PrivacyList&)),SLOT(getDefault_listReceived(const PrivacyList&))); connect(this,SIGNAL(listError()),SLOT(getDefault_listError())); requestList(defaultList); } else { emit defaultListAvailable(PrivacyList("")); } } void PsiPrivacyManager::getDefault_listsError() { disconnect(this,SIGNAL(listsReceived(const QString&, const QString&, const QStringList&)),this,SLOT(getDefault_listsReceived(const QString&, const QString&, const QStringList&))); disconnect(this,SIGNAL(listsError()),this,SLOT(getDefault_listsError())); emit defaultListError(); } void PsiPrivacyManager::getDefault_listReceived(const PrivacyList& l) { if (l.name() == getDefault_default_ && getDefault_waiting_) { disconnect(this,SIGNAL(listReceived(const PrivacyList&)),this,SLOT(getDefault_listReceived(const PrivacyList&))); disconnect(this,SIGNAL(listError()),this,SLOT(getDefault_listError())); getDefault_waiting_ = false; emit defaultListAvailable(l); } } void PsiPrivacyManager::getDefault_listError() { emit defaultListError(); } void PsiPrivacyManager::changeDefaultList(const QString& name) { SetPrivacyListsTask* t = new SetPrivacyListsTask(rootTask_); t->setDefault(name); connect(t,SIGNAL(finished()),SLOT(changeDefaultList_finished())); t->go(true); } void PsiPrivacyManager::changeDefaultList_finished() { SetPrivacyListsTask *t = (SetPrivacyListsTask*)sender(); if (!t) { qWarning("privacy.cpp:changeDefault_finished(): Unexpected sender."); return; } if (t->success()) { emit changeDefaultList_success(); } else { emit changeDefaultList_error(); } } void PsiPrivacyManager::changeActiveList(const QString& name) { SetPrivacyListsTask* t = new SetPrivacyListsTask(rootTask_); t->setActive(name); connect(t,SIGNAL(finished()),SLOT(changeActiveList_finished())); t->go(true); } void PsiPrivacyManager::changeActiveList_finished() { SetPrivacyListsTask *t = (SetPrivacyListsTask*)sender(); if (!t) { qWarning("privacy.cpp:changeActive_finished(): Unexpected sender."); return; } if (t->success()) { emit changeActiveList_success(); } else { emit changeActiveList_error(); } } void PsiPrivacyManager::changeList(const PrivacyList& list) { SetPrivacyListsTask* t = new SetPrivacyListsTask(rootTask_); t->setList(list); connect(t,SIGNAL(finished()),SLOT(changeList_finished())); t->go(true); } void PsiPrivacyManager::changeList_finished() { SetPrivacyListsTask *t = (SetPrivacyListsTask*)sender(); if (!t) { qWarning("privacy.cpp:changeList_finished(): Unexpected sender."); return; } if (t->success()) { emit changeList_success(); } else { emit changeList_error(); } } void PsiPrivacyManager::receiveLists() { GetPrivacyListsTask *t = (GetPrivacyListsTask*)sender(); if (!t) { qWarning("privacy.cpp:receiveLists(): Unexpected sender."); return; } if (t->success()) { emit listsReceived(t->defaultList(),t->activeList(),t->lists()); } else { qDebug("privacy.cpp: Error in lists receiving."); emit listsError(); } } void PsiPrivacyManager::receiveList() { GetPrivacyListTask *t = (GetPrivacyListTask*)sender(); if (!t) { qWarning("privacy.cpp:receiveList(): Unexpected sender."); return; } if (t->success()) { emit listReceived(t->list()); } else { qDebug("privacy.cpp: Error in list receiving."); emit listError(); } } #include "psiprivacymanager.moc" psi-0.14/src/privacy/privacyrule.ui0000644000175000017500000001071611305557613015516 0ustar janjan PrivacyRule 0 0 365 245 Edit Privacy Rule 9 6 0 6 Then: 0 6 Messages Queries Outgoing Presence Incoming Presence If: Qt::Horizontal Qt::Vertical 20 61 Qt::Vertical 20 51 true Qt::Horizontal 0 6 Qt::Horizontal 40 20 OK Cancel psi-0.14/src/privacy/privacyruledlg.h0000644000175000017500000000220511305557613016011 0ustar janjan/* * privacyruledlg.h * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PRIVACYRULEDLG_H #define PRIVACYRULEDLG_H #include #include "ui_privacyrule.h" class PrivacyListItem; class PrivacyRuleDlg : public QDialog { Q_OBJECT public: PrivacyRuleDlg(); void setRule(const PrivacyListItem&); PrivacyListItem rule() const; protected slots: void type_selected(const QString&); private: Ui::PrivacyRule ui_; }; #endif psi-0.14/src/privacy/privacydlg.cpp0000644000175000017500000002200111305557613015450 0ustar janjan/* * privacydlg.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "privacydlg.h" #include "privacylist.h" #include "privacymanager.h" #include "privacylistmodel.h" // fixme: subscribe on the destroyed() signal of the manager PrivacyDlg::PrivacyDlg(const QString& account_name, PrivacyManager* manager, QWidget* parent) : QDialog(parent), manager_(manager) { ui_.setupUi(this); setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(tr("%1: Privacy Lists").arg(account_name)); connect(manager_,SIGNAL(listsReceived(const QString&, const QString&, const QStringList&)),SLOT(updateLists(const QString&, const QString&, const QStringList&))); connect(manager_,SIGNAL(listReceived(const PrivacyList&)),SLOT(refreshList(const PrivacyList&))); connect(manager_,SIGNAL(listError()),SLOT(list_failed())); //connect(manager_,SIGNAL(listNamesError()),SLOT(listNamesError())); //connect(manager_,SIGNAL(listReceiveError()),SLOT(listReceiveError())); connect(ui_.cb_active,SIGNAL(activated(int)),SLOT(active_selected(int))); connect(ui_.cb_default,SIGNAL(activated(int)),SLOT(default_selected(int))); connect(ui_.cb_lists,SIGNAL(activated(int)),SLOT(list_selected(int))); connect(ui_.cb_lists,SIGNAL(currentIndexChanged(int)),SLOT(list_changed(int))); connect(manager_,SIGNAL(changeActiveList_success()),SLOT(change_succeeded())); connect(manager_,SIGNAL(changeActiveList_error()),SLOT(change_failed())); connect(manager_,SIGNAL(changeDefaultList_success()),SLOT(change_succeeded())); connect(manager_,SIGNAL(changeDefaultList_error()),SLOT(change_failed())); connect(manager_,SIGNAL(changeList_success()),SLOT(changeList_succeeded())); connect(manager_,SIGNAL(changeList_error()),SLOT(changeList_failed())); connect(ui_.pb_newList,SIGNAL(clicked()),SLOT(newList())); connect(ui_.pb_deleteList,SIGNAL(clicked()),SLOT(removeList())); connect(ui_.pb_add,SIGNAL(clicked()),SLOT(addRule())); connect(ui_.pb_edit,SIGNAL(clicked()),SLOT(editCurrentRule())); connect(ui_.pb_remove,SIGNAL(clicked()),SLOT(removeCurrentRule())); connect(ui_.pb_up,SIGNAL(clicked()),SLOT(moveCurrentRuleUp())); connect(ui_.pb_down,SIGNAL(clicked()),SLOT(moveCurrentRuleDown())); connect(ui_.pb_apply,SIGNAL(clicked()),SLOT(applyList())); connect(ui_.buttonBox->button(QDialogButtonBox::Close),SIGNAL(clicked()),SLOT(close())); setWidgetsEnabled(false); // Disable all buttons ui_.pb_deleteList->setEnabled(false); setEditRuleEnabled(false); ui_.pb_add->setEnabled(false); ui_.pb_apply->setEnabled(false); // FIXME: Temporarily disabling auto-activate ui_.ck_autoActivate->hide(); manager_->requestListNames(); } void PrivacyDlg::setWidgetsEnabled(bool b) { ui_.gb_settings->setEnabled(b); ui_.gb_listSettings->setEnabled(b); } void PrivacyDlg::setEditRuleEnabled(bool b) { ui_.pb_up->setEnabled(b); ui_.pb_down->setEnabled(b); ui_.pb_edit->setEnabled(b); ui_.pb_remove->setEnabled(b); } void PrivacyDlg::addRule() { model_.add(); } void PrivacyDlg::editCurrentRule() { // Maybe should use MVC setData here model_.edit(ui_.lv_rules->currentIndex()); } void PrivacyDlg::removeCurrentRule() { if (ui_.lv_rules->currentIndex().isValid()) { model_.removeRow(ui_.lv_rules->currentIndex().row(),ui_.lv_rules->currentIndex().parent()); } } void PrivacyDlg::moveCurrentRuleUp() { int row = ui_.lv_rules->currentIndex().row(); if (model_.moveUp(ui_.lv_rules->currentIndex())) { ui_.lv_rules->setCurrentIndex(model_.index(row-1,0)); } } void PrivacyDlg::moveCurrentRuleDown() { int row = ui_.lv_rules->currentIndex().row(); if (model_.moveDown(ui_.lv_rules->currentIndex())) { ui_.lv_rules->setCurrentIndex(model_.index(row+1,0)); } } void PrivacyDlg::applyList() { if (!model_.list().isEmpty()) { setWidgetsEnabled(false); manager_->changeList(model_.list()); if (newList_) manager_->requestListNames(); } } void PrivacyDlg::close() { // FIXME: Warn about unsaved changes done(0); } void PrivacyDlg::updateLists(const QString& defaultList, const QString& activeList, const QStringList& names) { // Active list ui_.cb_active->clear(); ui_.cb_active->addItem(tr("")); ui_.cb_active->addItems(names); if (!activeList.isEmpty()) { ui_.cb_active->setCurrentIndex(names.indexOf(activeList)+1); } else { ui_.cb_active->setCurrentIndex(0); } previousActive_ = ui_.cb_active->currentIndex(); // Default list ui_.cb_default->clear(); ui_.cb_default->addItem(tr("")); ui_.cb_default->addItems(names); if (!defaultList.isEmpty()) { ui_.cb_default->setCurrentIndex(names.indexOf(defaultList)+1); } else { ui_.cb_default->setCurrentIndex(0); } previousDefault_ = ui_.cb_default->currentIndex(); // All lists QString previousList = ui_.cb_lists->currentText(); ui_.cb_lists->clear(); ui_.cb_lists->addItems(names); if (ui_.cb_lists->count() > 0) { if (!previousList.isEmpty() && ui_.cb_lists->findText(previousList) != -1) { ui_.cb_lists->setCurrentIndex(ui_.cb_lists->findText(previousList)); } else { QString currentList = (activeList.isEmpty() ? activeList : defaultList); if (!currentList.isEmpty()) { ui_.cb_lists->setCurrentIndex(names.indexOf(currentList)); } } manager_->requestList(ui_.cb_lists->currentText()); } else { setWidgetsEnabled(true); } ui_.lv_rules->setModel(&model_); } void PrivacyDlg::listChanged() { if (model_.list().isEmpty()) { ui_.cb_lists->removeItem(previousList_); rememberSettings(); } setWidgetsEnabled(false); manager_->requestList(ui_.cb_lists->currentText()); } void PrivacyDlg::refreshList(const PrivacyList& list) { if (list.name() == ui_.cb_lists->currentText()) { rememberSettings(); model_.setList(list); setWidgetsEnabled(true); } } void PrivacyDlg::active_selected(int i) { if (i != previousActive_) { setWidgetsEnabled(false); manager_->changeActiveList((i == 0 ? "" : ui_.cb_active->itemText(i))); } } void PrivacyDlg::default_selected(int i) { if (i != previousDefault_) { setWidgetsEnabled(false); manager_->changeDefaultList((i == 0 ? "" : ui_.cb_active->itemText(i))); } } void PrivacyDlg::list_selected(int i) { if (i != previousList_) { listChanged(); } } void PrivacyDlg::list_changed(int i) { ui_.pb_deleteList->setEnabled(i != -1); ui_.pb_add->setEnabled(i != -1); setEditRuleEnabled(i != -1); ui_.pb_apply->setEnabled(i != -1); //setEditRuleEnabled(false); newList_ = false; } void PrivacyDlg::list_failed() { revertSettings(); setWidgetsEnabled(true); } void PrivacyDlg::changeList_succeeded() { // If we just deleted a list, select the first list if (model_.list().isEmpty()) { ui_.cb_lists->setCurrentIndex(0); listChanged(); } else { setWidgetsEnabled(true); } } void PrivacyDlg::changeList_failed() { QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("There was an error changing the list.")); setWidgetsEnabled(true); } void PrivacyDlg::change_succeeded() { rememberSettings(); setWidgetsEnabled(true); } void PrivacyDlg::change_failed() { revertSettings(); QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("There was an error processing your request.")); setWidgetsEnabled(true); } void PrivacyDlg::rememberSettings() { previousDefault_ = ui_.cb_default->currentIndex(); previousActive_ = ui_.cb_active->currentIndex(); previousList_ = ui_.cb_lists->currentIndex(); } void PrivacyDlg::revertSettings() { ui_.cb_default->setCurrentIndex(previousDefault_); ui_.cb_active->setCurrentIndex(previousActive_); ui_.cb_lists->setCurrentIndex(previousList_); } void PrivacyDlg::newList() { bool done = false; bool ok = false; QString name; while (!done) { name = QInputDialog::getText(this, tr("New List"), tr("Enter the name of the new list:"), QLineEdit::Normal, "", &ok); if (!ok) { done = true; } else if (ui_.cb_lists->findText(name) != -1) { QMessageBox::critical(this, tr("Error"), tr("A list with this name already exists.")); } else if (!name.isEmpty()) { done = true; } } if (ok) { if (ui_.cb_lists->currentIndex() != -1 && model_.list().isEmpty()) { ui_.cb_lists->removeItem(ui_.cb_lists->currentIndex()); } ui_.cb_lists->addItem(name); ui_.cb_lists->setCurrentIndex(ui_.cb_lists->findText(name)); model_.setList(PrivacyList(name)); newList_ = true; rememberSettings(); } } void PrivacyDlg::removeList() { model_.list().clear(); manager_->changeList(model_.list()); manager_->requestListNames(); } psi-0.14/src/privacy/privacylistitem.cpp0000644000175000017500000001165011305557613016544 0ustar janjan/* * privacylistitem.cpp * Copyright (C) 2006 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "privacylistitem.h" #include "xmpp_xmlcommon.h" #include "xmpp_jid.h" PrivacyListItem::PrivacyListItem() : message_(true), presenceIn_(true), presenceOut_(true), iq_(true) { } PrivacyListItem::PrivacyListItem(const QDomElement& e) { fromXml(e); } bool PrivacyListItem::isBlock() const { return (type() == JidType && action() == Deny && all()); } QString PrivacyListItem::toString() const { QString act; if (action() == PrivacyListItem::Deny) act = QObject::tr("Deny"); else act = QObject::tr("Allow"); QString what; if (all()) what = QObject::tr("All"); else { if (message()) what += QObject::tr("Messages,"); if (presenceIn()) what += QObject::tr("Presence-In,"); if (presenceOut()) what += QObject::tr("Presence-Out,"); if (iq()) what += QObject::tr("Queries,"); what.truncate(what.length()-1); } QString txt; if (type() == PrivacyListItem::FallthroughType) { txt = QString(QObject::tr("Else %1 %2")).arg(act).arg(what); } else { if (type() == PrivacyListItem::JidType) { txt = QString(QObject::tr("If JID is '%1' then %2 %3")).arg(value()).arg(act).arg(what); } else if (type() == PrivacyListItem::GroupType) { txt = QString(QObject::tr("If Group is '%1' then %2 %3")).arg(value()).arg(act).arg(what); } else if (type() == PrivacyListItem::SubscriptionType) { txt = QString(QObject::tr("If Subscription is '%1' then %2 %3")).arg(value()).arg(act).arg(what); } } return txt; } QDomElement PrivacyListItem::toXml(QDomDocument& doc) const { QDomElement item = doc.createElement("item"); if (type_ == JidType) item.setAttribute("type","jid"); else if (type_ == GroupType) item.setAttribute("type","group"); else if (type_ == SubscriptionType) item.setAttribute("type","subscription"); if (type_ != FallthroughType) item.setAttribute("value",value_); if (action_ == Allow) item.setAttribute("action","allow"); else item.setAttribute("action","deny"); item.setAttribute("order", order_); if (!(message_ && presenceIn_ && presenceOut_ && iq_)) { if (message_) item.appendChild(doc.createElement("message")); if (presenceIn_) item.appendChild(doc.createElement("presence-in")); if (presenceOut_) item.appendChild(doc.createElement("presence-out")); if (iq_) item.appendChild(doc.createElement("iq")); } return item; } void PrivacyListItem::fromXml(const QDomElement& el) { //qDebug("privacy.cpp: Parsing privacy list item"); if (el.isNull() || el.tagName() != "item") { qWarning("privacy.cpp: Invalid root tag for privacy list item."); return; } QString type = el.attribute("type"); if (type == "jid") type_ = JidType; else if (type == "group") type_ = GroupType; else if (type == "subscription") type_ = SubscriptionType; else type_ = FallthroughType; QString value = el.attribute("value"); value_ = value; if (type_ == JidType && XMPP::Jid(value_).isEmpty()) qWarning("privacy.cpp: Invalid value for item of type 'jid'."); else if (type_ == GroupType && value_.isEmpty()) qWarning("privacy.cpp: Empty value for item of type 'group'."); else if (type_ == SubscriptionType && value_ != "from" && value != "to" && value_ != "both" && value_ != "none") qWarning("privacy.cpp: Invalid value for item of type 'subscription'."); else if (type_ == FallthroughType && !value_.isEmpty()) qWarning("privacy.cpp: Value given for item of fallthrough type."); QString action = el.attribute("action"); if (action == "allow") action_ = Allow; else if (action == "deny") action_ = Deny; else qWarning("privacy.cpp: Invalid action given for item."); bool ok; order_ = el.attribute("order").toUInt(&ok); if (!ok) qWarning("privacy.cpp: Invalid order value for item."); if (el.hasChildNodes()) { findSubTag(el, "message", &message_); findSubTag(el, "presence-in", &presenceIn_); findSubTag(el, "presence-out", &presenceOut_); findSubTag(el, "iq", &iq_); } else { message_ = presenceIn_ = presenceOut_ = iq_ = true; } } PrivacyListItem PrivacyListItem::blockItem(const QString& jid) { PrivacyListItem it; it.setType(JidType); it.setAction(Deny); it.setAll(); it.setValue(jid); return it; } psi-0.14/src/passphrasedlg.h0000644000175000017500000000214611305557613014144 0ustar janjan/* * passphrasedlg.h - class to handle entering of OpenPGP passphrase * Copyright (C) 2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PASSPHRASEDLG_H #define PASSPHRASEDLG_H #include "ui_passphrase.h" class PassphraseDlg : public QDialog { Q_OBJECT public: PassphraseDlg(QWidget* parent = 0); void promptPassphrase(const QString& name); QString getPassphrase() const; private: Ui::Passphrase ui_; }; #endif psi-0.14/src/mucreasonseditor.ui0000644000175000017500000000664211305557613015065 0ustar janjan MUCReasonsEditor 0 0 400 300 Reason editor 9 6 Reasons 9 6 0 6 Add Remove 0 6 Qt::Horizontal 40 20 Ok false true Cancel btnOk clicked() MUCReasonsEditor accept() 265 271 -2 287 btnCancel clicked() MUCReasonsEditor reject() 341 283 81 272 psi-0.14/src/ahcformdlg.h0000644000175000017500000000321011305557613013403 0ustar janjan/* * ahcformdlg.h - Ad-Hoc Command Form Dialog * Copyright (C) 2005 Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef AHCFORMDLG_H #define AHCFORMDLG_H #include #include #include #include "xmpp_xdata.h" #include "xmpp_jid.h" class QPushButton; class BusyWidget; class AHCommand; class XDataWidget; namespace XMPP { class Client; } #include "ui_ahcformdlg.h" class AHCFormDlg : public QDialog { Q_OBJECT public: AHCFormDlg(const AHCommand& r, const XMPP::Jid& receiver, XMPP::Client* client, bool final = false); protected: XMPP::XData data() const; protected slots: void doPrev(); void doNext(); void doComplete(); void doExecute(); void doCancel(); void commandExecuted(); private: Ui::AHCFormDlg ui_; QPushButton* pb_prev_; QPushButton* pb_next_; QPushButton* pb_complete_; QPushButton* pb_cancel_; XDataWidget* xdata_; XMPP::Jid receiver_; QString node_; XMPP::Client* client_; QString sessionId_; }; #endif psi-0.14/src/proxy.h0000644000175000017500000000525211305557613012466 0ustar janjan/* * proxy.h - classes for handling proxy profiles * Copyright (C) 2003 Justin Karneges * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PROXYDLG_H #define PROXYDLG_H #include #include #include "ui_proxy.h" //#include "ui_proxyedit.h" class OptionsTree; class QDomElement; class QDomDocument; class ProxyItem; class ProxyManager; typedef QList ProxyItemList; class ProxySettings { public: ProxySettings(); QString host, user, pass; int port; bool useAuth; QString url; void toOptions(OptionsTree* o, QString base) const; void fromOptions(OptionsTree* o, QString base); QDomElement toXml(QDomDocument *) const; bool fromXml(const QDomElement &); }; class ProxyDlg : public QDialog { Q_OBJECT public: ProxyDlg(const ProxyItemList &, const QString &def, QWidget *parent=0); ~ProxyDlg(); signals: void applyList(const ProxyItemList &, int cur); public: class Private; friend class Private; private: Private *d; Ui::Proxy ui_; }; class ProxyChooser : public QWidget { Q_OBJECT public: ProxyChooser(ProxyManager*, QWidget* parent); ~ProxyChooser(); QString currentItem() const; void setCurrentItem(const QString &item); private slots: void pm_settingsChanged(); void pm_settingsChangedApply(); void doOpen(); private: class Private; Private *d; void buildComboBox(); }; class ProxyItem { public: ProxyItem() {} QString id; QString name; QString type; ProxySettings settings; }; class ProxyManager : public QObject { Q_OBJECT public: ProxyManager(OptionsTree *o, QObject *parent=0); ~ProxyManager(); ProxyChooser *createProxyChooser(QWidget *parent=0); ProxyItemList itemList() const; ProxyItem getItem(const QString &id) const; QString lastEdited() const; void migrateItemList(const ProxyItemList &); // int findOldIndex(int) const; signals: void settingsChanged(); void proxyRemoved(QString); public slots: void openDialog(QString); private slots: void pd_applyList(const ProxyItemList &, int cur); private: class Private; Private *d; }; #endif psi-0.14/src/filetrans.ui0000644000175000017500000001173411305557613013464 0ustar janjan FileTrans 0 0 334 268 Form1 accountlabel 0 To: 100 0 true 0 File: psi/browse Size: true Description: QFrame::HLine QFrame::Sunken 0 40 20 Expanding Horizontal stop start true qPixmapFromMimeSource psi-0.14/src/mucjoindlg.h0000644000175000017500000000322011305557613013431 0ustar janjan/* * mucjoindlg.h * Copyright (C) 2001-2008 Justin Karneges, Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MUCJOINDLG_H #define MUCJOINDLG_H #include #include "ui_mucjoin.h" class PsiCon; class QString; class PsiAccount; #include "xmpp_jid.h" class MUCJoinDlg : public QDialog { Q_OBJECT public: MUCJoinDlg(PsiCon *, PsiAccount *); ~MUCJoinDlg(); void setJid(const XMPP::Jid& jid); void setNick(const QString nick); void setPassword(const QString& password); void joined(); void error(int, const QString &); public slots: void done(int); void doJoin(); // reimplemented void accept(); private slots: void updateIdentity(PsiAccount *); void updateIdentityVisibility(); void pa_disconnected(); void recent_activated(int); private: Ui::MUCJoin ui_; PsiCon* controller_; PsiAccount* account_; QPushButton* joinButton_; XMPP::Jid jid_; void disableWidgets(); void enableWidgets(); void setWidgetsEnabled(bool enabled); }; #endif psi-0.14/src/filetransdlg.cpp0000644000175000017500000012143211305557613014315 0ustar janjan#include "filetransdlg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psicon.h" #include "psiaccount.h" #include "userlist.h" #include "iconwidget.h" #include "s5b.h" #include "busywidget.h" #include "filetransfer.h" #include "accountscombobox.h" #include "psiiconset.h" #include "msgmle.h" #include "jidutil.h" #include "psitooltip.h" #include "psicontactlist.h" #include "accountlabel.h" #include "psioptions.h" #include "fileutil.h" typedef Q_UINT64 LARGE_TYPE; #define CSMAX (sizeof(LARGE_TYPE)*8) #define CSMIN 16 static int calcShift(qlonglong big) { LARGE_TYPE val = 1; val <<= CSMAX - 1; for(int n = CSMAX - CSMIN; n > 0; --n) { if(big & val) return n; val >>= 1; } return 0; } static int calcComplement(qlonglong big, int shift) { int block = 1 << shift; qlonglong rem = big % block; if(rem == 0) return 0; else return (block - (int)rem); } static int calcTotalSteps(qlonglong big, int shift) { if(big < 1) return 0; return ((big - 1) >> shift) + 1; } static int calcProgressStep(qlonglong big, int complement, int shift) { return ((big + complement) >> shift); } static QStringList *activeFiles = 0; static void active_file_add(const QString &s) { if(!activeFiles) activeFiles = new QStringList; activeFiles->append(s); //printf("added: [%s]\n", s.latin1()); } static void active_file_remove(const QString &s) { if(!activeFiles) return; activeFiles->removeAll(s); //printf("removed: [%s]\n", s.latin1()); } static bool active_file_check(const QString &s) { if(!activeFiles) return false; return activeFiles->contains(s); } static QString clean_filename(const QString &s) { //#ifdef Q_OS_WIN QString badchars = "\\/|?*:\"<>"; QString str; for(int n = 0; n < s.length(); ++n) { bool found = false; for(int b = 0; b < badchars.length(); ++b) { if(s.at(n) == badchars.at(b)) { found = true; break; } } if(!found) str += s; } if(str.isEmpty()) str = "unnamed"; return str; //#else // return s; //#endif } //---------------------------------------------------------------------------- // FileTransferHandler //---------------------------------------------------------------------------- class FileTransferHandler::Private { public: PsiAccount *pa; FileTransfer *ft; S5BConnection *c; Jid peer; QString fileName, saveName; qlonglong fileSize, sent, offset, length; QString desc; bool sending; QFile f; int shift; int complement; QString activeFile; }; FileTransferHandler::FileTransferHandler(PsiAccount *pa, FileTransfer *ft) { d = new Private; d->pa = pa; d->c = 0; if(ft) { d->sending = false; d->peer = ft->peer(); d->fileName = clean_filename(ft->fileName()); d->fileSize = ft->fileSize(); d->desc = ft->description(); d->shift = calcShift(d->fileSize); d->complement = calcComplement(d->fileSize, d->shift); d->ft = ft; Jid proxy = d->pa->userAccount().dtProxy; if(proxy.isValid()) d->ft->setProxy(proxy); mapSignals(); } else { d->sending = true; d->ft = 0; } } FileTransferHandler::~FileTransferHandler() { if(!d->activeFile.isEmpty()) active_file_remove(d->activeFile); if(d->ft) { d->ft->close(); delete d->ft; } delete d; } void FileTransferHandler::send(const XMPP::Jid &to, const QString &fname, const QString &desc) { if(!d->sending) return; d->peer = to; QFileInfo fi(fname); d->fileName = fi.fileName(); d->fileSize = fi.size(); // TODO: large file support d->desc = desc; d->shift = calcShift(d->fileSize); d->complement = calcComplement(d->fileSize, d->shift); d->ft = d->pa->client()->fileTransferManager()->createTransfer(); Jid proxy = d->pa->userAccount().dtProxy; if(proxy.isValid()) d->ft->setProxy(proxy); mapSignals(); d->f.setFileName(fname); d->ft->sendFile(d->peer, d->fileName, d->fileSize, desc); } PsiAccount *FileTransferHandler::account() const { return d->pa; } int FileTransferHandler::mode() const { return (d->sending ? Sending : Receiving); } Jid FileTransferHandler::peer() const { return d->peer; } QString FileTransferHandler::fileName() const { return d->fileName; } qlonglong FileTransferHandler::fileSize() const { return d->fileSize; } QString FileTransferHandler::description() const { return d->desc; } qlonglong FileTransferHandler::offset() const { return d->offset; } int FileTransferHandler::totalSteps() const { return calcTotalSteps(d->fileSize, d->shift); } bool FileTransferHandler::resumeSupported() const { if(d->ft) return d->ft->rangeSupported(); else return false; } QString FileTransferHandler::saveName() const { return d->saveName; } void FileTransferHandler::accept(const QString &saveName, const QString &fileName, qlonglong offset) { if(d->sending) return; d->fileName = fileName; d->saveName = saveName; d->offset = offset; d->length = d->fileSize; d->f.setFileName(saveName); d->ft->accept(offset); } void FileTransferHandler::s5b_proxyQuery() { statusMessage(tr("Quering proxy...")); } void FileTransferHandler::s5b_proxyResult(bool b) { if(b) statusMessage(tr("Proxy query successful.")); else statusMessage(tr("Proxy query failed!")); } void FileTransferHandler::s5b_requesting() { statusMessage(tr("Requesting data transfer channel...")); } void FileTransferHandler::s5b_accepted() { statusMessage(tr("Peer accepted request.")); } void FileTransferHandler::s5b_tryingHosts(const StreamHostList &) { statusMessage(tr("Connecting to peer...")); } void FileTransferHandler::s5b_proxyConnect() { statusMessage(tr("Connecting to proxy...")); } void FileTransferHandler::s5b_waitingForActivation() { statusMessage(tr("Waiting for peer activation...")); } void FileTransferHandler::ft_accepted() { d->offset = d->ft->offset(); d->length = d->ft->length(); d->c = d->ft->s5bConnection(); connect(d->c, SIGNAL(proxyQuery()), SLOT(s5b_proxyQuery())); connect(d->c, SIGNAL(proxyResult(bool)), SLOT(s5b_proxyResult(bool))); connect(d->c, SIGNAL(requesting()), SLOT(s5b_requesting())); connect(d->c, SIGNAL(accepted()), SLOT(s5b_accepted())); connect(d->c, SIGNAL(tryingHosts(const StreamHostList &)), SLOT(s5b_tryingHosts(const StreamHostList &))); connect(d->c, SIGNAL(proxyConnect()), SLOT(s5b_proxyConnect())); connect(d->c, SIGNAL(waitingForActivation()), SLOT(s5b_waitingForActivation())); if(d->sending) accepted(); else statusMessage(QString()); } void FileTransferHandler::ft_connected() { d->sent = d->offset; if(d->sending) { // open the file, and set the correct offset bool ok = false; if(d->f.open(QIODevice::ReadOnly)) { if(d->offset == 0) { ok = true; } else { if(d->f.seek(d->offset)) ok = true; } } if(!ok) { delete d->ft; d->ft = 0; error(ErrFile, 0, d->f.errorString()); return; } if(d->sent == d->fileSize) QTimer::singleShot(0, this, SLOT(doFinish())); else QTimer::singleShot(0, this, SLOT(trySend())); } else { // open the file, truncating if offset is zero, otherwise set the correct offset QIODevice::OpenMode m = QIODevice::ReadWrite; if(d->offset == 0) m |= QIODevice::Truncate; bool ok = false; if(d->f.open(m)) { if(d->offset == 0) { ok = true; } else { if(d->f.seek(d->offset)) ok = true; } } if(!ok) { delete d->ft; d->ft = 0; error(ErrFile, 0, d->f.errorString()); return; } d->activeFile = d->f.fileName(); active_file_add(d->activeFile); // done already? this means a file size of zero if(d->sent == d->fileSize) QTimer::singleShot(0, this, SLOT(doFinish())); } connected(); } void FileTransferHandler::ft_readyRead(const QByteArray &a) { if(!d->sending) { //printf("%d bytes read\n", a.size()); int r = d->f.write(a.data(), a.size()); if(r < 0) { d->f.close(); delete d->ft; d->ft = 0; error(ErrFile, 0, d->f.errorString()); return; } d->sent += a.size(); doFinish(); } } void FileTransferHandler::ft_bytesWritten(int x) { if(d->sending) { //printf("%d bytes written\n", x); d->sent += x; if(d->sent == d->fileSize) { d->f.close(); delete d->ft; d->ft = 0; } else QTimer::singleShot(0, this, SLOT(trySend())); progress(calcProgressStep(d->sent, d->complement, d->shift), d->sent); } } void FileTransferHandler::ft_error(int x) { if(d->f.isOpen()) d->f.close(); delete d->ft; d->ft = 0; if(x == FileTransfer::ErrReject) error(ErrReject, x, ""); else if(x == FileTransfer::ErrNeg) error(ErrTransfer, x, tr("Unable to negotiate transfer.")); else if(x == FileTransfer::ErrConnect) error(ErrTransfer, x, tr("Unable to connect to peer for data transfer.")); else if(x == FileTransfer::ErrProxy) error(ErrTransfer, x, tr("Unable to connect to proxy for data transfer.")); else if(x == FileTransfer::ErrStream) error(ErrTransfer, x, tr("Lost connection / Cancelled.")); } void FileTransferHandler::trySend() { // Since trySend comes from singleShot which is an "uncancelable" // action, we should protect that d->ft is valid, for good measure if(!d->ft) return; // When FileTransfer emits error, you are not allowed to call // dataSizeNeeded() afterwards. Simetime ago, we changed to using // QueuedConnection for error() signal delivery (see mapSignals()). // This made it possible to call dataSizeNeeded by accident between // the error() signal emit and the ft_error() slot invocation. To // work around this problem, we'll check to see if the FileTransfer // is internally active by checking if s5bConnection() is null. // FIXME: this probably breaks other file transfer methods, whenever // we get those. Probably we need a real fix in Iris.. if(!d->ft->s5bConnection()) return; int blockSize = d->ft->dataSizeNeeded(); QByteArray a(blockSize, 0); int r = 0; if(blockSize > 0) r = d->f.read(a.data(), a.size()); if(r < 0) { d->f.close(); delete d->ft; d->ft = 0; error(ErrFile, 0, d->f.errorString()); return; } if(r < (int)a.size()) a.resize(r); d->ft->writeFileData(a); } void FileTransferHandler::doFinish() { if(d->sent == d->fileSize) { d->f.close(); delete d->ft; d->ft = 0; } progress(calcProgressStep(d->sent, d->complement, d->shift), d->sent); } void FileTransferHandler::mapSignals() { connect(d->ft, SIGNAL(accepted()), SLOT(ft_accepted())); connect(d->ft, SIGNAL(connected()), SLOT(ft_connected())); connect(d->ft, SIGNAL(readyRead(const QByteArray &)), SLOT(ft_readyRead(const QByteArray &))); connect(d->ft, SIGNAL(bytesWritten(int)), SLOT(ft_bytesWritten(int))); connect(d->ft, SIGNAL(error(int)), SLOT(ft_error(int)),Qt::QueuedConnection); } //---------------------------------------------------------------------------- // FileRequestDlg //---------------------------------------------------------------------------- class FileRequestDlg::Private { public: PsiCon *psi; PsiAccount *pa; AccountsComboBox *cb_ident; QLabel* lb_identity; AccountLabel* lb_ident; QLabel* lb_time; ChatView *te; Jid jid; FileTransferHandler *ft; QString fileName; qlonglong fileSize; bool sending; QTimer t; }; FileRequestDlg::FileRequestDlg(const Jid &j, PsiCon *psi, PsiAccount *pa) : QDialog(0, psi_dialog_flags) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); setupUi(this); QStringList l; FileRequestDlg(j, psi, pa, l); } FileRequestDlg::FileRequestDlg(const Jid &jid, PsiCon *psi, PsiAccount *pa, const QStringList& files, bool direct) : QDialog(0, psi_dialog_flags) { setAttribute(Qt::WA_DeleteOnClose); d = new Private; setModal(false); setupUi(this); d->psi = psi; d->pa = 0; d->jid = jid; d->ft = 0; d->sending = true; d->lb_ident = 0; updateIdentity(pa); Q3HBox *hb = new Q3HBox(this); d->lb_identity = new QLabel(tr("Identity: "), hb); d->cb_ident = d->psi->accountsComboBox(hb); connect(d->cb_ident, SIGNAL(activated(PsiAccount *)), SLOT(updateIdentity(PsiAccount *))); d->cb_ident->setAccount(pa); replaceWidget(lb_accountlabel, hb); setTabOrder(d->cb_ident, le_to); connect(d->psi, SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility())); updateIdentityVisibility(); d->te = new ChatView(this); d->te->setReadOnly(false); d->te->setAcceptRichText(false); replaceWidget(te_desc, d->te); setTabOrder(le_fname, d->te); setTabOrder(d->te, pb_stop); setWindowTitle(tr("Send File")); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/upload").icon()); #endif le_to->setText(d->jid.full()); le_to->setReadOnly(false); pb_start->setText(tr("&Send")); pb_stop->setText(tr("&Close")); connect(tb_browse, SIGNAL(clicked()), SLOT(chooseFile())); connect(pb_start, SIGNAL(clicked()), SLOT(doStart())); connect(pb_stop, SIGNAL(clicked()), SLOT(close())); lb_status->setText(tr("Ready")); d->te->setFocus(); d->psi->dialogRegister(this); if (files.isEmpty()) { QTimer::singleShot(0, this, SLOT(chooseFile())); } else { // TODO: Once sending of multiple files is supported, change this QFileInfo fi(files.first()); // Check if the file is legal if(!fi.exists()) { QMessageBox::critical(this, tr("Error"), QString("The file '%1' does not exist.").arg(files.first())); QTimer::singleShot(0, this, SLOT(reject())); return; } if(fi.isDir()) { QMessageBox::critical(this, tr("Error"), tr("Sending folders is not supported.")); QTimer::singleShot(0, this, SLOT(reject())); return; } FileUtil::setLastUsedSavePath(fi.path()); le_fname->setText(QDir::convertSeparators(fi.filePath())); lb_size->setText(tr("%1 byte(s)").arg(fi.size())); // TODO: large file support } if (direct) { doStart(); } } FileRequestDlg::FileRequestDlg(const QDateTime &ts, FileTransfer *ft, PsiAccount *pa) : QDialog(0, psi_dialog_flags) { setAttribute(Qt::WA_DeleteOnClose); d = new Private; setModal(false); setupUi(this); d->psi = 0; d->pa = 0; d->jid = ft->peer(); d->ft = new FileTransferHandler(pa, ft); d->sending = false; updateIdentity(pa); d->fileName = ft->fileName(); d->fileSize = ft->fileSize(); d->cb_ident = 0; Q3HBox *hb = new Q3HBox(this); d->lb_identity = new QLabel(tr("Identity: "), hb); d->lb_ident = new AccountLabel(hb); d->lb_ident->setAccount(d->pa); d->lb_ident->setSizePolicy(QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed )); new QLabel(tr("Time:"), hb); d->lb_time = new QLabel(ts.time().toString(Qt::LocalDate), hb); d->lb_time->setFrameStyle( QFrame::Panel | QFrame::Sunken ); connect(d->pa->psi(), SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility())); updateIdentityVisibility(); replaceWidget(lb_accountlabel, hb); d->te = new ChatView(this); d->te->setAcceptRichText(false); replaceWidget(te_desc, d->te); setTabOrder(le_fname, d->te); setTabOrder(d->te, pb_stop); lb_to->setText(tr("From:")); setWindowTitle(tr("Receive File")); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/download").icon()); #endif le_to->setText(d->jid.full()); le_fname->setText(d->fileName); lb_size->setText(tr("%1 byte(s)").arg(d->fileSize)); d->te->setReadOnly(true); d->te->setText(ft->description()); pb_start->setText(tr("&Accept")); pb_stop->setText(tr("&Reject")); tb_browse->hide(); connect(pb_start, SIGNAL(clicked()), SLOT(doStart())); connect(pb_stop, SIGNAL(clicked()), SLOT(close())); connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout())); lb_status->setText(tr("Ready")); pb_start->setFocus(); d->pa->dialogRegister(this); } FileRequestDlg::~FileRequestDlg() { delete d->ft; if(d->psi) d->psi->dialogUnregister(this); else d->pa->dialogUnregister(this); delete d; } void FileRequestDlg::done(int r) { if(busy->isActive()) { int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel the transfer?"), tr("&Yes"), tr("&No")); if(n != 0) return; // close/reject FT if there is one if(d->ft) { delete d->ft; d->ft = 0; } } QDialog::done(r); } void FileRequestDlg::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Return && ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::AltModifier)) ) { if(pb_start->isEnabled()) doStart(); } else QDialog::keyPressEvent(e); } void FileRequestDlg::updateIdentity(PsiAccount *pa) { if(d->pa) disconnect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected())); if(!pa) { close(); return; } d->pa = pa; connect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected())); } void FileRequestDlg::updateIdentityVisibility() { bool visible = d->pa->psi()->contactList()->enabledAccounts().count() > 1; if (d->cb_ident) d->cb_ident->setVisible(visible); if (d->lb_ident) d->lb_ident->setVisible(visible); d->lb_identity->setVisible(visible); } void FileRequestDlg::pa_disconnected() { //if(busy->isActive()) { // busy->stop(); // close(); //} } void FileRequestDlg::blockWidgets() { if(d->cb_ident) d->cb_ident->setEnabled(false); le_to->setEnabled(false); le_fname->setEnabled(false); tb_browse->setEnabled(false); d->te->setEnabled(false); pb_start->setEnabled(false); } void FileRequestDlg::unblockWidgets() { if(d->cb_ident) d->cb_ident->setEnabled(true); le_to->setEnabled(true); le_fname->setEnabled(true); tb_browse->setEnabled(true); d->te->setEnabled(true); pb_start->setEnabled(true); } void FileRequestDlg::chooseFile() { QString str = FileUtil::getOpenFileName(this, tr("Choose a file"), tr("All files (*)")); if (!str.isEmpty()) { QFileInfo fi(str); le_fname->setText(QDir::convertSeparators(fi.filePath())); lb_size->setText(tr("%1 byte(s)").arg(fi.size())); // TODO: large file support } } void FileRequestDlg::doStart() { if(!d->pa->checkConnected(this)) return; if(d->sending) { Jid to = le_to->text(); if(!to.isValid()) { QMessageBox::information(this, tr("Error"), tr("The Jabber ID specified is not valid. Correct this and try again.")); return; } QFileInfo fi(le_fname->text()); if(!fi.exists()) { QMessageBox::information(this, tr("Error"), tr("The file specified does not exist. Choose a correct file name before sending.")); return; } blockWidgets(); pb_stop->setText(tr("&Cancel")); pb_stop->setFocus(); busy->start(); lb_status->setText(tr("Requesting...")); d->fileName = fi.fileName(); d->fileSize = fi.size(); // TODO: large file support d->ft = new FileTransferHandler(d->pa); connect(d->ft, SIGNAL(accepted()), SLOT(ft_accepted())); connect(d->ft, SIGNAL(statusMessage(const QString &)), SLOT(ft_statusMessage(const QString &))); connect(d->ft, SIGNAL(connected()), SLOT(ft_connected())); connect(d->ft, SIGNAL(error(int, int, const QString &)), SLOT(ft_error(int, int, const QString &))); d->ft->send(le_to->text(), le_fname->text(), d->te->getPlainText()); } else { QString fname, savename; fname = FileUtil::getSaveFileName(this, tr("Save As"), d->fileName, tr("All files (*)")); if(fname.isEmpty()) return; QFileInfo fi(fname); savename = fname + ".part"; fname = fi.fileName(); if(active_file_check(savename)) { QMessageBox::information(this, tr("Error"), tr("This file is being transferred already!")); return; } qlonglong resume_offset = 0; if(!fi.exists()) { // supports resume? check for a .part if(d->ft->resumeSupported()) { QFileInfo fi(savename); if(fi.exists()) resume_offset = fi.size(); } } pb_start->setEnabled(false); le_fname->setText(fname); pb_stop->setText(tr("&Cancel")); pb_stop->setFocus(); busy->start(); lb_status->setText(tr("Accepting...")); d->t.setSingleShot(true); d->t.start(30000); connect(d->ft, SIGNAL(accepted()), SLOT(ft_accepted())); connect(d->ft, SIGNAL(statusMessage(const QString &)), SLOT(ft_statusMessage(const QString &))); connect(d->ft, SIGNAL(connected()), SLOT(ft_connected())); connect(d->ft, SIGNAL(error(int, int, const QString &)), SLOT(ft_error(int, int, const QString &))); d->ft->accept(savename, fname, resume_offset); } } void FileRequestDlg::ft_accepted() { lb_status->setText(tr("Accepted!")); } void FileRequestDlg::ft_statusMessage(const QString &s) { if(!s.isEmpty()) { lb_status->setText(s); } // stop the timer at first activity if(d->t.isActive()) d->t.stop(); } void FileRequestDlg::ft_connected() { d->t.stop(); busy->stop(); FileTransDlg *w = d->pa->psi()->ftdlg(); FileTransferHandler *h = d->ft; d->ft = 0; closeDialogs(this); close(); w->showWithoutActivation(); w->takeTransfer(h, 0, 0); } void FileRequestDlg::ft_error(int x, int fx, const QString &) { d->t.stop(); busy->stop(); delete d->ft; d->ft = 0; closeDialogs(this); if(d->sending) { unblockWidgets(); pb_stop->setText(tr("&Close")); lb_status->setText(tr("Ready")); } QString str; if(x == FileTransferHandler::ErrReject) str = tr("File was rejected by remote user."); else if(x == FileTransferHandler::ErrTransfer) { if(fx == FileTransfer::ErrNeg) str = tr( "Unable to negotiate transfer.\n\n" "This can happen if the contact did not understand our request, or if the\n" "contact is offline." ); else if(fx == FileTransfer::ErrConnect) str = tr( "Unable to connect to peer for data transfer.\n\n" "Ensure that your Data Transfer settings are proper. If you are behind\n" "a NAT router or firewall then you'll need to open the proper TCP port\n" "or specify a Data Transfer Proxy in your account settings." ); else if(fx == FileTransfer::ErrProxy) str = tr( "Failure to either connect to, or activate, the Data Transfer Proxy.\n\n" "This means that the Proxy service is either not functioning or it is\n" "unreachable. If you are behind a firewall, then you'll need to ensure\n" "that outgoing TCP connections are allowed." ); } else str = tr("File I/O error"); QMessageBox::information(this, tr("Error"), str); if(!d->sending || x == FileTransferHandler::ErrReject) close(); } void FileRequestDlg::t_timeout() { delete d->ft; d->ft = 0; busy->stop(); closeDialogs(this); QString str = tr("Unable to accept the file. Perhaps the sender has cancelled the request."); QMessageBox::information(this, tr("Error"), str); close(); } //---------------------------------------------------------------------------- // FileTransDlg //---------------------------------------------------------------------------- class FileTransItem : public Q3ListViewItem { public: QPixmap icon; bool sending; QString name; qlonglong size; QString peer; QString rate; int progress; qlonglong sent; int bps; int timeRemaining; int id; int dist; bool done; QString error; FileTransItem(Q3ListView *parent, const QString &_name, qlonglong _size, const QString &_peer, bool _sending) :Q3ListViewItem(parent) { done = false; sending = _sending; name = _name; size = _size; peer = _peer; rate = FileTransDlg::tr("N/A"); sent = 0; progress = 0; dist = -1; } void niceUnit(qlonglong n, qlonglong *div, QString *unit) { qlonglong gb = 1024 * 1024 * 1024; qlonglong mb = 1024 * 1024; qlonglong kb = 1024; if(n >= gb) { *div = gb; *unit = QString("GB"); } else if(n >= mb) { *div = mb; *unit = QString("MB"); } else if(n >= kb) { *div = kb; *unit = QString("KB"); } else { *div = 1; *unit = QString("B"); } } QString roundedNumber(qlonglong n, qlonglong div) { bool decimal = false; if(div >= 1024) { div /= 10; decimal = true; } qlonglong x_long = n / div; int x = (int)x_long; if(decimal) { double f = (double)x; f /= 10; return QString::number(f, 'f', 1); } else return QString::number(x); } bool setProgress(int _progress, qlonglong _sent, int _bps) { progress = _progress; sent = _sent; bps = _bps; if(bps > 0) { qlonglong rest_long = size - sent; rest_long /= bps; int maxtime = (23 * 60 * 60) + (59 * 60) + (59); // 23h59m59s if(rest_long > maxtime) rest_long = maxtime; timeRemaining = (int)rest_long; } int lastDist = dist; dist = progressBarDist(progressBarWidth()); if(dist != lastDist) return true; else return false; } void updateRate() { QString s; { qlonglong div; QString unit; niceUnit(size, &div, &unit); s = roundedNumber(sent, div) + '/' + roundedNumber(size, div) + unit; if(done) { if(error.isEmpty()) s += QString(" ") + FileTransDlg::tr("[Done]"); else s += QString(" ") + FileTransDlg::tr("[Error: %1]").arg(error); } else if(bps == -1) s += ""; else if(bps == 0) s += QString(" ") + FileTransDlg::tr("[Stalled]"); else { niceUnit(bps, &div, &unit); s += QString(" @ ") + FileTransDlg::tr("%1%2/s").arg(roundedNumber(bps, div)).arg(unit); s += ", "; QTime t = QTime().addSecs(timeRemaining); s += FileTransDlg::tr("%1h%2m%3s remaining").arg(t.hour()).arg(t.minute()).arg(t.second()); } } rate = s; } int progressBarWidth() const { int m = 4; int w = listView()->columnWidth(0); //int pw = (w - (3 * m)) / 2; int pw = (w - (3 * m)) * 2 / 3; return pw; } int progressBarDist(int width) const { int xsize = width - 2; return (progress * xsize / 8192); } void drawProgressBar(QPainter *p, const QColorGroup &cg, int x, int y, int width, int height) const { p->save(); if(isSelected()) p->setPen(cg.highlightedText()); else p->setPen(cg.text()); p->drawRect(x, y, width, height); int xoff = x + 1; int yoff = y + 1; int xsize = width - 2; int ysize = height - 2; int dist = progressBarDist(width); p->fillRect(xoff, yoff, dist, ysize, cg.brush(QColorGroup::Highlight)); p->fillRect(xoff + dist, yoff, width - 2 - dist, ysize, cg.brush(QColorGroup::Base)); int percent = progress * 100 / 8192; QString s = QString::number(percent) + '%'; QFontMetrics fm(p->font()); int ty = ((height - fm.height()) / 2) + fm.ascent() + y; int textwidth = fm.width(s); int center = xoff + (xsize / 2); p->save(); p->setPen(cg.highlightedText()); p->setClipRect(xoff, yoff, dist, ysize); p->drawText(center - (textwidth / 2), ty, s); p->restore(); p->save(); p->setPen(cg.text()); p->setClipRect(xoff + dist, yoff, width - 2 - dist, ysize); p->drawText(center - (textwidth / 2), ty, s); p->restore(); p->restore(); } void setup() { widthChanged(); Q3ListView *lv = listView(); QFontMetrics fm = lv->fontMetrics(); int m = 4; int pm = 2; int ph = fm.height() + 2 + (pm * 2); int h = (ph * 2) + (m * 3); h += lv->itemMargin() * 2; // ensure an even number if(h & 1) ++h; setHeight(h); } QString chopString(const QString &s, const QFontMetrics &fm, int len) const { if(fm.width(s) <= len) return s; QString str; uint n = s.length(); do { str = s.mid(0, --n) + "..."; } while(n > 0 && fm.width(str) > len); return str; } void paintCell(QPainter *mp, const QColorGroup &_cg, int, int width, int) { QColorGroup cg = _cg; int w = width; int h = height(); // tint the background /*//QColor base = Qt::black; //cg.base(); QColor base = Qt::white; int red = base.red(); int green = base.green(); int blue = base.blue(); bool light = false;//true; if(sending) { if(light) { green = green * 15 / 16; blue = blue * 15 / 16; } else { red = 255 - red; red = red * 15 / 16; red = 255 - red; } } else { if(light) { red = red * 15 / 16; blue = blue * 15 / 16; } else { green = 255 - green; green = green * 15 / 16; green = 255 - green; } } base.setRgb(red, green, blue); cg.setColor(QColorGroup::Base, base);*/ QPixmap pix(w, h); QPainter *p = new QPainter(&pix); QFont font = mp->font(); QFont boldFont = font; boldFont.setBold(true); QFontMetrics fm(font); QFontMetrics fmbold(boldFont); QBrush br; // m = margin, pm = progress margin, ph = progress height, yoff = text y offset, // tt = text top, tb = text bottom, pw = progress width, px = progress x coord int m = 4; int pm = 2; int ph = fm.height() + 2 + (pm * 2); int yoff = 1 + pm; int tt = m + yoff + fm.ascent(); int tb = (m * 2) + ph + yoff + fm.ascent(); //int pw = (w - (3 * m)) / 2; int pw = (w - (3 * m)) * 2 / 3; int tw = (w - (3 * m)) - pw; int px = (m * 2) + tw; // clear out the background if(isSelected()) br = cg.brush(QColorGroup::Highlight); else br = cg.brush(QColorGroup::Base); p->fillRect(0, 0, width, h, br); // icon p->drawPixmap(m, m + yoff, icon); int tm = m + icon.width() + 4; tw = tw - (icon.width() + 4); // filename / peer if(isSelected()) p->setPen(cg.highlightedText()); else p->setPen(cg.text()); p->setFont(boldFont); QString s1 = FileTransDlg::tr("File") + ": "; QString s2 = FileTransDlg::tr("To") + ": "; QString s3 = FileTransDlg::tr("From") + ": "; int lw = QMAX(QMAX(fmbold.width(s1), fmbold.width(s2)), fmbold.width(s3)); int left = tw - lw; p->drawText(tm, tt, s1); p->drawText(tm, tb, sending ? s2 : s3); p->setFont(font); p->drawText(tm + lw, tt, chopString(name, fm, left)); p->drawText(tm + lw, tb, chopString(peer, fm, left)); // rate p->setFont(boldFont); s1 = FileTransDlg::tr("Status") + ": "; lw = fmbold.width(s1); left = pw - lw; p->drawText(px, tb, s1); p->setFont(font); p->drawText(px + lw, tb, chopString(rate, fm, left)); // progress bar drawProgressBar(p, cg, px, m, pw, ph); delete p; mp->drawPixmap(0, 0, pix); } QString makeTip() const { QTime t = QTime().addSecs(timeRemaining); QString rem = FileTransDlg::tr("%1h%2m%3s").arg(t.hour()).arg(t.minute()).arg(t.second()); QString s; s += FileTransDlg::tr("Filename") + QString(": %1").arg(name); s += QString("\n") + FileTransDlg::tr("Type") + QString(": %1").arg(sending ? FileTransDlg::tr("Upload") : FileTransDlg::tr("Download")); s += QString("\n") + FileTransDlg::tr("Peer") + QString(": %1").arg(peer); s += QString("\n") + FileTransDlg::tr("Size") + QString(": %1").arg(size); if(done) { s += QString("\n") + FileTransDlg::tr("[Done]"); } else { s += QString("\n") + FileTransDlg::tr("Transferred") + QString(": %1").arg(sent); if(bps > 0) s += QString("\n") + FileTransDlg::tr("Time remaining") + QString(": %1").arg(rem); } return s; } }; class FileTransView : public Q3ListView { Q_OBJECT public: FileTransView(QWidget *parent=0, const char *name=0) :Q3ListView(parent, name) { connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem *, const QPoint &, int)), this, SLOT(qlv_contextMenuRequested(Q3ListViewItem *, const QPoint &, int))); } bool maybeTip(const QPoint &pos) { FileTransItem *i = static_cast(itemAt(pos)); if(!i) return false; QRect r(itemRect(i)); PsiToolTip::showText(mapToGlobal(pos), i->makeTip(), this); return true; } void resizeEvent(QResizeEvent *e) { Q3ListView::resizeEvent(e); if(e->oldSize().width() != e->size().width()) doResize(); } bool event(QEvent* e) { if (e->type() == QEvent::ToolTip) { QPoint pos = ((QHelpEvent*) e)->pos(); e->setAccepted(maybeTip(pos)); return true; } return Q3ListView::event(e); } signals: void itemCancel(int id); void itemOpenDest(int id); void itemClear(int id); private slots: void qlv_contextMenuRequested(Q3ListViewItem *item, const QPoint &pos, int) { if(!item) return; FileTransItem *i = static_cast(item); Q3PopupMenu p; p.insertItem(tr("&Cancel"), 0); p.insertSeparator(); //p.insertItem(tr("&Open Destination Folder"), 1); p.insertItem(tr("Cl&ear"), 2); if(i->done) { p.setItemEnabled(0, false); } else { //p.setItemEnabled(1, false); p.setItemEnabled(2, false); } int x = p.exec(pos); // TODO: what if item is deleted during exec? if(x == 0) { if(!i->done) itemCancel(i->id); } else if(x == 1) itemOpenDest(i->id); else if(x == 2) itemClear(i->id); } private: void doResize() { Q3ListViewItemIterator it(this); for(Q3ListViewItem *i; (i = it.current()); ++it) i->setup(); } }; class TransferMapping { public: FileTransferHandler *h; int id; int p; qlonglong sent; int at; qlonglong last[10]; TransferMapping() { h = 0; at = 0; } ~TransferMapping() { delete h; } void logSent() { // if we're at the end, shift down to make room if(at == 10) { for(int n = 0; n < at - 1; ++n) last[n] = last[n + 1]; --at; } last[at++] = sent; } }; class FileTransDlg::Private { public: FileTransDlg *parent; PsiCon *psi; FileTransView *lv; Q3PtrList transferList; QTimer t; Private(FileTransDlg *_parent) { parent = _parent; transferList.setAutoDelete(true); } int findFreeId() { int n = 0; while(1) { bool found = false; Q3ListViewItemIterator it(lv); for(Q3ListViewItem *i; (i = it.current()); ++it) { FileTransItem *fi = static_cast(i); if(fi->id == n) { found = true; break; } } if(!found) break; ++n; } return n; } FileTransItem *findItem(int id) { Q3ListViewItemIterator it(lv); for(Q3ListViewItem *i; (i = it.current()); ++it) { FileTransItem *fi = static_cast(i); if(fi->id == id) return fi; } return 0; } Q3PtrList getFinished() { Q3PtrList list; Q3ListViewItemIterator it(lv); for(Q3ListViewItem *i; (i = it.current()); ++it) { FileTransItem *fi = static_cast(i); if(fi->done) list.append(fi); } return list; } TransferMapping *findMapping(FileTransferHandler *h) { Q3PtrListIterator it(transferList); for(TransferMapping *i; (i = it.current()); ++it) { if(i->h == h) return i; } return 0; } TransferMapping *findMapping(int id) { Q3PtrListIterator it(transferList); for(TransferMapping *i; (i = it.current()); ++it) { if(i->id == id) return i; } return 0; } void updateProgress(TransferMapping *i, bool updateAll=true) { bool done = (i->p == i->h->totalSteps()); // calculate bps int bps = -1; if(!done && i->at >= 2) { int seconds = i->at - 1; qlonglong average = i->last[i->at-1] - i->last[0]; bps = ((int)average) / seconds; } if(done) { FileTransItem *fi = findItem(i->id); fi->done = true; } parent->setProgress(i->id, i->p, i->h->totalSteps(), i->sent, bps, updateAll); if(done) { bool recv = (i->h->mode() == FileTransferHandler::Receiving); QString fname, savename; if(recv) { fname = i->h->fileName(); savename = i->h->saveName(); } PsiAccount *pa = i->h->account(); transferList.removeRef(i); if(recv) { //printf("fname: [%s], savename: [%s]\n", fname.latin1(), savename.latin1()); // rename .part to original filename QFileInfo fi(savename); QDir dir = fi.dir(); if(dir.exists(fname)) dir.remove(fname); if(!dir.rename(fi.fileName(), fname)) { // TODO: display some error about renaming } } pa->playSound(PsiOptions::instance()->getOption("options.ui.notifications.sounds.completed-file-transfer").toString()); } } }; FileTransDlg::FileTransDlg(PsiCon *psi) :AdvancedWidget(0, psi_dialog_flags) { d = new Private(this); d->psi = psi; //d->psi->dialogRegister(this); connect(&d->t, SIGNAL(timeout()), SLOT(updateItems())); setWindowTitle(tr("Transfer Manager")); #ifndef Q_WS_MAC setWindowIcon(IconsetFactory::icon("psi/filemanager").icon()); #endif QVBoxLayout *vb = new QVBoxLayout(this); vb->setSpacing(6); // FIXME: Is forced spacing really necessary? d->lv = new FileTransView(this); connect(d->lv, SIGNAL(itemCancel(int)), SLOT(itemCancel(int))); connect(d->lv, SIGNAL(itemOpenDest(int)), SLOT(itemOpenDest(int))); connect(d->lv, SIGNAL(itemClear(int)), SLOT(itemClear(int))); vb->addWidget(d->lv); QHBoxLayout *hb = new QHBoxLayout; vb->addLayout(hb); hb->addStretch(1); QPushButton *pb_clear = new QPushButton(tr("Clear &Finished"), this); connect(pb_clear, SIGNAL(clicked()), SLOT(clearFinished())); hb->addWidget(pb_clear); QPushButton *pb_close = new QPushButton(tr("&Hide"), this); connect(pb_close, SIGNAL(clicked()), SLOT(close())); hb->addWidget(pb_close); pb_close->setDefault(true); pb_close->setFocus(); d->lv->addColumn(""); d->lv->header()->hide(); d->lv->setResizeMode(Q3ListView::LastColumn); d->lv->setAllColumnsShowFocus(true); d->lv->setSorting(-1); resize(560, 240); } FileTransDlg::~FileTransDlg() { //d->psi->dialogUnregister(this); delete d; } int FileTransDlg::addItem(const QString &filename, qlonglong size, const QString &peer, bool sending) { int id = d->findFreeId(); FileTransItem *i = new FileTransItem(d->lv, filename, size, peer, sending); if(sending) i->icon = IconsetFactory::icon("psi/upload").impix().pixmap(); else i->icon = IconsetFactory::icon("psi/download").impix().pixmap(); i->id = id; d->t.start(1000); return id; } void FileTransDlg::setProgress(int id, int step, int total, qlonglong sent, int bytesPerSecond, bool updateAll) { FileTransItem *i = d->findItem(id); if(i) { // convert steps/total into a word int progress; if(total > 0) progress = step * 8192 / total; else progress = 8192; bool do_repaint = i->setProgress(progress, sent, bytesPerSecond); if(updateAll) { i->updateRate(); do_repaint = true; } if(do_repaint) i->repaint(); } } void FileTransDlg::removeItem(int id) { FileTransItem *i = d->findItem(id); if(i) delete i; if(d->lv->childCount() == 0) d->t.stop(); } void FileTransDlg::setError(int id, const QString &reason) { FileTransItem *i = d->findItem(id); if(i) { i->done = true; i->error = reason; i->updateRate(); i->repaint(); show(); d->lv->ensureItemVisible(i); QMessageBox::information(this, tr("Transfer Error"), tr("Transfer of %1 with %2 failed.\nReason: %3").arg(i->name).arg(i->peer).arg(reason)); } } void FileTransDlg::takeTransfer(FileTransferHandler *h, int p, qlonglong sent) { QString peer; UserListItem *u = h->account()->findFirstRelevant(h->peer()); if(u) peer = JIDUtil::nickOrJid(u->name(),u->jid().full()); else peer = h->peer().full(); TransferMapping *i = new TransferMapping; i->h = h; i->id = addItem(h->fileName(), h->fileSize(), peer, (h->mode() == FileTransferHandler::Sending)); i->p = p; i->sent = sent; d->transferList.append(i); FileTransItem *fi = d->findItem(i->id); d->lv->ensureItemVisible(fi); if(p == i->h->totalSteps()) { d->updateProgress(i, true); } else { connect(h, SIGNAL(progress(int, qlonglong)), SLOT(ft_progress(int, qlonglong))); connect(h, SIGNAL(error(int, int, const QString &)), SLOT(ft_error(int, int, const QString &))); } } void FileTransDlg::clearFinished() { Q3PtrList list = d->getFinished(); { // remove related transfer mappings Q3PtrListIterator it(list); for(FileTransItem *fi; (fi = it.current()); ++it) { TransferMapping *i = d->findMapping(fi->id); d->transferList.removeRef(i); } } list.setAutoDelete(true); list.clear(); } void FileTransDlg::ft_progress(int p, qlonglong sent) { TransferMapping *i = d->findMapping((FileTransferHandler *)sender()); i->p = p; i->sent = sent; if(p == i->h->totalSteps()) d->updateProgress(i, true); else d->updateProgress(i, false); } void FileTransDlg::ft_error(int x, int, const QString &s) { TransferMapping *i = d->findMapping((FileTransferHandler *)sender()); int id = i->id; d->transferList.removeRef(i); QString str; //if(x == FileTransferHandler::ErrReject) // str = tr("File was rejected by remote user."); if(x == FileTransferHandler::ErrTransfer) str = s; else str = tr("File I/O error (%1)").arg(s); setError(id, str); } void FileTransDlg::updateItems() { // operate on a copy so that we can delete items in updateProgress Q3PtrList list = d->transferList; Q3PtrListIterator it(list); for(TransferMapping *i; (i = it.current()); ++it) { if(i->h) { i->logSent(); d->updateProgress(i); } } } void FileTransDlg::itemCancel(int id) { FileTransItem *fi = d->findItem(id); TransferMapping *i = d->findMapping(id); d->transferList.removeRef(i); delete fi; } void FileTransDlg::itemOpenDest(int id) { TransferMapping *i = d->findMapping(id); QString path; bool recv = (i->h->mode() == FileTransferHandler::Receiving); if(recv) path = QFileInfo(i->h->saveName()).path(); else path = QFileInfo(i->h->fileName()).path(); //printf("item open dest: [%s]\n", path.latin1()); } void FileTransDlg::itemClear(int id) { FileTransItem *fi = d->findItem(id); TransferMapping *i = d->findMapping(id); d->transferList.removeRef(i); delete fi; } void FileTransDlg::killTransfers(PsiAccount *pa) { Q3PtrList list = d->transferList; Q3PtrListIterator it(list); for(TransferMapping *i; (i = it.current()); ++it) { // this account? if(i->h->account() == pa) { FileTransItem *fi = d->findItem(i->id); d->transferList.removeRef(i); delete fi; } } } #include "filetransdlg.moc" psi-0.14/src/bookmarkmanagedlg.cpp0000644000175000017500000001533111305557613015304 0ustar janjan/* * bookmarkmanagedlg.cpp - manage groupchat room bookmarks * Copyright (C) 2008 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bookmarkmanagedlg.h" #include #include #include #include "bookmarkmanager.h" #include "psiaccount.h" BookmarkManageDlg::BookmarkManageDlg(PsiAccount* account) : QDialog() , account_(account) , model_(0) { setAttribute(Qt::WA_DeleteOnClose, true); ui_.setupUi(this); account_->dialogRegister(this); QAction* removeBookmarkAction = new QAction(this); connect(removeBookmarkAction, SIGNAL(triggered()), SLOT(removeBookmark())); removeBookmarkAction->setShortcuts(QKeySequence::Delete); ui_.listView->addAction(removeBookmarkAction); addButton_ = ui_.bookmarkButtonBox->addButton(tr("&Add"), QDialogButtonBox::ActionRole); removeButton_ = ui_.bookmarkButtonBox->addButton(tr("&Remove"), QDialogButtonBox::DestructiveRole); joinButton_ = ui_.bookmarkButtonBox->addButton(tr("&Join"), QDialogButtonBox::ActionRole); connect(addButton_, SIGNAL(clicked()), SLOT(addBookmark())); connect(removeButton_, SIGNAL(clicked()), SLOT(removeBookmark())); connect(joinButton_, SIGNAL(clicked()), SLOT(joinCurrentRoom())); model_ = new QStandardItemModel(this); ui_.listView->setModel(model_); connect(ui_.listView->itemDelegate(), SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)), SLOT(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint))); connect(ui_.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(selectionChanged(const QItemSelection&, const QItemSelection&))); connect(ui_.host, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(ui_.room, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(ui_.nickname, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(ui_.password, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem())); connect(ui_.autoJoin, SIGNAL(clicked(bool)), SLOT(updateCurrentItem())); loadBookmarks(); QItemSelection dummy; selectionChanged(dummy, dummy); } BookmarkManageDlg::~BookmarkManageDlg() { account_->dialogUnregister(this); } void BookmarkManageDlg::reject() { QDialog::reject(); } void BookmarkManageDlg::accept() { if (account_->checkConnected(this)) { saveBookmarks(); QDialog::accept(); } } void BookmarkManageDlg::loadBookmarks() { model_->clear(); foreach(ConferenceBookmark c, account_->bookmarkManager()->conferences()) { QStandardItem* item = new QStandardItem(c.name()); item->setData(QVariant(c.jid().full()), JidRole); item->setData(QVariant(c.autoJoin()), AutoJoinRole); item->setData(QVariant(c.nick()), NickRole); item->setData(QVariant(c.password()), PasswordRole); appendItem(item); } } ConferenceBookmark BookmarkManageDlg::bookmarkFor(const QModelIndex& index) const { return ConferenceBookmark(index.data(Qt::DisplayRole).toString(), index.data(JidRole).toString(), index.data(AutoJoinRole).toBool(), index.data(NickRole).toString(), index.data(PasswordRole).toString()); } void BookmarkManageDlg::saveBookmarks() { QList conferences; for (int row = 0; row < model_->rowCount(); ++row) { QModelIndex index = model_->index(row, 0, QModelIndex()); conferences += bookmarkFor(index); } account_->bookmarkManager()->setBookmarks(conferences); } void BookmarkManageDlg::addBookmark() { QStandardItem* item = new QStandardItem(tr("Unnamed")); appendItem(item); ui_.listView->reset(); // ensure that open editors won't get in our way ui_.listView->setCurrentIndex(item->index()); ui_.listView->edit(item->index()); } void BookmarkManageDlg::removeBookmark() { model_->removeRow(currentIndex().row()); } void BookmarkManageDlg::closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint) { Q_UNUSED(editor); if (hint == QAbstractItemDelegate::SubmitModelCache) { QList lineEdits; lineEdits << ui_.host << ui_.room << ui_.nickname; foreach(QLineEdit* lineEdit, lineEdits) { if (lineEdit->text().isEmpty()) { lineEdit->setFocus(); break; } } } } void BookmarkManageDlg::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { Q_UNUSED(deselected); QModelIndex current; if (!selected.indexes().isEmpty()) current = selected.indexes().first(); XMPP::Jid jid = XMPP::Jid(current.data(JidRole).toString()); ui_.host->setText(jid.domain()); ui_.room->setText(jid.node()); ui_.nickname->setText(current.data(NickRole).toString()); ui_.password->setText(current.data(PasswordRole).toString()); ui_.autoJoin->setChecked(current.data(AutoJoinRole).toBool()); QList editors; editors << ui_.host << ui_.room << ui_.nickname << ui_.password << ui_.autoJoin; foreach(QWidget* w, editors) { w->setEnabled(current.isValid()); } removeButton_->setEnabled(current.isValid()); updateCurrentItem(); } XMPP::Jid BookmarkManageDlg::jid() const { return XMPP::Jid(ui_.room->text(), ui_.host->text()); } void BookmarkManageDlg::updateCurrentItem() { joinButton_->setEnabled(!jid().domain().isEmpty() && !jid().node().isEmpty() && !ui_.nickname->text().isEmpty()); QStandardItem* item = model_->item(currentIndex().row()); if (item) { item->setData(QVariant(jid().full()), JidRole); item->setData(QVariant(ui_.autoJoin->isChecked()), AutoJoinRole); item->setData(QVariant(ui_.nickname->text()), NickRole); item->setData(QVariant(ui_.password->text()), PasswordRole); } } QModelIndex BookmarkManageDlg::currentIndex() const { if (!ui_.listView->selectionModel()->selectedIndexes().isEmpty()) return ui_.listView->selectionModel()->selectedIndexes().first(); return QModelIndex(); } void BookmarkManageDlg::joinCurrentRoom() { account_->actionJoin(bookmarkFor(currentIndex()), true); } void BookmarkManageDlg::appendItem(QStandardItem* item) { item->setDragEnabled(true); item->setDropEnabled(false); model_->invisibleRootItem()->appendRow(item); } psi-0.14/src/mcmdsimplesite.cpp0000644000175000017500000000310411305557613014651 0ustar janjan/* * Copyright (C) 2008 Martin Hostettler * * 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 2 * 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, see . * */ // simple UI integration for mini command system. #include #include #include #include #include #include "mcmdsimplesite.h" void MCmdSimpleSite::mCmdReady(const QString prompt, const QString def) { if (!open) mini_msg_swap = inputWidget->toPlainText(); open = true; promptWidget->setText(prompt); inputWidget->setText(def); inputWidget->setPalette(cmdPalette); promptWidget->show(); } void MCmdSimpleSite::mCmdClose() { open = false; inputWidget->setText(mini_msg_swap); inputWidget->setPalette(palette); promptWidget->hide(); } void MCmdSimpleSite::setInput(QTextEdit *i) { inputWidget = i; palette = inputWidget->palette(); cmdPalette = palette; cmdPalette.setBrush(QPalette::Base, QToolTip::palette().brush(QPalette::ToolTipBase)); cmdPalette.setBrush(QPalette::Text, QToolTip::palette().brush(QPalette::ToolTipText)); } psi-0.14/src/accountregdlg.h0000644000175000017500000000533411305557613014127 0ustar janjan/* * accountregdlg.h * Copyright (C) 2001, 2002, 2006 Justin Karneges, Remko Troncon * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ACCOUNTREGDLG_H #define ACCOUNTREGDLG_H #include #include #include "profiles.h" #include "xmpp_jid.h" #include "ui_accountreg.h" class ProxyManager; class ProxyChooser; class QWidget; class QScrollArea; class QStringList; class MiniClient; class XDataWidget; class ServerListQuerier; class QByteArray; namespace XMPP { class Form; class XData; } class AccountRegDlg : public QDialog { Q_OBJECT public: AccountRegDlg(ProxyManager*, QWidget *parent=0); ~AccountRegDlg(); const XMPP::Jid& jid() const { return jid_; } const QString& pass() const { return pass_; } bool useHost() const { return opt_host_; } const QString& host() const { return host_; } int port() const { return port_; } bool legacySSLProbe() { return legacy_ssl_probe_; } UserAccount::SSLFlag ssl() const { return ssl_; } QString proxy() const { return proxy_; } QString tlsOverrideDomain() { return tlsOverrideDomain_; }; QByteArray tlsOverrideCert() { return tlsOverrideCert_; }; public slots: void done(int); protected: static XMPP::XData convertToXData(const XMPP::Form&); static XMPP::Form convertFromXData(const XMPP::XData&); bool checkSSL(); void block(); void unblock(); protected slots: void hostToggled(bool); void sslActivated(int); void next(); void selectServer(); void serverListReceived(const QStringList&); void serverListError(const QString&); void client_handshaken(); void client_error(); void getFields_finished(); void setFields_finished(); private: Ui::AccountReg ui_; QScrollArea* fields_container_; XDataWidget* fields_; ProxyManager *proxy_manager_; ProxyChooser *proxy_chooser_; ServerListQuerier *serverlist_querier_; MiniClient *client_; bool isOld_; // Account settings XMPP::Jid jid_, server_; UserAccount::SSLFlag ssl_; bool opt_host_, legacy_ssl_probe_; QString host_; int port_; QString pass_; QString proxy_; QString tlsOverrideDomain_; QByteArray tlsOverrideCert_; }; #endif psi-0.14/src/protocol/0000755000175000017500000000000011305557613012771 5ustar janjanpsi-0.14/src/protocol/discoinfoquerier.h0000644000175000017500000000225411305557613016517 0ustar janjan#ifndef DISCOINFOQUERIER_H #define DISCOINFOQUERIER_H #include namespace XMPP { class Jid; class DiscoItem; }; namespace Protocol { /** * A DiscoInfoQuerier is an object used to query Service Discovery information. */ class DiscoInfoQuerier : public QObject { Q_OBJECT public: /** * Retrieves Disco information of a jid on a specific node. */ virtual void getDiscoInfo(const XMPP::Jid& jid, const QString& node) = 0; signals: /** * Signals that a disco information request was succesful. * * @param jid the jid on which the request was done * @param node the node on which the request was done * @param item the resulting disco item. */ void getDiscoInfo_success(const XMPP::Jid& jid, const QString& node, const XMPP::DiscoItem& item); /** * Signals that a disco information request returned an error. * * @param jid the jid on which the request was done * @param node the node on which the request was done * @param error_code the error code of the error * @param error_string the error text of the error */ void getDiscoInfo_error(const XMPP::Jid& jid, const QString& node, int error_code, const QString& error_string); }; }; #endif psi-0.14/src/protocol/protocol.pri0000644000175000017500000000004711305557613015347 0ustar janjanHEADERS += \ $$PWD/discoinfoquerier.h psi-0.14/src/chatdlg.ui0000644000175000017500000002310611305557613013077 0ustar janjan ChatDlg 0 0 400 300 Form 4 6 Qt::Vertical 5 3 0 0 QFrame::NoFrame QFrame::Plain 0 4 0 4 16 16 16 16 Qt::NoFocus true 0 5 0 0 40 0 40 16777215 Message length QFrame::Panel QFrame::Sunken 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 5 0 0 AccountLabel Toggle encryption 16 16 Select icon 16 16 QToolButton::InstantPopup Actions 16 16 QToolButton::InstantPopup Qt::DownArrow 7 3 0 0 Qt::NoFocus true 5 4 0 0 QFrame::NoFrame QFrame::Plain 0 6 5 4 0 0 Qt::Horizontal 0 4 0 6 75 true 7 5 0 0 5 4 0 0 Avatar ChatView QTextEdit
msgmle.h
ChatSplitter QSplitter
chatsplitter.h
ChatEditProxy QTextEdit
chateditproxy.h
AccountLabel QLabel
accountlabel.h
IconLabel QLabel
iconlabel.h
psi-0.14/src/chateditproxy.h0000644000175000017500000000325311305557613014173 0ustar janjan/* * chateditproxy.h - abstraction to change ChatEdit type in runtime * Copyright (C) 2007 Michail Pishchagin * * 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 2 * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CHATEDITPROXY_H #define CHATEDITPROXY_H #include class QTextEdit; class QLayout; class ChatEdit; class ChatEditProxy : public QWidget { Q_OBJECT public: ChatEditProxy(QWidget* parent); /** * Returns encapsulated QTextEdit widget. */ ChatEdit* chatEdit() const { return textEdit_; } signals: /** * Emitted when internal QTextEdit gets replaced with * another one. */ void textEditCreated(QTextEdit* textEdit); protected: /** * Returns true if line edit mode is enabled. */ bool lineEditEnabled() const { return lineEditEnabled_; } void setLineEditEnabled(bool enable); public slots: void optionsChanged(); private: virtual ChatEdit* createTextEdit(); void moveData(QTextEdit* newTextEdit, QTextEdit* oldTextEdit) const; void updateLayout(); bool lineEditEnabled_; ChatEdit* textEdit_; QLayout* layout_; }; #endif psi-0.14/src/accountremove.ui0000644000175000017500000000634511305557613014351 0ustar janjan AccountRemove 0 0 459 186 Remove Account Remove Account Remove account from Psi only. Remove account and try to unregister it from the server. Password: 100 32767 QLineEdit::Password Qt::Horizontal QSizePolicy::Expanding 0 0 Qt::Vertical QSizePolicy::Expanding 16 0 QDialogButtonBox::Cancel qPixmapFromMimeSource BusyWidget QWidget
busywidget.h
1
psi-0.14/src/showtextdlg.h0000644000175000017500000000215011305557613013653 0ustar janjan/* * showtextdlg.h - dialog for displaying a text file * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_SHOWTEXTDLG_H #define CS_SHOWTEXTDLG_H #include class ShowTextDlg : public QDialog { Q_OBJECT public: ShowTextDlg(const QString &fname, bool rich=FALSE, QWidget *parent=0); ShowTextDlg(const QString &text, bool nonfile, bool rich, QWidget *parent); }; #endif psi-0.14/psi.pro0000644000175000017500000000066411305557613011664 0ustar janjanTEMPLATE = subdirs include(conf.pri) windows:include(conf_windows.pri) # configure iris unix:system("echo \"include(../src/conf_iris.pri)\" > iris/conf.pri") windows:system("echo include(../src/conf_iris.pri) > iris\\conf.pri") qca-static { sub_qca.subdir = third-party/qca sub_iris.depends = sub_qca SUBDIRS += sub_qca } sub_iris.subdir = iris sub_src.subdir = src sub_src.depends = sub_iris SUBDIRS += \ sub_iris \ sub_src psi-0.14/psi.desktop0000644000175000017500000000406711305557613012536 0ustar janjan[Desktop Entry] # This is the spec version, *not* the application version Version=1.0 Type=Application Name=Psi GenericName=Jabber Client Comment=Communicate over the Jabber network Icon=psi Exec=psi Terminal=false Categories=Network;InstantMessaging;Qt; # Translations GenericName[be]=Кліент Jabber Comment[be]=Размаўляйце ў сетцы Jabber GenericName[bg]=Jabber Клиент Comment[bg]=Комуникирайте през Jabber мрежата GenericName[ca]=Client Jabber Comment[ca]=Comuniqui's a través de la xarxa Jabber GenericName[cs]=Jabber Klient Comment[cs]=Komunikujte přes Jabber po síti GenericName[de]=Jabber-Programm Comment[de]=Im Jabber-Netzwerk kommunizieren GenericName[eo]=Ĵabbera Klientilo Comment[eo]=Komunikiĝu per la ĵabbera reto GenericName[es]=Cliente Jabber Comment[es]=Comunícate a través de la red Jabber GenericName[fr]=Client Jabber Comment[fr]=Communiquez via le réseau Jabber GenericName[it]=Client Jabber Comment[it]=Comunica sulla rete Jabber GenericName[ja]=Jabberクライアント Comment[ja]=Jabberネットーワーク通信 GenericName[mk]=Клиент за Jabber Comment[mk]=Комуницирајте преку Jabber мрежата GenericName[nl]=Jabber Client Comment[nl]=Communiceer over het Jabber netwerk GenericName[pl]=Klient XMPP Comment[pl]=Komunikacja poprzez sieć XMPP GenericName[pt_BR]=Cliente Jabber Comment[pt_BR]=Comunique-se através da rede Jabber GenericName[ru]=Jabber-клиент Comment[ru]=Общение в сети Jabber GenericName[sl]=Odjemalec za Jabber/XMPP Comment[sl]=Takojšnje sporočanje prek omrežij Jabber/XMPP GenericName[sv]=Jabberklient Comment[sv]=Kommunicera över Jabbernätverket GenericName[uk]=Jabber клієнт Comment[uk]=Програма для спілкування в мережі jabber. GenericName[ur_PK]=جیبر وصول کار Comment[ur_PK]=جیبر نیٹ ورک پر مواصلت کریں GenericName[vi]=Ứng dụng khách Jabber Comment[vi]=Liên lạc qua mạng Jabber nhé GenericName[zh_TW]=Jabber 客戶端 Comment[zh_TW]=在 Jabber 網路上交談 psi-0.14/conf_windows.pri0000644000175000017500000000121711305557613013555 0ustar janjan!exists(conf.pri) { # Windows build settings CONFIG += release #CONFIG += qca-static # tell iris to use our internal libz CONFIG += psi-zip # OpenSSL qca-static { DEFINES += HAVE_OPENSSL DEFINES += OSSL_097 OPENSSL_PREFIX = /local INCLUDEPATH += $$OPENSSL_PREFIX/include LIBS += -L$$OPENSSL_PREFIX/lib } # SASL #qca-static { # CYRUSSASL_PREFIX = /local # INCLUDEPATH += $$CYRUSSASL_PREFIX/include # LIBS += $$CYRUSSASL_PREFIX/lib/libsasl.lib #} # ASpell #DEFINES += HAVE_ASPELL contains(DEFINES, HAVE_ASPELL) { ASPELL_PREFIX = ../../../aspell INCLUDEPATH += "$$ASPELL_PREFIX/include" LIBS += -L"$$ASPELL_PREFIX/lib" LIBS += -laspell-15 } } psi-0.14/iris/0000755000175000017500000000000011305557617011313 5ustar janjanpsi-0.14/iris/common.pri0000644000175000017500000000064311305557616013321 0ustar janjan# common stuff for iris.pro and iris.pri # FIXME: Remove this DEFINES += IRIS_XMPP_JID_DEPRECATED # default build configuration !iris_build_pri { # build appledns on mac mac:CONFIG += appledns # bundle appledns inside of irisnetcore on mac mac:CONFIG += appledns_bundle # bundle irisnetcore inside of iris CONFIG += irisnetcore_bundle # don't build iris, app will include iris.pri #CONFIG += iris_bundle } psi-0.14/iris/conf_win.pri.example0000644000175000017500000000043211305557616015261 0ustar janjanload(winlocal.prf) # qca CONFIG += crypto # zlib INCLUDEPATH += $$WINLOCAL_PREFIX/include LIBS += -L$$WINLOCAL_PREFIX/lib # zlib may have a different lib name depending on how it was compiled win32-g++ { LIBS += -lz } else { LIBS += -lzlib # static #LIBS += -lzdll # dll } psi-0.14/iris/configure0000755000175000017500000012326011305557616013225 0ustar janjan#!/bin/sh # # Generated by qconf 1.5 ( http://delta.affinix.com/qconf/ ) # show_usage() { cat </dev/null` if echo $WHICH | grep 'shell built-in command' >/dev/null 2>&1; then WHICH=which elif [ -z "$WHICH" ]; then if which which >/dev/null 2>&1; then WHICH=which else for a in /usr/ucb /usr/bin /bin /usr/local/bin; do if [ -x $a/which ]; then WHICH=$a/which break; fi done fi fi if [ -z "$WHICH" ]; then OLD_IFS=$IFS IFS=: for a in $PATH; do if [ -x $a/$1 ]; then echo "$a/$1" IFS=$OLD_IFS export IFS HOME=$OLD_HOME export HOME return 0 fi done IFS=$OLD_IFS export IFS else a=`"$WHICH" "$1" 2>/dev/null` if [ ! -z "$a" -a -x "$a" ]; then echo "$a" HOME=$OLD_HOME export HOME return 0 fi fi HOME=$OLD_HOME export HOME return 1 } WHICH=which_command # find a make command if [ -z "$MAKE" ]; then MAKE= for mk in gmake make; do if $WHICH $mk >/dev/null 2>&1; then MAKE=`$WHICH $mk` break fi done if [ -z "$MAKE" ]; then echo "You don't seem to have 'make' or 'gmake' in your PATH." echo "Cannot proceed." exit 1 fi fi show_qt_info() { printf "Be sure you have a proper Qt 4.0 build environment set up. This means not\n" printf "just Qt, but also a C++ compiler, a make tool, and any other packages\n" printf "necessary for compiling C++ programs.\n" printf "\n" printf "If you are certain everything is installed, then it could be that Qt 4 is not\n" printf "being recognized or that a different version of Qt is being detected by\n" printf "mistake (for example, this could happen if \$QTDIR is pointing to a Qt 3\n" printf "installation). At least one of the following conditions must be satisfied:\n" printf "\n" printf " 1) --qtdir is set to the location of Qt\n" printf " 2) \$QTDIR is set to the location of Qt\n" printf " 3) QtCore is in the pkg-config database\n" printf " 4) qmake is in the \$PATH\n" printf "\n" printf "This script will use the first one it finds to be true, checked in the above\n" printf "order. #3 and #4 are the recommended options. #1 and #2 are mainly for\n" printf "overriding the system configuration.\n" printf "\n" } while [ $# -gt 0 ]; do optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` case "$1" in --qtdir=*) EX_QTDIR=$optarg shift ;; --static) QC_STATIC="Y" shift ;; --release) QC_RELEASE="Y" shift ;; --debug) QC_DEBUG="Y" shift ;; --debug-and-release) QC_DEBUG_AND_RELEASE="Y" shift ;; --no-separate-debug-info) QC_NO_SEPARATE_DEBUG_INFO="Y" shift ;; --separate-debug-info) QC_SEPARATE_DEBUG_INFO="Y" shift ;; --no-framework) QC_NO_FRAMEWORK="Y" shift ;; --framework) QC_FRAMEWORK="Y" shift ;; --universal) QC_UNIVERSAL="Y" shift ;; --mac-sdk=*) QC_MAC_SDK=$optarg shift ;; --disable-tests) QC_DISABLE_TESTS="Y" shift ;; --with-qca=*) QC_WITH_QCA=$optarg shift ;; --with-zlib-inc=*) QC_WITH_ZLIB_INC=$optarg shift ;; --with-zlib-lib=*) QC_WITH_ZLIB_LIB=$optarg shift ;; --verbose) QC_VERBOSE="Y" shift ;; --help) show_usage; exit ;; *) show_usage; exit ;; esac done echo "Configuring Iris ..." if [ "$QC_VERBOSE" = "Y" ]; then echo echo EX_QTDIR=$EX_QTDIR echo QC_STATIC=$QC_STATIC echo QC_RELEASE=$QC_RELEASE echo QC_DEBUG=$QC_DEBUG echo QC_DEBUG_AND_RELEASE=$QC_DEBUG_AND_RELEASE echo QC_NO_SEPARATE_DEBUG_INFO=$QC_NO_SEPARATE_DEBUG_INFO echo QC_SEPARATE_DEBUG_INFO=$QC_SEPARATE_DEBUG_INFO echo QC_NO_FRAMEWORK=$QC_NO_FRAMEWORK echo QC_FRAMEWORK=$QC_FRAMEWORK echo QC_UNIVERSAL=$QC_UNIVERSAL echo QC_MAC_SDK=$QC_MAC_SDK echo QC_DISABLE_TESTS=$QC_DISABLE_TESTS echo QC_WITH_QCA=$QC_WITH_QCA echo QC_WITH_ZLIB_INC=$QC_WITH_ZLIB_INC echo QC_WITH_ZLIB_LIB=$QC_WITH_ZLIB_LIB echo fi printf "Verifying Qt 4 build environment ... " # run qmake -v and check version qmake_check_v4() { if [ -x "$1" ]; then if echo `$1 -v 2>&1` | grep "Qt version 4\." >/dev/null 2>&1; then return 0 elif [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: $1 not for Qt 4" fi fi return 1 } if [ "$QC_VERBOSE" = "Y" ]; then echo fi qm="" names="qmake-qt4 qmake4 qmake" # qt4 check: --qtdir if [ -z "$qm" ] && [ ! -z "$EX_QTDIR" ]; then for n in $names; do qstr=$EX_QTDIR/bin/$n if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via --qtdir" fi # qt4 check: QTDIR if [ -z "$qm" ] && [ ! -z "$QTDIR" ]; then for n in $names; do qstr=$QTDIR/bin/$n if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via \$QTDIR" fi # qt4 check: pkg-config if [ -z "$qm" ]; then str=`pkg-config QtCore --variable=exec_prefix 2>/dev/null` if [ ! -z "$str" ]; then for n in $names; do qstr=$str/bin/$n if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via pkg-config" fi # qt4 check: PATH if [ -z "$qm" ]; then for n in $names; do qstr=`$WHICH $n 2>/dev/null` if qmake_check_v4 "$qstr"; then qm=$qstr break; fi done fi if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then echo "Warning: qmake not found via \$PATH" fi if [ -z "$qm" ]; then if [ "$QC_VERBOSE" = "Y" ]; then echo " -> fail" else echo "fail" fi printf "\n" printf "Reason: Unable to find the 'qmake' tool for Qt 4.\n" printf "\n" show_qt_info exit 1; fi if [ "$QC_VERBOSE" = "Y" ]; then echo qmake found in $qm fi # try to determine the active makespec defmakespec=$QMAKESPEC if [ -z "$defmakespec" ]; then if $WHICH readlink >/dev/null 2>&1; then READLINK=`$WHICH readlink` fi if [ ! -z "$READLINK" ]; then qt_mkspecsdir=`$qm -query QT_INSTALL_DATA`/mkspecs if [ -d "$qt_mkspecsdir" ] && [ -h "$qt_mkspecsdir/default" ]; then defmakespec=`$READLINK $qt_mkspecsdir/default` fi fi fi if [ "$QC_VERBOSE" = "Y" ]; then echo makespec is $defmakespec fi qm_spec="" # if the makespec is macx-xcode, force macx-g++ if [ "$defmakespec" = "macx-xcode" ]; then qm_spec=macx-g++ QMAKESPEC=$qm_spec export QMAKESPEC if [ "$QC_VERBOSE" = "Y" ]; then echo overriding makespec to $qm_spec fi fi gen_files() { cat >$1/modules.cpp <= 4.2 -----END QCMOD----- */ class qc_qt42 : public ConfObj { public: qc_qt42(Conf *c) : ConfObj(c) {} QString name() const { return "Qt >= 4.2"; } QString shortname() const { return "qt42"; } bool exec() { conf->debug(QString("QT_VERSION = 0x%1").arg(QString::number(QT_VERSION, 16))); if(QT_VERSION >= 0x040200) return true; else return false; } }; #line 1 "buildmode.qcm" /* -----BEGIN QCMOD----- name: buildmode section: project arg: release,Build with debugging turned off (default). arg: debug,Build with debugging turned on. arg: debug-and-release,Build two versions, with and without debugging turned on (mac only). arg: no-separate-debug-info,Do not store debug information in a separate file (default for mac). arg: separate-debug-info,Strip debug information into a separate .debug file (default for non-mac). arg: no-framework,Do not build as a Mac framework. arg: framework,Build as a Mac framework (default). -----END QCMOD----- */ #define QC_BUILDMODE bool qc_buildmode_release = false; bool qc_buildmode_debug = false; bool qc_buildmode_framework = false; bool qc_buildmode_separate_debug_info = false; class qc_buildmode : public ConfObj { public: qc_buildmode(Conf *c) : ConfObj(c) {} QString name() const { return "buildmode"; } QString shortname() const { return "buildmode"; } // no output QString checkString() const { return QString(); } bool exec() { // first, parse out the options bool opt_release = false; bool opt_debug = false; bool opt_debug_and_release = false; bool opt_no_framework = false; bool opt_framework = false; bool opt_no_separate_debug_info = false; bool opt_separate_debug_info = false; if(conf->getenv("QC_RELEASE") == "Y") opt_release = true; if(conf->getenv("QC_DEBUG") == "Y") opt_debug = true; if(conf->getenv("QC_DEBUG_AND_RELEASE") == "Y") opt_debug_and_release = true; if(conf->getenv("QC_NO_FRAMEWORK") == "Y") opt_no_framework = true; if(conf->getenv("QC_FRAMEWORK") == "Y") opt_framework = true; if(conf->getenv("QC_NO_SEPARATE_DEBUG_INFO") == "Y") opt_no_separate_debug_info = true; if(conf->getenv("QC_SEPARATE_DEBUG_INFO") == "Y") opt_separate_debug_info = true; bool staticmode = false; if(conf->getenv("QC_STATIC") == "Y") staticmode = true; #ifndef Q_OS_MAC if(opt_debug_and_release) { printf("\nError: The --debug-and-release option is for mac only.\n"); exit(1); } if(opt_framework) { printf("\nError: The --framework option is for mac only.\n"); exit(1); } #endif if(opt_framework && opt_debug) { printf("\nError: Cannot use both --framework and --debug.\n"); exit(1); } // sanity check exclusive options int x; // build mode x = 0; if(opt_release) ++x; if(opt_debug) ++x; if(opt_debug_and_release) ++x; if(x > 1) { printf("\nError: Use only one of --release, --debug, or --debug-and-release.\n"); exit(1); } // framework if(opt_framework && staticmode) { printf("\nError: Cannot use both --framework and --static.\n"); exit(1); } x = 0; if(opt_no_framework) ++x; if(opt_framework) ++x; if(x > 1) { printf("\nError: Use only one of --framework or --no-framework.\n"); exit(1); } // debug info x = 0; if(opt_no_separate_debug_info) ++x; if(opt_separate_debug_info) ++x; if(x > 1) { printf("\nError: Use only one of --separate-debug-info or --no-separate-debug-info\n"); exit(1); } // now process the options if(opt_release) qc_buildmode_release = true; else if(opt_debug) qc_buildmode_debug = true; else if(opt_debug_and_release) { qc_buildmode_release = true; qc_buildmode_debug = true; } else // default qc_buildmode_release = true; if(opt_framework) qc_buildmode_framework = true; else if(opt_no_framework) { // nothing to do } else // default { if(!staticmode && !opt_debug) qc_buildmode_framework = true; } if(opt_separate_debug_info) qc_buildmode_separate_debug_info = true; else if(opt_no_separate_debug_info) { // nothing to do } else // default { #ifndef Q_OS_MAC qc_buildmode_separate_debug_info = true; #endif } // make the string QStringList opts; QString other; if(qc_buildmode_release && qc_buildmode_debug) { opts += "debug_and_release"; opts += "build_all"; } else if(qc_buildmode_release) opts += "release"; else // qc_buildmode_debug opts += "debug"; #ifdef Q_OS_MAC if(qc_buildmode_framework) opts += "lib_bundle"; #endif if(qc_buildmode_separate_debug_info) { opts += "separate_debug_info"; other += "QMAKE_CFLAGS += -g\n"; other += "QMAKE_CXXFLAGS += -g\n"; } QString str = QString("CONFIG += ") + opts.join(" ") + '\n'; conf->addExtra(str); if(!other.isEmpty()) conf->addExtra(other); return true; } }; #line 1 "universal.qcm" /* -----BEGIN QCMOD----- name: Mac universal binary support section: project arg: universal,Build with Mac universal binary support. arg: mac-sdk=[path],Path to Mac universal SDK (PPC host only). -----END QCMOD----- */ #define QC_UNIVERSAL bool qc_universal_enabled = false; QString qc_universal_sdk; //---------------------------------------------------------------------------- // qc_universal //---------------------------------------------------------------------------- class qc_universal : public ConfObj { public: qc_universal(Conf *c) : ConfObj(c) {} QString name() const { return "Mac universal binary support"; } QString shortname() const { return "universal"; } QString checkString() const { return QString(); } bool exec() { #ifdef Q_OS_MAC if(qc_getenv("QC_UNIVERSAL") == "Y") { qc_universal_enabled = true; QString str = "contains(QT_CONFIG,x86):contains(QT_CONFIG,ppc) {\n" " CONFIG += x86 ppc\n" "}\n"; QString sdk = qc_getenv("QC_MAC_SDK"); if(!sdk.isEmpty()) { str += QString("QMAKE_MAC_SDK = %1\n").arg(sdk); qc_universal_sdk = sdk; } conf->addExtra(str); } #endif return true; } }; #line 1 "qca.qcm" /* -----BEGIN QCMOD----- name: QCA >= 2.0 arg: with-qca=[path],Specify path to QCA tree, mainly for building against an uninstalled QCA. -----END QCMOD----- */ // based on crypto.prf. any changes made to that file need to be tracked here. static QString internal_crypto_prf(const QString &incdir, const QString &libdir) { QString out = QString( "QCA_INCDIR = %1\n" "QCA_LIBDIR = %2\n" "\n" "CONFIG *= qt\n" "\n" "LINKAGE =\n" "\n" "# on mac, if qca was built as a framework, link against it\n" "mac: {\n" " framework_dir = \$\$QCA_LIBDIR\n" " exists(\$\$framework_dir/qca.framework) {\n" " #QMAKE_FRAMEWORKPATH *= \$\$framework_dir\n" " LIBS += -F\$\$framework_dir\n" " INCLUDEPATH += \$\$framework_dir/qca.framework/Headers\n" " LINKAGE = -framework qca\n" " }\n" "}\n" "\n" "# else, link normally\n" "isEmpty(LINKAGE) {\n" " INCLUDEPATH += \$\$QCA_INCDIR/QtCrypto\n" " LIBS += -L\$\$QCA_LIBDIR\n" " LINKAGE = -lqca\n" " CONFIG(debug, debug|release) {\n" " windows:LINKAGE = -lqcad\n" " mac:LINKAGE = -lqca_debug\n" " }\n" "}\n" "\n" "LIBS += \$\$LINKAGE\n" ).arg(incdir, libdir); return out; } #define QC_QCA QString qc_qca_procode; //---------------------------------------------------------------------------- // qc_qca //---------------------------------------------------------------------------- class qc_qca : public ConfObj { public: qc_qca(Conf *c) : ConfObj(c) {} QString name() const { return "QCA >= 2.0"; } QString shortname() const { return "qca"; } bool exec() { // get the build mode #ifdef QC_BUILDMODE bool release = qc_buildmode_release; bool debug = qc_buildmode_debug; #else // else, default to just release mode bool release = true; bool debug = false; #endif // test for "crypto" feature and check qca version number QString qca_prefix, qca_incdir, qca_libdir, qca_crypto_prf; qca_prefix = conf->getenv("QC_WITH_QCA"); QString proextra; if(!qca_prefix.isEmpty()) { qca_incdir = qca_prefix + "/include"; qca_libdir = qca_prefix + "/lib"; qca_crypto_prf = internal_crypto_prf(qca_incdir, qca_libdir); proextra = "CONFIG += qt\n" "QT -= gui\n"; proextra += qca_crypto_prf; } else { proextra = "CONFIG += qt crypto\n" "QT -= gui\n"; } QString str = "#include \n" "\n" "int main()\n" "{\n" " unsigned long x = QCA_VERSION;\n" " if(x >= 0x020000 && x < 0x030000) return 0; else return 1;\n" "}\n"; if(release) { int ret; if(!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += release\n", &ret)) return false; if(ret != 0) return false; } if(debug) { int ret; if(!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += debug\n", &ret)) return false; if(ret != 0) return false; } if(!qca_prefix.isEmpty()) str = qca_crypto_prf; else str = "CONFIG += crypto\n"; qc_qca_procode = str; conf->addExtra(str); return true; } }; #line 1 "zlib.qcm" /* -----BEGIN QCMOD----- name: zlib arg: with-zlib-inc=[path],Path to zlib include files arg: with-zlib-lib=[path],Path to zlib library files -----END QCMOD----- */ //---------------------------------------------------------------------------- // qc_zlib //---------------------------------------------------------------------------- class qc_zlib : public ConfObj { public: qc_zlib(Conf *c) : ConfObj(c) {} QString name() const { return "zlib"; } QString shortname() const { return "zlib"; } bool exec() { QString inc, lib; QString s; s = conf->getenv("QC_WITH_ZLIB_INC"); if(!s.isEmpty()) { if(!conf->checkHeader(s, "zlib.h")) return false; inc = s; } else { if(!conf->findHeader("zlib.h", QStringList(), &s)) return false; inc = s; } s = conf->getenv("QC_WITH_ZLIB_LIB"); if(!s.isEmpty()) { if(!conf->checkLibrary(s, "z")) return false; lib = s; } else { if(!conf->findLibrary("z", &s)) return false; lib = s; } if(!inc.isEmpty()) conf->addIncludePath(inc); if(!lib.isEmpty()) conf->addLib(QString("-L") + s); conf->addLib("-lz"); return true; } }; #line 1 "extra.qcm" /* -----BEGIN QCMOD----- name: extra section: project arg: disable-tests,Don't build examples and unittests. -----END QCMOD----- */ class qc_extra : public ConfObj { public: qc_extra(Conf *c) : ConfObj(c) {} QString name() const { return "extra"; } QString shortname() const { return "extra"; } // no output QString checkString() const { return QString(); } bool exec() { QString str; QFile f; if(conf->getenv("QC_DISABLE_TESTS") == "Y") str += "CONFIG += no_tests\n"; conf->addExtra(str); bool release = true; bool debug = false; bool debug_info = false; bool universal = false; QString sdk; #ifdef QC_BUILDMODE release = qc_buildmode_release; debug = qc_buildmode_debug; debug_info = qc_buildmode_separate_debug_info; #endif #ifdef QC_UNIVERSAL universal = qc_universal_enabled; sdk = qc_universal_sdk; #endif // write confapp_unix.pri str = QString(); QString var = conf->getenv("BINDIR"); if(!var.isEmpty()) str += QString("BINDIR = %1\n").arg(var); if(debug) // debug or debug-and-release str += QString("CONFIG += debug\n"); else // release str += QString("CONFIG += release\n"); if(debug_info) { str += QString("CONFIG += separate_debug_info\n"); str += "QMAKE_CFLAGS += -g\n"; str += "QMAKE_CXXFLAGS += -g\n"; } if(universal) { str += "contains(QT_CONFIG,x86):contains(QT_CONFIG,ppc) {\n" " CONFIG += x86 ppc\n" "}\n"; if(!sdk.isEmpty()) str += QString("QMAKE_MAC_SDK = %1\n").arg(sdk); } #ifdef QC_QCA if(!qc_qca_procode.isEmpty()) str += qc_qca_procode; #endif f.setFileName("confapp_unix.pri"); if(f.open(QFile::WriteOnly | QFile::Truncate)) f.write(str.toLatin1()); f.close(); return true; } QString makeEscapedDefine(const QString &var, const QString &val) { QString str = QString( "DEFINES += %1=\\\\\\\\\\\\\\"%2\\\\\\\\\\\\\\"\n" ).arg(var).arg(val); return str; } }; EOT cat >$1/modules_new.cpp <required = true; o->disabled = false; o = new qc_buildmode(conf); o->required = true; o->disabled = false; o = new qc_universal(conf); o->required = true; o->disabled = false; o = new qc_qca(conf); o->required = true; o->disabled = false; o = new qc_zlib(conf); o->required = true; o->disabled = false; o = new qc_extra(conf); o->required = true; o->disabled = false; EOT cat >$1/conf4.h < class Conf; enum VersionMode { VersionMin, VersionExact, VersionMax, VersionAny }; // ConfObj // // Subclass ConfObj to create a new configuration module. class ConfObj { public: Conf *conf; bool required; bool disabled; bool success; ConfObj(Conf *c); virtual ~ConfObj(); // long or descriptive name of what is being checked/performed // example: "KDE >= 3.3" virtual QString name() const = 0; // short name // example: "kde" virtual QString shortname() const = 0; // string to display during check // default: "Checking for [name] ..." virtual QString checkString() const; // string to display after check // default: "yes" or "no", based on result of exec() virtual QString resultString() const; // this is where the checking code goes virtual bool exec() = 0; }; // Conf // // Interact with this class from your ConfObj to perform detection // operations and to output configuration parameters. class Conf { public: bool debug_enabled; QString qmake_path; QString qmakespec; QString maketool; QString DEFINES; QString INCLUDEPATH; QString LIBS; QString extra; QList list; QMap vars; Conf(); ~Conf(); QString getenv(const QString &var); QString qvar(const QString &s); bool exec(); void debug(const QString &s); QString expandIncludes(const QString &inc); QString expandLibs(const QString &lib); int doCommand(const QString &s, QByteArray *out = 0); int doCommand(const QString &prog, const QStringList &args, QByteArray *out = 0); bool doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, const QString &proextra, int *retcode = 0); bool checkHeader(const QString &path, const QString &h); bool findHeader(const QString &h, const QStringList &ext, QString *inc); bool checkLibrary(const QString &path, const QString &name); bool findLibrary(const QString &name, QString *lib); QString findProgram(const QString &prog); bool findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname, QString *incpath, QString *libs); bool findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags); bool findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, QStringList *incs, QString *libs, QString *otherflags); void addDefine(const QString &str); void addLib(const QString &str); void addIncludePath(const QString &str); void addExtra(const QString &str); private: bool first_debug; friend class ConfObj; void added(ConfObj *o); }; #endif EOT cat >$1/conf4.cpp < #include class MocTestObject : public QObject { Q_OBJECT public: MocTestObject() {} }; QString qc_getenv(const QString &var) { char *p = ::getenv(var.toLatin1().data()); if(!p) return QString(); return QString(p); } QStringList qc_pathlist() { QStringList list; QString path = qc_getenv("PATH"); if(!path.isEmpty()) list = path.split(':', QString::SkipEmptyParts); return list; } QString qc_findprogram(const QString &prog) { QString out; QStringList list = qc_pathlist(); for(int n = 0; n < list.count(); ++n) { QFileInfo fi(list[n] + '/' + prog); if(fi.exists() && fi.isExecutable()) { out = fi.filePath(); break; } } return out; } QString qc_findself(const QString &argv0) { if(argv0.contains('/')) return argv0; else return qc_findprogram(argv0); } int qc_runcommand(const QString &command, QByteArray *out, bool showOutput) { QString fullcmd = command; if(!showOutput) fullcmd += " 2>/dev/null"; FILE *f = popen(fullcmd.toLatin1().data(), "r"); if(!f) return -1; if(out) out->clear(); while(1) { char c = (char)fgetc(f); if(feof(f)) break; if(out) out->append(c); if(showOutput) fputc(c, stdout); } int ret = pclose(f); if(ret == -1) return -1; return ret; } int qc_runprogram(const QString &prog, const QStringList &args, QByteArray *out, bool showOutput) { QString fullcmd = prog; QString argstr = args.join(" "); if(!argstr.isEmpty()) fullcmd += QString(" ") + argstr; return qc_runcommand(fullcmd, out, showOutput); // TODO: use QProcess once it is fixed /* QProcess process; if(showOutput) process.setReadChannelMode(ForwardedChannels); process.start(prog, args); process.waitForFinished(-1); return process.exitCode(); */ } bool qc_removedir(const QString &dirPath) { QDir dir(dirPath); if(!dir.exists()) return false; QStringList list = dir.entryList(); foreach(QString s, list) { if(s == "." || s == "..") continue; QFileInfo fi(dir.filePath(s)); if(fi.isDir()) { if(!qc_removedir(fi.filePath())) return false; } else { if(!dir.remove(s)) return false; } } QString dirName = dir.dirName(); if(!dir.cdUp()) return false; if(!dir.rmdir(dirName)) return false; return true; } void qc_splitcflags(const QString &cflags, QStringList *incs, QStringList *otherflags) { incs->clear(); otherflags->clear(); QStringList cflagsList = cflags.split(" "); for(int n = 0; n < cflagsList.count(); ++n) { QString str = cflagsList[n]; if(str.startsWith("-I")) { // we want everything except the leading "-I" incs->append(str.remove(0, 2)); } else { // we want whatever is left otherflags->append(str); } } } QString qc_escapeArg(const QString &str) { QString out; for(int n = 0; n < (int)str.length(); ++n) { if(str[n] == '-') out += '_'; else out += str[n]; } return out; } //---------------------------------------------------------------------------- // ConfObj //---------------------------------------------------------------------------- ConfObj::ConfObj(Conf *c) { conf = c; conf->added(this); required = false; disabled = false; success = false; } ConfObj::~ConfObj() { } QString ConfObj::checkString() const { return QString("Checking for %1 ...").arg(name()); } QString ConfObj::resultString() const { if(success) return "yes"; else return "no"; } //---------------------------------------------------------------------------- // qc_internal_pkgconfig //---------------------------------------------------------------------------- class qc_internal_pkgconfig : public ConfObj { public: QString pkgname, desc; VersionMode mode; QString req_ver; qc_internal_pkgconfig(Conf *c, const QString &_name, const QString &_desc, VersionMode _mode, const QString &_req_ver) : ConfObj(c) { pkgname = _name; desc = _desc; mode = _mode; req_ver = _req_ver; } QString name() const { return desc; } QString shortname() const { return pkgname; } bool exec() { QStringList incs; QString version, libs, other; if(!conf->findPkgConfig(pkgname, mode, req_ver, &version, &incs, &libs, &other)) return false; for(int n = 0; n < incs.count(); ++n) conf->addIncludePath(incs[n]); if(!libs.isEmpty()) conf->addLib(libs); //if(!other.isEmpty()) // conf->addExtra(QString("QMAKE_CFLAGS += %1\n").arg(other)); return true; } }; //---------------------------------------------------------------------------- // Conf //---------------------------------------------------------------------------- Conf::Conf() { // TODO: no more vars? //vars.insert("QMAKE_INCDIR_X11", new QString(X11_INC)); //vars.insert("QMAKE_LIBDIR_X11", new QString(X11_LIBDIR)); //vars.insert("QMAKE_LIBS_X11", new QString(X11_LIB)); //vars.insert("QMAKE_CC", CC); debug_enabled = false; } Conf::~Conf() { qDeleteAll(list); } void Conf::added(ConfObj *o) { list.append(o); } QString Conf::getenv(const QString &var) { return qc_getenv(var); } void Conf::debug(const QString &s) { if(debug_enabled) { if(first_debug) printf("\n"); first_debug = false; printf(" * %s\n", qPrintable(s)); } } bool Conf::exec() { for(int n = 0; n < list.count(); ++n) { ConfObj *o = list[n]; // if this was a disabled-by-default option, check if it was enabled if(o->disabled) { QString v = QString("QC_ENABLE_") + qc_escapeArg(o->shortname()); if(getenv(v) != "Y") continue; } // and the opposite? else { QString v = QString("QC_DISABLE_") + qc_escapeArg(o->shortname()); if(getenv(v) == "Y") continue; } bool output = true; QString check = o->checkString(); if(check.isEmpty()) output = false; if(output) { printf("%s", check.toLatin1().data()); fflush(stdout); } first_debug = true; bool ok = o->exec(); o->success = ok; if(output) { QString result = o->resultString(); if(!first_debug) printf(" -> %s\n", result.toLatin1().data()); else printf(" %s\n", result.toLatin1().data()); } if(!ok && o->required) { printf("\nError: need %s!\n", o->name().toLatin1().data()); return false; } } return true; } QString Conf::qvar(const QString &s) { return vars.value(s); } QString Conf::expandIncludes(const QString &inc) { return QString("-I") + inc; } QString Conf::expandLibs(const QString &lib) { return QString("-L") + lib; } int Conf::doCommand(const QString &s, QByteArray *out) { debug(QString("[%1]").arg(s)); int r = qc_runcommand(s, out, debug_enabled); debug(QString("returned: %1").arg(r)); return r; } int Conf::doCommand(const QString &prog, const QStringList &args, QByteArray *out) { QString fullcmd = prog; QString argstr = args.join(" "); if(!argstr.isEmpty()) fullcmd += QString(" ") + argstr; debug(QString("[%1]").arg(fullcmd)); int r = qc_runprogram(prog, args, out, debug_enabled); debug(QString("returned: %1").arg(r)); return r; } bool Conf::doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, const QString &proextra, int *retcode) { QDir tmp(".qconftemp"); if(!tmp.mkdir("atest")) { debug("unable to create atest dir"); return false; } QDir dir(tmp.filePath("atest")); if(!dir.exists()) { debug("atest dir does not exist"); return false; } QString fname = dir.filePath("atest.cpp"); QString out = "atest"; QFile f(fname); if(!f.open(QFile::WriteOnly | QFile::Truncate)) { debug("unable to open atest.cpp for writing"); return false; } if(f.write(filedata.toLatin1()) == -1) { debug("error writing to atest.cpp"); return false; } f.close(); debug(QString("Wrote atest.cpp:\n%1").arg(filedata)); QString pro = QString( "CONFIG += console\n" "CONFIG -= qt app_bundle\n" "SOURCES += atest.cpp\n"); QString inc = incs.join(" "); if(!inc.isEmpty()) pro += "INCLUDEPATH += " + inc + '\n'; if(!libs.isEmpty()) pro += "LIBS += " + libs + '\n'; pro += proextra; fname = dir.filePath("atest.pro"); f.setFileName(fname); if(!f.open(QFile::WriteOnly | QFile::Truncate)) { debug("unable to open atest.pro for writing"); return false; } if(f.write(pro.toLatin1()) == -1) { debug("error writing to atest.pro"); return false; } f.close(); debug(QString("Wrote atest.pro:\n%1").arg(pro)); QString oldpath = QDir::currentPath(); QDir::setCurrent(dir.path()); bool ok = false; int r = doCommand(qmake_path, QStringList() << "atest.pro"); if(r == 0) { r = doCommand(maketool, QStringList()); if(r == 0) { ok = true; if(retcode) *retcode = doCommand(QString("./") + out, QStringList()); } r = doCommand(maketool, QStringList() << "distclean"); if(r != 0) debug("error during atest distclean"); } QDir::setCurrent(oldpath); // cleanup //dir.remove("atest.pro"); //dir.remove("atest.cpp"); //tmp.rmdir("atest"); // remove whole dir since distclean doesn't always work qc_removedir(tmp.filePath("atest")); if(!ok) return false; return true; } bool Conf::checkHeader(const QString &path, const QString &h) { QFileInfo fi(path + '/' + h); if(fi.exists()) return true; return false; } bool Conf::findHeader(const QString &h, const QStringList &ext, QString *inc) { if(checkHeader("/usr/include", h)) { *inc = ""; return true; } QStringList dirs; dirs += "/usr/local/include"; dirs += ext; for(QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { if(checkHeader(*it, h)) { *inc = *it; return true; } } return false; } bool Conf::checkLibrary(const QString &path, const QString &name) { QString str = //"#include \n" "int main()\n" "{\n" //" printf(\"library checker running\\\\n\");\n" " return 0;\n" "}\n"; QString libs; if(!path.isEmpty()) libs += QString("-L") + path + ' '; libs += QString("-l") + name; if(!doCompileAndLink(str, QStringList(), libs, QString())) return false; return true; } bool Conf::findLibrary(const QString &name, QString *lib) { if(checkLibrary("", name)) { *lib = ""; return true; } if(checkLibrary("/usr/local/lib", name)) { *lib = "/usr/local/lib"; return true; } return false; } QString Conf::findProgram(const QString &prog) { return qc_findprogram(prog); } bool Conf::findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname, QString *incpath, QString *libs) { QString inc, lib; QString s; s = getenv(incvar); if(!s.isEmpty()) { if(!checkHeader(s, incname)) return false; inc = s; } else { if(!findHeader(incname, QStringList(), &s)) return false; inc = s; } s = getenv(libvar); if(!s.isEmpty()) { if(!checkLibrary(s, libname)) return false; lib = s; } else { if(!findLibrary(libname, &s)) return false; lib = s; } QString lib_out; if(!lib.isEmpty()) lib_out += QString("-L") + s; lib_out += QString("-l") + libname; *incpath = inc; *libs = lib_out; return true; } bool Conf::findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags) { QStringList args; QByteArray out; int ret; args += "--version"; ret = doCommand(path, args, &out); if(ret != 0) return false; QString version_out = QString::fromLatin1(out).trimmed(); args.clear(); args += "--libs"; ret = doCommand(path, args, &out); if(ret != 0) return false; QString libs_out = QString::fromLatin1(out).trimmed(); args.clear(); args += "--cflags"; ret = doCommand(path, args, &out); if(ret != 0) return false; QString cflags = QString::fromLatin1(out).trimmed(); QStringList incs_out, otherflags_out; qc_splitcflags(cflags, &incs_out, &otherflags_out); *version = version_out; *incs = incs_out; *libs = libs_out; *otherflags = otherflags_out.join(" "); return true; } bool Conf::findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, QStringList *incs, QString *libs, QString *otherflags) { QStringList args; QByteArray out; int ret; args += name; args += "--exists"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; if(mode != VersionAny) { args.clear(); args += name; if(mode == VersionMin) args += QString("--atleast-version=%1").arg(req_version); else if(mode == VersionMax) args += QString("--max-version=%1").arg(req_version); else args += QString("--exact-version=%1").arg(req_version); ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; } args.clear(); args += name; args += "--modversion"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; QString version_out = QString::fromLatin1(out).trimmed(); args.clear(); args += name; args += "--libs"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; QString libs_out = QString::fromLatin1(out).trimmed(); args.clear(); args += name; args += "--cflags"; ret = doCommand("pkg-config", args, &out); if(ret != 0) return false; QString cflags = QString::fromLatin1(out).trimmed(); QStringList incs_out, otherflags_out; qc_splitcflags(cflags, &incs_out, &otherflags_out); *version = version_out; *incs = incs_out; *libs = libs_out; *otherflags = otherflags_out.join(" "); return true; } void Conf::addDefine(const QString &str) { if(DEFINES.isEmpty()) DEFINES = str; else DEFINES += QString(" ") + str; debug(QString("DEFINES += %1").arg(str)); } void Conf::addLib(const QString &str) { if(LIBS.isEmpty()) LIBS = str; else LIBS += QString(" ") + str; debug(QString("LIBS += %1").arg(str)); } void Conf::addIncludePath(const QString &str) { if(INCLUDEPATH.isEmpty()) INCLUDEPATH = str; else INCLUDEPATH += QString(" ") + str; debug(QString("INCLUDEPATH += %1").arg(str)); } void Conf::addExtra(const QString &str) { extra += str + '\n'; debug(QString("extra += %1").arg(str)); } //---------------------------------------------------------------------------- // main //---------------------------------------------------------------------------- #include "conf4.moc" #ifdef HAVE_MODULES # include"modules.cpp" #endif int main() { Conf *conf = new Conf; ConfObj *o; o = 0; #ifdef HAVE_MODULES # include"modules_new.cpp" #endif conf->debug_enabled = (qc_getenv("QC_VERBOSE") == "Y") ? true: false; if(conf->debug_enabled) printf(" -> ok\n"); else printf("ok\n"); QString confCommand = qc_getenv("QC_COMMAND"); QString proName = qc_getenv("QC_PROFILE"); conf->qmake_path = qc_getenv("QC_QMAKE"); conf->qmakespec = qc_getenv("QC_QMAKESPEC"); conf->maketool = qc_getenv("QC_MAKETOOL"); if(conf->debug_enabled) printf("conf command: [%s]\n", qPrintable(confCommand)); QString confPath = qc_findself(confCommand); if(confPath.isEmpty()) { printf("Error: cannot find myself; rerun with an absolute path\n"); return 1; } QString srcdir = QFileInfo(confPath).absolutePath(); QString builddir = QDir::current().absolutePath(); QString proPath = QDir(srcdir).filePath(proName); if(conf->debug_enabled) { printf("conf path: [%s]\n", qPrintable(confPath)); printf("srcdir: [%s]\n", qPrintable(srcdir)); printf("builddir: [%s]\n", qPrintable(builddir)); printf("profile: [%s]\n", qPrintable(proPath)); printf("qmake path: [%s]\n", qPrintable(conf->qmake_path)); printf("qmakespec: [%s]\n", qPrintable(conf->qmakespec)); printf("make tool: [%s]\n", qPrintable(conf->maketool)); printf("\n"); } bool success = false; if(conf->exec()) { QFile f("conf.pri"); if(!f.open(QFile::WriteOnly | QFile::Truncate)) { printf("Error writing %s\n", qPrintable(f.fileName())); return 1; } QString str; str += "# qconf\n\n"; QString var; var = qc_getenv("PREFIX"); if(!var.isEmpty()) str += QString("PREFIX = %1\n").arg(var); var = qc_getenv("BINDIR"); if(!var.isEmpty()) str += QString("BINDIR = %1\n").arg(var); var = qc_getenv("INCDIR"); if(!var.isEmpty()) str += QString("INCDIR = %1\n").arg(var); var = qc_getenv("LIBDIR"); if(!var.isEmpty()) str += QString("LIBDIR = %1\n").arg(var); var = qc_getenv("DATADIR"); if(!var.isEmpty()) str += QString("DATADIR = %1\n").arg(var); str += '\n'; if(qc_getenv("QC_STATIC") == "Y") str += "CONFIG += staticlib\n"; // TODO: don't need this? //str += "QT_PATH_PLUGINS = " + QString(qInstallPathPlugins()) + '\n'; if(!conf->DEFINES.isEmpty()) str += "DEFINES += " + conf->DEFINES + '\n'; if(!conf->INCLUDEPATH.isEmpty()) str += "INCLUDEPATH += " + conf->INCLUDEPATH + '\n'; if(!conf->LIBS.isEmpty()) str += "LIBS += " + conf->LIBS + '\n'; if(!conf->extra.isEmpty()) str += conf->extra; str += '\n'; QByteArray cs = str.toLatin1(); f.write(cs); f.close(); success = true; } QString qmake_path = conf->qmake_path; QString qmakespec = conf->qmakespec; delete conf; if(!success) return 1; // run qmake on the project file QStringList args; if(!qmakespec.isEmpty()) { args += "-spec"; args += qmakespec; } args += proPath; int ret = qc_runprogram(qmake_path, args, 0, true); if(ret != 0) return 1; return 0; } EOT cat >$1/conf4.pro </dev/null else $qm conf4.pro >/dev/null fi $MAKE clean >/dev/null 2>&1 $MAKE >../conf.log 2>&1 ) if [ "$?" != "0" ]; then rm -rf .qconftemp if [ "$QC_VERBOSE" = "Y" ]; then echo " -> fail" else echo "fail" fi printf "\n" printf "Reason: There was an error compiling 'conf'. See conf.log for details.\n" printf "\n" show_qt_info if [ "$QC_VERBOSE" = "Y" ]; then echo "conf.log:" cat conf.log fi exit 1; fi QC_COMMAND=$0 export QC_COMMAND QC_PROFILE=iris.pro export QC_PROFILE QC_QMAKE=$qm export QC_QMAKE QC_QMAKESPEC=$qm_spec export QC_QMAKESPEC QC_MAKETOOL=$MAKE export QC_MAKETOOL .qconftemp/conf ret="$?" if [ "$ret" = "1" ]; then rm -rf .qconftemp echo exit 1; else if [ "$ret" != "0" ]; then rm -rf .qconftemp if [ "$QC_VERBOSE" = "Y" ]; then echo " -> fail" else echo "fail" fi echo echo "Reason: Unexpected error launching 'conf'" echo exit 1; fi fi rm -rf .qconftemp echo echo "Good, your configure finished. Now run $MAKE." echo psi-0.14/iris/TODO0000644000175000017500000000352211305557616012004 0ustar janjannetinterface use qca syncthread, match keystore in thread safety concerns "Interface ids obtained through NetInterfaceManager are guaranteed to be valid until the event loop resumes, or until the next call to interfaces() or interfaceForAddress()." ... the code seems to be lying about interfaceForAddress. netnames support faking srv (or perhaps any record) somehow, through config or code support multithreading put the netnames backend into an alternate thread (this thread should probably be some generic irisnet thing that other modules can use too) netnames front-end api communicates with the backend, so that one backend is shared by all threads NameResolver/ServiceBrowser/ServiceResolver should have isActive? report ServiceBrowser error codes report ServiceResolver error codes ServiceInstance attribs arg of constructor should be optional? ServiceInstance should cache the name() answer ServiceProvider should support error codes and passing many ip addresses ServiceResolver should give the hostnames and the ip addresses. hostnames may be needed for SASL consider reverse dns (for both internet and multicast) dns/bonjour/idn/dns-sd tcp/udp/rtp, bytestream abstraction protocol http/socks/ice/ocsp/crl lineproto, httpproto, xmlproto, binaryproto?, socksishproto? auth/cert/pgp parameter abstraction network interface detection simplified keystore handling? stringprep built-in simplified SASL digest-md5, plain?, anonymous? layer tracking & flow control both sync and async api threading capable proxies http/httpsconnect/httppoll/socks4,5/fakessl? dns/net/proxy/auth engine plugins? upnp/bonjour nat dodging / port opening? connector questions: 1) where does it end? 2) how would a pgp-auth for xmpp-core work? goal: support xmpp-core for tcp/httpbind xmpp-core should be "just another protocol" psi-0.14/iris/.gitignore0000644000175000017500000000014011305557616013275 0ustar janjanMakefile *.o *.moc ui_*.h moc_*.cpp qrc_*.cpp /conf.log /conf.pri /configure /bin /lib /plugins psi-0.14/iris/README0000644000175000017500000000207211305557616012173 0ustar janjanIris XMPP Library ----------------- Date: August 24th, 2008 Website: http://delta.affinix.com/iris/ Mailing List: Delta Project Install ------- First, build Iris: Unix: ./configure make Windows: copy conf_win.pri.example conf_win.pri copy confapp_win.pri.example confapp_win.pri qmake make (or nmake) There is no installation. Just include iris.pri in your qmake project. Iris requires Qt 4.2 or greater and QCA 2.0 or greater. License ------- This library is licensed under the Lesser GNU General Public License. See the COPYING file for more information. Description ----------- Iris is a comprehensive library for working with the XMPP/Jabber protocol. It complies with the XMPP RFCs and many XEPs. In addition to XMPP, Iris also offers access to many other protocols and concepts, including DNS, DNS-SD, connection and transport abstraction, HTTP, SOCKS, XML streaming, network interfaces, compression, encryption, authentication, flow control, proxies, and NAT traversal. psi-0.14/iris/confapp_win.pri.example0000644000175000017500000000043211305557616015762 0ustar janjanload(winlocal.prf) # qca CONFIG += crypto # zlib INCLUDEPATH += $$WINLOCAL_PREFIX/include LIBS += -L$$WINLOCAL_PREFIX/lib # zlib may have a different lib name depending on how it was compiled win32-g++ { LIBS += -lz } else { LIBS += -lzlib # static #LIBS += -lzdll # dll } psi-0.14/iris/COPYING0000644000175000017500000006350411305557616012355 0ustar janjan GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! psi-0.14/iris/src/0000755000175000017500000000000011305557616012101 5ustar janjanpsi-0.14/iris/src/irisnet/0000755000175000017500000000000011305557616013556 5ustar janjanpsi-0.14/iris/src/irisnet/corelib/0000755000175000017500000000000011305557616015175 5ustar janjanpsi-0.14/iris/src/irisnet/corelib/corelib.pri0000644000175000017500000000143611305557616017334 0ustar janjanQT *= network # libidn #LIBS += -lidn include(../../jdns/jdns.pri) INCLUDEPATH += $$PWD/../../jdns HEADERS += \ $$PWD/jdnsshared.h \ $$PWD/objectsession.h \ $$PWD/irisnetexport.h \ $$PWD/irisnetplugin.h \ $$PWD/irisnetglobal.h \ $$PWD/irisnetglobal_p.h \ $$PWD/netinterface.h \ $$PWD/netavailability.h \ $$PWD/netnames.h SOURCES += \ $$PWD/jdnsshared.cpp \ $$PWD/objectsession.cpp \ $$PWD/irisnetplugin.cpp \ $$PWD/irisnetglobal.cpp \ $$PWD/netinterface.cpp \ $$PWD/netavailability.cpp \ $$PWD/netnames.cpp unix { SOURCES += \ $$PWD/netinterface_unix.cpp } windows { SOURCES += \ $$PWD/netinterface_win.cpp } SOURCES += \ $$PWD/netnames_jdns.cpp #include(legacy/legacy.pri) appledns:appledns_bundle { DEFINES += APPLEDNS_STATIC include(../appledns/appledns.pri) } psi-0.14/iris/src/irisnet/corelib/jdnsshared.h0000644000175000017500000005011311305557616017473 0ustar janjan/* * Copyright (C) 2006,2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef JDNSSHARED_H #define JDNSSHARED_H #include "qjdns.h" class JDnsShared; class JDnsSharedPrivate; class JDnsSharedRequestPrivate; class JDnsSharedDebugPrivate; /** \brief Collects debugging information from JDnsShared \note Iris users should utilize NetNames for DNS capabilities, not JDnsSharedDebug. See the JDnsShared documentation for more information. JDnsSharedDebug is used to collect debugging information from one or many JDnsShared objects. To use it, simply create it and pass it to JDnsShared::setDebug(). Example use: \code JDnsSharedDebug *db = new JDnsSharedDebug; connect(db, SIGNAL(debugLinesReady(const QStringList &)), SLOT(db_debugLinesReady(const QStringList &))); JDnsShared *jdnsShared1 = new JDnsShared(JDnsShared::UnicastInternet); jdnsShared1->setDebug(db, "U"); JDnsShared *jdnsShared2 = new JDnsShared(JDnsShared::UnicastLocal); jdnsShared2->setDebug(db, "L"); ... void db_debugLinesReady(const QStringList &lines) { foreach(QString line, lines) printf("%s\n", qPrintable(line)); } \endcode JDnsShared reports debug lines with the name and interface number prepended to each line. For example, if there is debug information to report about the second interface added to \a jdnsShared2 in the above example, the lines would be prepended with "L1: ". Do not destroy JDnsSharedDebug until all of the JDnsShared objects associated with it have been destroyed. \sa JDnsShared JDnsSharedRequest */ class JDnsSharedDebug : public QObject { Q_OBJECT public: /** \brief Constructs a new object with the given \a parent */ JDnsSharedDebug(QObject *parent = 0); /** \brief Destroys the object */ ~JDnsSharedDebug(); /** \brief Read the available debug information Debug information is reported as a series of lines. The lines are of reasonable length, and so if you're storing a backlog of the most recent debug information, it should be safe to make the cut-off point based on lines. \sa readyRead */ QStringList readDebugLines(); signals: /** \brief Emitted when there is debug information to report \sa readDebugLines */ void readyRead(); private: friend class JDnsShared; friend class JDnsSharedPrivate; friend class JDnsSharedDebugPrivate; JDnsSharedDebugPrivate *d; }; /** \brief Performs a DNS operation using JDnsShared \note Iris users should utilize NetNames for DNS capabilities, not JDnsSharedRequest. See the JDnsShared documentation for more information. JDnsSharedRequest is used to perform DNS operations on a JDnsShared object. Many requests may be performed simultaneously, such that a single JDnsShared object can be "shared" across the application. Please see the JDnsShared documentation for more complete information about how the overall system works. Call query() to perform a query. Call publish() (or publishUpdate()) to make DNS records available on the local network (JDnsShared::Multicast mode only). When the operation has something to report, the resultsReady() signal is emitted. Call success() to determine the status of the operation. If success() returns false, then the operation has failed and the reason for the failure can be determined with error(). If success() returns true, then the meaning differs depending on the type of operation being performed:
  • For JDnsShared::UnicastInternet and JDnsShared::UnicastLocal modes, call results() to obtain the records obtained by the query. In these modes, resultsReady() is only emitted once, at which point the operation is no longer active.
  • For JDnsShared::Multicast, operations are long-lived. Query operations never timeout, and resultsReady() may be emitted multiple times. In order to stop the query, either call cancel() or destroy the JDnsSharedRequest object. Similarly, publishing is long-lived. The record stays published as long as the JDnsSharedRequest has not been cancelled or destroyed.
Here is how you might look up an A record: \code JDnsSharedRequest *req = new JDnsSharedRequest(jdnsShared); connect(req, SIGNAL(resultsReady()), SLOT(req_resultsReady())); req->query("psi-im.org", QJDns::A); ... void req_resultsReady() { if(req->success()) { // print all of the IP addresses obtained QList results = req->results(); foreach(QJDns::Record r, results) { if(r.type == QJDns::A) printf("%s\n", qPrintable(r.address.toString()); } } else printf("Error resolving!\n"); } \endcode Here is an example of publishing a record: \code JDnsSharedRequest *pub = new JDnsSharedRequest(jdnsShared); connect(pub, SIGNAL(resultsReady()), SLOT(pub_resultsReady())); // let's publish an A record QJDns::Record rec; rec.owner = "SomeComputer.local."; rec.type = QJDns::A; rec.ttl = 120; rec.haveKnown = true; rec.address = QHostAddress("192.168.0.32"); pub->publish(QJDns::Unique, rec); ... void pub_resultsReady() { if(pub->success()) printf("Record published\n"); else printf("Error publishing!\n"); } \endcode To update an existing record, use publishUpdate(): \code // the IP address of the host changed, so make a new record QJDns::Record rec; rec.owner = "SomeComputer.local."; rec.type = QJDns::A; rec.ttl = 120; rec.haveKnown = true; rec.address = QHostAddress("192.168.0.64"); // update it pub->publishUpdate(rec); \endcode As a special exception, the address value can be left unspecified for A and Aaaa record types, which tells JDnsShared to substitute the address value with the address of whatever interfaces the record gets published on. This is the preferred way to publish the IP address of your own machine, and in fact it is the only way to do so if you have multiple interfaces, because there will likely be a different IP address value for each interface (the record resolves to a different answer depending on which interface a query comes from). \code // let's publish our own A record QJDns::Record rec; rec.owner = "MyComputer.local."; rec.type = QJDns::A; rec.ttl = 120; rec.haveKnown = true; rec.address = QHostAddress(); pub->publish(QJDns::Unique, rec); \endcode When you want to unpublish, call cancel() or destroy the JDnsSharedRequest. \sa JDnsShared */ class JDnsSharedRequest : public QObject { Q_OBJECT public: /** \brief Operation type */ enum Type { Query, ///< Query operation, initiated by query() Publish ///< Publish operation, initiated by publish() or publishUpdate() }; /** \brief Request error */ enum Error { ErrorNoNet, ///< There are no available network interfaces to operate on. This happens if JDnsShared::addInterface() was not called. ErrorGeneric, ///< Generic error during the operation. ErrorNXDomain, ///< The name looked up does not exist. ErrorTimeout, ///< The operation timed out. ErrorConflict ///< Attempt to publish an already published unique record. }; /** \brief Constructs a new object with the given \a jdnsShared and \a parent */ JDnsSharedRequest(JDnsShared *jdnsShared, QObject *parent = 0); /** \brief Destroys the object If there is an active operation, it is cancelled. */ ~JDnsSharedRequest(); /** \brief The type of operation being performed */ Type type(); /** \brief Perform a query operation */ void query(const QByteArray &name, int type); /** \brief Perform a publish operation */ void publish(QJDns::PublishMode m, const QJDns::Record &record); /** \brief Update a record that is currently published */ void publishUpdate(const QJDns::Record &record); /** \brief Cancels the current operation */ void cancel(); /** \brief Indicates whether or not the operation was successful */ bool success() const; /** \brief Returns the reason for error */ Error error() const; /** \brief Returns the results of the operation */ QList results() const; signals: /** \brief Indicates that the operation has something to report After receiving this signal, call success() to check on the status of the operation, followed by results() or error() as appropriate. */ void resultsReady(); private: friend class JDnsShared; friend class JDnsSharedPrivate; friend class JDnsSharedRequestPrivate; JDnsSharedRequestPrivate *d; }; /** \brief Abstraction layer on top of QJDns \note Iris users should utilize NetNames for DNS capabilities, not JDnsShared. JDnsShared is provided for non-Iris users (and it is also used internally by NetNames). To use JDnsShared by itself, simply drop the jdnsshared.h and jdnsshared.cpp files, along with JDNS, into your project. It is not a full replacement for Qt's Q3Dns, as some tasks are left to you, but it covers most of it. QJDns supports everything a typical application should ever need in DNS. However, it is expected that modern applications will need to maintain multiple QJDns instances at the same time, and this is where things can get complicated. For example, most applications will want at least two QJDns instances: one for IPv4 unicast and one for IPv6 unicast. A single JDnsShared object encapsulates multiple instances of QJDns that are related. For example, an IPv4 unicast instance and an IPv6 unicast instance could be coupled within JDnsShared. Then, when a unicast operation is performed on the JDnsShared object, both underlying instances will be queried as appropriate. The application would not need to perform two resolutions itself, nor deal with any related complexity. Further, individual operations are performed using a separate class called JDnsSharedRequest, eliminating the need for the application to directly interface with a central QJDns object or track integer handles. This makes it easier for individual parts of the application to "share" the same instance (or set of instances) of QJDns, hence the name. JDnsShared is a thin abstraction. QJDns subtypes (e.g. QJDns::Type, QJDns::Record, etc) are still used with JDnsShared. Because of the duplication of documentation effort between NetNames and QJDns, there is no formal documentation for QJDns. Users of JDnsShared will need to read qjdns.h, although a basic explanation of the elements can be found below. Types:
QJDns::TypeThis is a convenience enumeration for common DNS record types. For example: A, Aaaa, Srv, etc. The values directly map to the integer values of the DNS protocol (e.g. Srv = 33). See qjdns.h for all of the types and values.
QJDns::RecordThis class holds a DNS record. The main fields are type (integer type, probably something listed in QJDns::Type), rdata (QByteArray of the record value), and haveKnown (boolean to indicate if a decoded form of the record value is also available). See qjdns.h for the possible known fields. You will most-likely always work with known types. Received records that have a type listed in QJDns::Type are guaranteed to be known and will provide a decoded value. If you are creating a record for publishing, you will need to set owner, ttl, and type. If the type to be published is listed in QJDns::Type, then you will need to set haveKnown to true and set the known fields as appropriate, otherwise you need to set rdata. You do not need to supply an encoded form in rdata for known types, it can be left empty in that case.
QJDns::PublishModeThis is for Multicast DNS, and can either be Unique or Shared. A shared record can be published by multiple owners (for example, a "_ssh._tcp.local." PTR record might resolve to many different SSH services owned by different machines). A unique record can only have one owner (for example, a "mycomputer.local." A record would resolve to the IP address of the machine that published it). Attempting to publish a record on a network where a unique record is already present will result in a conflict error.
Functions:
QJDns::detectPrimaryMulticast()Detects a multicast interface. Pass QHostAddress::Any or QHostAddress::AnyIPv6, depending on which type of interface is desired.
To use JDnsShared, first create an instance of it, set it up by calling addInterface() as necessary, and then use JDnsSharedRequest to perform operations on it. Here is an example of how to create and set up a JDnsShared object for typical DNS resolution: \code // construct JDnsShared *dns = new JDnsShared(JDnsShared::UnicastInternet); // add IPv4 and IPv6 interfaces dns->addInterface(QHostAddress::Any); dns->addInterface(QHostAddress::AnyIPv6); // at this point, the object is ready for operation \endcode Perform a resolution like this: \code JDnsSharedRequest *req = new JDnsSharedRequest(dns); connect(req, SIGNAL(resultsReady()), SLOT(req_resultsReady())); req->query("psi-im.org", QJDns::A); ... void req_resultsReady() { if(req->success()) { // print all of the IP addresses obtained QList results = req->results(); foreach(QJDns::Record r, results) { if(r.type == QJDns::A) printf("%s\n", qPrintable(r.address.toString()); } } else printf("Error resolving!\n"); } \endcode It is important to filter the results as shown in the above example. QJDns guarantees at least one record in the results will be of the type queried for, but there may also be CNAME records present (of course, if the query was for a CNAME type, then the results will only be CNAME records). The recommended approach is to simply filter for the record types desired, as shown, rather than single out CNAME specifically. When you are finished with a JDnsShared object, it should be shut down before deleting: \code connect(dns, SIGNAL(shutdownFinished()), SLOT(dns_shutdownFinished())); dns->shutdown(); ... void dns_shutdownFinished() { delete dns; } \endcode Setting up JDnsShared for UnicastLocal and Multicast mode is done the same way as with UnicastInternet. For example, here is how Multicast mode could be set up: \code // construct JDnsShared *dns = new JDnsShared(JDnsShared::Multicast); // add IPv4 interface QHostAddress addr = QJDns::detectPrimaryMulticast(QHostAddress::Any); dns->addInterface(addr); // at this point, the object is ready for operation \endcode JDnsShared provides a lot of functionality, but certain aspects of DNS are deemed out of its scope. Below are the responsibilities of the user of JDnsShared, if a more complete DNS behavior is desired:
  • Querying for several "qualified" names. You should first query for the name as provided, and if that fails then query for name + ".domain" (for every domain the computer is in). See domains().
  • Detecting for ".local" in the name to be queried, and using that to decide whether to query via Multicast/UnicastLocal or UnicastInternet.
  • For zeroconf/Bonjour, keep in mind that JDnsShared only provides low-level record queries. DNS-SD and any higher layers would be your job.
Using a custom DNS implementation, such as JDnsShared, has the drawback that it is difficult to take advantage of platform-specific features (for example, an OS-wide DNS cache or LDAP integration). An application strategy for normal DNS should probably be:
  • If an A or AAAA record is desired, use a native lookup.
  • Else, if the platform has advanced DNS features already (ie, res_query), use those.
  • Else, use JDnsShared.
For Multicast DNS, awareness of the platform is doubly important. There should only be one Multicast DNS "Responder" per computer, and using JDnsShared in Multicast mode at the same time could result in a conflict. An application strategy for Multicast DNS should be:
  • If the platform has a Multicast DNS daemon installed already, use it somehow.
  • Else, use JDnsShared.
\sa JDnsSharedRequest */ class JDnsShared : public QObject { Q_OBJECT public: /** \brief The mode to operate in */ enum Mode { /** For regular DNS resolution. In this mode, lookups are performed on all interfaces, and the first returned result is used. */ UnicastInternet, /** Perform regular DNS resolution using the Multicast DNS address. This is used to resolve large and/or known Multicast DNS names without actually multicasting anything. */ UnicastLocal, /** Multicast DNS querying and publishing. \note For Multicast mode, JDnsShared supports up to one interface for each IP version (e.g. one IPv4 interface and one IPv6 interface), and expects the default/primary multicast interface for that IP version to be used. */ Multicast }; /** \brief Constructs a new object with the given \a mode and \a parent */ JDnsShared(Mode mode, QObject *parent = 0); /** \brief Destroys the object */ ~JDnsShared(); /** \brief Sets the debug object to report to If a debug object is set using this function, then JDnsShared will send output text to it, prefixing each line with \a name. */ void setDebug(JDnsSharedDebug *db, const QString &name); /** \brief Adds an interface to operate on For UnicastInternet and UnicastLocal, these will almost always be QHostAddress::Any or QHostAddress::AnyIPv6 (operate on the default interface for IPv4 or IPv6, respectively). For Multicast, it is expected that the default/primary multicast interface will be used here. Do not pass QHostAddress::Any (or AnyIPv6) with Multicast mode. Returns true if the interface was successfully added, otherwise returns false. */ bool addInterface(const QHostAddress &addr); /** \brief Removes a previously-added interface */ void removeInterface(const QHostAddress &addr); /** \brief Shuts down the object This operation primarily exists for Multicast mode, so that any published records have a chance to be unpublished. If the JDnsShared object is simply deleted without performing a shutdown, then published records will linger on the network until their TTLs expire. When shutdown is complete, the shutdownFinished() signal will be emitted. */ void shutdown(); /** \brief The domains to search in You should perform a separate resolution for every domain configured on this machine. */ static QList domains(); /** \brief Performs a blocking shutdown of many JDnsShared instances This function is a convenient way to shutdown multiple JDnsShared instances synchronously. The internal shutdown procedure uses no more than a few cycles of the eventloop, so it should be safe to call without worry of the application being overly stalled. This function takes ownership of the instances passed to it, and will delete them upon completion. It is worth noting that this function is implemented without the use of a nested eventloop. All of the JDnsShared instances are moved into a temporary thread to perform the shutdown procedure, which should not cause any unexpected behavior in the current thread. \code QList list; list += jdnsShared_unicast; list += jdnsShared_multicast; JDnsShared::waitForShutdown(list); // collect remaining debug information QStringList finalDebugLines = jdnsSharedDebug.readDebugLines(); \endcode */ static void waitForShutdown(const QList &instances); signals: /** \brief Indicates the object has been shut down */ void shutdownFinished(); private: friend class JDnsSharedRequest; friend class JDnsSharedPrivate; JDnsSharedPrivate *d; }; #endif psi-0.14/iris/src/irisnet/corelib/objectsession.cpp0000644000175000017500000001440111305557616020553 0ustar janjan/* * Copyright (C) 2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "objectsession.h" #include #include #include #include #include namespace XMPP { class ObjectSessionWatcherPrivate { public: ObjectSession *sess; }; class ObjectSessionPrivate : public QObject { Q_OBJECT public: ObjectSession *q; class MethodCall { public: QObject *obj; QByteArray method; class Argument { public: int type; void *data; }; QList args; MethodCall(QObject *_obj, const char *_method) : obj(_obj), method(_method) { } ~MethodCall() { clearArgs(); } void clearArgs() { for(int n = 0; n < args.count(); ++n) QMetaType::destroy(args[n].type, args[n].data); args.clear(); } bool setArgs(QGenericArgument val0 = QGenericArgument(), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) { const char *arg_name[] = { val0.name(), val1.name(), val2.name(), val3.name(), val4.name(), val5.name(), val6.name(), val7.name(), val8.name(), val9.name() }; void *arg_data[] = { val0.data(), val1.data(), val2.data(), val3.data(), val4.data(), val5.data(), val6.data(), val7.data(), val8.data(), val9.data() }; clearArgs(); for(int n = 0; n < 10; ++n) { if(arg_name[n] == 0) break; Argument arg; arg.type = QMetaType::type(arg_name[n]); if(!arg.type) { clearArgs(); return false; } arg.data = QMetaType::construct(arg.type, arg_data[n]); args += arg; } return true; } }; QList pendingCalls; QTimer *callTrigger; bool paused; QList watchers; ObjectSessionPrivate(ObjectSession *_q) : QObject(_q), q(_q), paused(false) { callTrigger = new QTimer(this); connect(callTrigger, SIGNAL(timeout()), SLOT(doCall())); callTrigger->setSingleShot(true); } ~ObjectSessionPrivate() { invalidateWatchers(); callTrigger->disconnect(this); callTrigger->setParent(0); callTrigger->deleteLater(); } void addPendingCall(MethodCall *call) { pendingCalls += call; if(!paused && !callTrigger->isActive()) callTrigger->start(); } bool havePendingCall(QObject *obj, const char *method) const { foreach(const MethodCall *call, pendingCalls) { if(call->obj == obj && qstrcmp(call->method.data(), method) == 0) return true; } return false; } void invalidateWatchers() { for(int n = 0; n < watchers.count(); ++n) watchers[n]->sess = 0; watchers.clear(); } private slots: void doCall() { MethodCall *call = pendingCalls.takeFirst(); if(!pendingCalls.isEmpty()) callTrigger->start(); Q_ASSERT(call->args.count() <= 10); QGenericArgument arg[10]; for(int n = 0; n < call->args.count(); ++n) arg[n] = QGenericArgument(QMetaType::typeName(call->args[n].type), call->args[n].data); bool ok; ok = QMetaObject::invokeMethod(call->obj, call->method.data(), Qt::DirectConnection, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]); Q_ASSERT(ok); delete call; } }; ObjectSessionWatcher::ObjectSessionWatcher(ObjectSession *sess) { d = new ObjectSessionWatcherPrivate; d->sess = sess; if(d->sess) d->sess->d->watchers += d; } ObjectSessionWatcher::~ObjectSessionWatcher() { if(d->sess) d->sess->d->watchers.removeAll(d); delete d; } bool ObjectSessionWatcher::isValid() const { if(d->sess) return true; else return false; } ObjectSession::ObjectSession(QObject *parent) : QObject(parent) { d = new ObjectSessionPrivate(this); } ObjectSession::~ObjectSession() { delete d; } void ObjectSession::reset() { d->invalidateWatchers(); if(d->callTrigger->isActive()) d->callTrigger->stop(); d->pendingCalls.clear(); } bool ObjectSession::isDeferred(QObject *obj, const char *method) { return d->havePendingCall(obj, method); } void ObjectSession::defer(QObject *obj, const char *method, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9) { ObjectSessionPrivate::MethodCall *call = new ObjectSessionPrivate::MethodCall(obj, method); call->setArgs(val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); d->addPendingCall(call); } void ObjectSession::deferExclusive(QObject *obj, const char *method, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9) { if(d->havePendingCall(obj, method)) return; ObjectSessionPrivate::MethodCall *call = new ObjectSessionPrivate::MethodCall(obj, method); call->setArgs(val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); d->addPendingCall(call); } void ObjectSession::pause() { Q_ASSERT(!d->paused); if(d->callTrigger->isActive()) d->callTrigger->stop(); d->paused = true; } void ObjectSession::resume() { Q_ASSERT(d->paused); d->paused = false; if(!d->pendingCalls.isEmpty()) d->callTrigger->start(); } } #include "objectsession.moc" psi-0.14/iris/src/irisnet/corelib/netinterface_unix.cpp0000644000175000017500000002062211305557616021415 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ // this code assumes the following ioctls work: // SIOCGIFCONF - get list of devices // SIOCGIFFLAGS - get flags about a device // gateway detection currently only works on linux #include "irisnetplugin.h" #include #include #include #include #include #include #include // for solaris #ifndef SIOCGIFCONF # include #endif class UnixIface { public: QString name; bool loopback; QHostAddress address; }; class UnixGateway { public: QString ifaceName; QHostAddress address; }; static QList get_sioc_ifaces() { QList out; int tmpsock = socket(AF_INET, SOCK_DGRAM, 0); if(tmpsock < 0) return out; struct ifconf ifc; int lastlen = 0; QByteArray buf(100 * sizeof(struct ifreq), 0); // guess while(1) { ifc.ifc_len = buf.size(); ifc.ifc_buf = buf.data(); if(ioctl(tmpsock, SIOCGIFCONF, &ifc) < 0) { if(errno != EINVAL || lastlen != 0) return out; } else { // if it didn't grow since last time, then // there's no overflow if(ifc.ifc_len == lastlen) break; lastlen = ifc.ifc_len; } buf.resize(buf.size() + 10 * sizeof(struct ifreq)); } buf.resize(lastlen); int itemsize; for(int at = 0; at < buf.size(); at += itemsize) { struct ifreq *ifr = (struct ifreq *)(buf.data() + at); #ifndef Q_OS_LINUX int sockaddr_len; if(((struct sockaddr *)&ifr->ifr_addr)->sa_family == AF_INET) { sockaddr_len = sizeof(struct sockaddr_in); } else if(((struct sockaddr *)&ifr->ifr_addr)->sa_family == AF_INET6) { sockaddr_len = sizeof(struct sockaddr_in6); } else { sockaddr_len = sizeof(struct sockaddr); } // set this asap so the next iteration is possible itemsize = sizeof(ifr->ifr_name) + sockaddr_len; #else itemsize = sizeof(ifreq); #endif // skip if the family is 0 (sometimes you get empty entries) if(ifr->ifr_addr.sa_family == 0) continue; // make a copy of this item to do additional ioctls on struct ifreq ifrcopy = *ifr; // grab the flags if(ioctl(tmpsock, SIOCGIFFLAGS, &ifrcopy) < 0) continue; // device must be up and not loopback if(!(ifrcopy.ifr_flags & IFF_UP)) continue; UnixIface i; i.name = QString::fromLatin1(ifr->ifr_name); i.loopback = (ifrcopy.ifr_flags & IFF_LOOPBACK) ? true : false; i.address.setAddress(&ifr->ifr_addr); out += i; } // don't need this anymore close(tmpsock); return out; } #ifdef Q_OS_LINUX static QStringList read_proc_as_lines(const char *procfile) { QStringList out; FILE *f = fopen(procfile, "r"); if(!f) return out; QByteArray buf; while(!feof(f)) { // max read on a proc is 4K QByteArray block(4096, 0); int ret = fread(block.data(), 1, block.size(), f); if(ret <= 0) break; block.resize(ret); buf += block; } fclose(f); QString str = QString::fromLocal8Bit(buf); out = str.split('\n', QString::SkipEmptyParts); return out; } static QHostAddress linux_ipv6_to_qaddr(const QString &in) { QHostAddress out; if(in.length() != 32) return out; quint8 raw[16]; for(int n = 0; n < 16; ++n) { bool ok; int x = in.mid(n * 2, 2).toInt(&ok, 16); if(!ok) return out; raw[n] = (quint8)x; } out.setAddress(raw); return out; } static QHostAddress linux_ipv4_to_qaddr(const QString &in) { QHostAddress out; if(in.length() != 8) return out; quint32 raw; unsigned char *rawp = (unsigned char *)&raw; for(int n = 0; n < 4; ++n) { bool ok; int x = in.mid(n * 2, 2).toInt(&ok, 16); if(!ok) return out; rawp[n] = (unsigned char )x; } out.setAddress(raw); return out; } static QList get_linux_ipv6_ifaces() { QList out; QStringList lines = read_proc_as_lines("/proc/net/if_inet6"); for(int n = 0; n < lines.count(); ++n) { const QString &line = lines[n]; QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts); if(parts.count() < 6) continue; QString name = parts[5]; if(name.isEmpty()) continue; QHostAddress addr = linux_ipv6_to_qaddr(parts[0]); if(addr.isNull()) continue; QString scopestr = parts[3]; bool ok; unsigned int scope = parts[3].toInt(&ok, 16); if(!ok) continue; // IPV6_ADDR_LOOPBACK 0x0010U // IPV6_ADDR_SCOPE_MASK 0x00f0U bool loopback = false; if((scope & 0x00f0U) == 0x0010U) loopback = true; UnixIface i; i.name = name; i.loopback = loopback; i.address = addr; out += i; } return out; } static QList get_linux_gateways() { QList out; QStringList lines = read_proc_as_lines("/proc/net/route"); // skip the first line, so we start at 1 for(int n = 1; n < lines.count(); ++n) { const QString &line = lines[n]; QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts); if(parts.count() < 10) // net-tools does 10, but why not 11? continue; QHostAddress addr = linux_ipv4_to_qaddr(parts[2]); if(addr.isNull()) continue; int iflags = parts[3].toInt(0, 16); if(!(iflags & RTF_UP)) continue; if(!(iflags & RTF_GATEWAY)) continue; UnixGateway g; g.ifaceName = parts[0]; g.address = addr; out += g; } lines = read_proc_as_lines("/proc/net/ipv6_route"); for(int n = 0; n < lines.count(); ++n) { const QString &line = lines[n]; QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts); if(parts.count() < 10) continue; QHostAddress addr = linux_ipv6_to_qaddr(parts[4]); if(addr.isNull()) continue; int iflags = parts[8].toInt(0, 16); if(!(iflags & RTF_UP)) continue; if(!(iflags & RTF_GATEWAY)) continue; UnixGateway g; g.ifaceName = parts[9]; g.address = addr; out += g; } return out; } #endif static QList get_unix_ifaces() { QList out = get_sioc_ifaces(); #ifdef Q_OS_LINUX out += get_linux_ipv6_ifaces(); #endif return out; } static QList get_unix_gateways() { // support other platforms here QList out; #ifdef Q_OS_LINUX out = get_linux_gateways(); #endif return out; } namespace XMPP { class UnixNet : public NetInterfaceProvider { Q_OBJECT Q_INTERFACES(XMPP::NetInterfaceProvider); public: QList info; QTimer t; UnixNet() : t(this) { connect(&t, SIGNAL(timeout()), SLOT(check())); } void start() { t.start(5000); poll(); } QList interfaces() const { return info; } void poll() { QList ifaces; QList list = get_unix_ifaces(); for(int n = 0; n < list.count(); ++n) { // see if we have it already int lookup = -1; for(int k = 0; k < ifaces.count(); ++k) { if(ifaces[k].id == list[n].name) { lookup = k; break; } } // don't have it? make it if(lookup == -1) { Info i; i.id = list[n].name; i.name = list[n].name; i.isLoopback = list[n].loopback; i.addresses += list[n].address; ifaces += i; } // otherwise, tack on the address else ifaces[lookup].addresses += list[n].address; } QList glist = get_unix_gateways(); for(int n = 0; n < glist.count(); ++n) { // look up the interface int lookup = -1; for(int k = 0; k < ifaces.count(); ++k) { if(ifaces[k].id == glist[n].ifaceName) { lookup = k; break; } } if(lookup == -1) break; ifaces[lookup].gateway = glist[n].address; } info = ifaces; } public slots: void check() { poll(); emit updated(); } }; class UnixNetProvider : public IrisNetProvider { Q_OBJECT Q_INTERFACES(XMPP::IrisNetProvider); public: virtual NetInterfaceProvider *createNetInterfaceProvider() { return new UnixNet; } }; IrisNetProvider *irisnet_createUnixNetProvider() { return new UnixNetProvider; } } #include "netinterface_unix.moc" psi-0.14/iris/src/irisnet/corelib/irisnetglobal.h0000644000175000017500000000230011305557616020177 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef IRISNETGLOBAL_H #define IRISNETGLOBAL_H #include #include #include "irisnetexport.h" namespace XMPP { // set the directories for plugins. call before doing anything else. IRISNET_EXPORT void irisNetSetPluginPaths(const QStringList &paths); // free any shared data and plugins. // note: this is automatically called when qapp shuts down. IRISNET_EXPORT void irisNetCleanup(); } #endif psi-0.14/iris/src/irisnet/corelib/objectsession.h0000644000175000017500000000474311305557616020230 0ustar janjan/* * Copyright (C) 2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef OBJECTSESSION_H #define OBJECTSESSION_H #include namespace XMPP { class ObjectSessionPrivate; class ObjectSessionWatcherPrivate; class ObjectSession : public QObject { Q_OBJECT public: ObjectSession(QObject *parent = 0); ~ObjectSession(); // clear all deferred requests, invalidate watchers void reset(); bool isDeferred(QObject *obj, const char *method); void defer(QObject *obj, const char *method, QGenericArgument val0 = QGenericArgument(), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()); void deferExclusive(QObject *obj, const char *method, QGenericArgument val0 = QGenericArgument(), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()); void pause(); void resume(); private: friend class ObjectSessionWatcher; ObjectSessionPrivate *d; }; class ObjectSessionWatcher { public: ObjectSessionWatcher(ObjectSession *sess); ~ObjectSessionWatcher(); bool isValid() const; private: friend class ObjectSessionPrivate; ObjectSessionWatcherPrivate *d; }; } #endif psi-0.14/iris/src/irisnet/corelib/irisnetglobal.cpp0000644000175000017500000001340511305557616020542 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "irisnetglobal_p.h" #include "irisnetplugin.h" namespace XMPP { // built-in providers #ifdef Q_OS_WIN extern IrisNetProvider *irisnet_createWinNetProvider(); #endif #ifdef Q_OS_UNIX extern IrisNetProvider *irisnet_createUnixNetProvider(); #endif extern IrisNetProvider *irisnet_createJDnsProvider(); #ifdef APPLEDNS_STATIC extern IrisNetProvider *irisnet_createAppleProvider(); #endif //---------------------------------------------------------------------------- // internal //---------------------------------------------------------------------------- class PluginInstance { private: QPluginLoader *_loader; QObject *_instance; bool _ownInstance; PluginInstance() { } public: static PluginInstance *fromFile(const QString &fname) { QPluginLoader *loader = new QPluginLoader(fname); if(!loader->load()) { delete loader; return 0; } QObject *obj = loader->instance(); if(!obj) { loader->unload(); delete loader; return 0; } PluginInstance *i = new PluginInstance; i->_loader = loader; i->_instance = obj; i->_ownInstance = true; return i; } static PluginInstance *fromStatic(QObject *obj) { PluginInstance *i = new PluginInstance; i->_loader = 0; i->_instance = obj; i->_ownInstance = false; return i; } static PluginInstance *fromInstance(QObject *obj) { PluginInstance *i = new PluginInstance; i->_loader = 0; i->_instance = obj; i->_ownInstance = true; return i; } ~PluginInstance() { if(_ownInstance) delete _instance; if(_loader) { _loader->unload(); delete _loader; } } void claim() { if(_loader) _loader->moveToThread(0); if(_ownInstance) _instance->moveToThread(0); } QObject *instance() { return _instance; } bool sameType(const PluginInstance *other) { if(!_instance || !other->_instance) return false; if(qstrcmp(_instance->metaObject()->className(), other->_instance->metaObject()->className()) != 0) return false; return true; } }; class PluginManager { public: bool builtin_done; QStringList paths; QList plugins; QList providers; PluginManager() { builtin_done = false; } ~PluginManager() { unload(); } bool tryAdd(PluginInstance *i, bool lowPriority = false) { // is it the right kind of plugin? IrisNetProvider *p = qobject_cast(i->instance()); if(!p) return false; // make sure we don't have it already for(int n = 0; n < plugins.count(); ++n) { if(i->sameType(plugins[n])) return false; } i->claim(); plugins += i; if(lowPriority) providers.append(p); else providers.prepend(p); return true; } void addBuiltIn(IrisNetProvider *p) { PluginInstance *i = PluginInstance::fromInstance(p); if(!tryAdd(i, true)) delete i; } void scan() { if(!builtin_done) { #ifdef Q_OS_WIN addBuiltIn(irisnet_createWinNetProvider()); #endif #ifdef Q_OS_UNIX addBuiltIn(irisnet_createUnixNetProvider()); #endif addBuiltIn(irisnet_createJDnsProvider()); builtin_done = true; } QObjectList list = QPluginLoader::staticInstances(); for(int n = 0; n < list.count(); ++n) { PluginInstance *i = PluginInstance::fromStatic(list[n]); if(!tryAdd(i)) delete i; } for(int n = 0; n < paths.count(); ++n) { QDir dir(paths[n]); if(!dir.exists()) continue; QStringList entries = dir.entryList(); for(int k = 0; k < entries.count(); ++k) { QFileInfo fi(dir.filePath(entries[k])); if(!fi.exists()) continue; QString fname = fi.filePath(); PluginInstance *i = PluginInstance::fromFile(fname); if(!i) continue; if(!tryAdd(i)) delete i; } } } void unload() { // unload in reverse order QList revlist; for(int n = 0; n < plugins.count(); ++n) revlist.prepend(plugins[n]); qDeleteAll(revlist); plugins.clear(); providers.clear(); } }; class IrisNetGlobal { public: QMutex m; PluginManager pluginManager; QList cleanupList; }; Q_GLOBAL_STATIC(QMutex, global_mutex) static IrisNetGlobal *global = 0; static void deinit(); static void init() { QMutexLocker locker(global_mutex()); if(global) return; global = new IrisNetGlobal; qAddPostRoutine(deinit); } void deinit() { if(!global) return; while(!global->cleanupList.isEmpty()) (global->cleanupList.takeFirst())(); delete global; global = 0; } //---------------------------------------------------------------------------- // Global //---------------------------------------------------------------------------- void irisNetSetPluginPaths(const QStringList &paths) { init(); QMutexLocker locker(&global->m); global->pluginManager.paths = paths; } void irisNetCleanup() { deinit(); } void irisNetAddPostRoutine(IrisNetCleanUpFunction func) { init(); QMutexLocker locker(&global->m); global->cleanupList.prepend(func); } QList irisNetProviders() { init(); QMutexLocker locker(&global->m); global->pluginManager.scan(); return global->pluginManager.providers; } } psi-0.14/iris/src/irisnet/corelib/irisnetplugin.cpp0000644000175000017500000000400411305557616020573 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "irisnetplugin.h" namespace XMPP { //---------------------------------------------------------------------------- // IrisNetProvider //---------------------------------------------------------------------------- NetInterfaceProvider *IrisNetProvider::createNetInterfaceProvider() { return 0; } NetAvailabilityProvider *IrisNetProvider::createNetAvailabilityProvider() { return 0; } NameProvider *IrisNetProvider::createNameProviderInternet() { return 0; } NameProvider *IrisNetProvider::createNameProviderLocal() { return 0; } ServiceProvider *IrisNetProvider::createServiceProvider() { return 0; } //---------------------------------------------------------------------------- // NameProvider //---------------------------------------------------------------------------- bool NameProvider::supportsSingle() const { return false; } bool NameProvider::supportsLongLived() const { return false; } bool NameProvider::supportsRecordType(int type) const { Q_UNUSED(type); return false; } void NameProvider::resolve_localResultsReady(int id, const QList &results) { Q_UNUSED(id); Q_UNUSED(results); } void NameProvider::resolve_localError(int id, XMPP::NameResolver::Error e) { Q_UNUSED(id); Q_UNUSED(e); } } psi-0.14/iris/src/irisnet/corelib/netinterface.h0000644000175000017500000001456311305557616020026 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef NETINTERFACE_H #define NETINTERFACE_H #include "irisnetglobal.h" namespace XMPP { class NetInterfaceManager; class NetInterfacePrivate; class NetInterfaceManagerPrivate; /** \brief Provides information about a network interface NetInterface provides information about a particular network interface. Construct it by passing the interface id of interest (e.g. "eth0") and a NetInterfaceManager parent object. Interface ids can be obtained from NetInterfaceManager. To test if a NetInterface is valid, call isValid(). Use name() to return a display-friendly name of the interface. The addresses() function returns a list of IP addresses for this interface. There may be a gateway IP address associated with this interface, which can be fetched with gateway(). Here's an example of how to print the IP addresses of eth0: \code NetInterface iface("eth0"); if(iface.isValid()) { QList addrs = iface.addresses(); for(int n = 0; n < addrs.count(); ++n) printf("%s\n", qPrintable(addrs[n].toString())); } \endcode If the interface goes away, the unavailable() signal is emitted and the NetInterface becomes invalid. \sa NetInterfaceManager */ class IRISNET_EXPORT NetInterface : public QObject { Q_OBJECT public: /** \brief Constructs a new interface object with the given \a id and \a manager If \a id is not a valid interface id, then the object will not be valid (isValid() will return false). Normally it is not necessary to check for validity, since interface ids obtained from NetInterfaceManager are guaranteed to be valid until the event loop resumes. \sa isValid */ NetInterface(const QString &id, NetInterfaceManager *manager); /** \brief Destroys the interface object */ ~NetInterface(); /** \brief Returns true if the interface is valid, otherwise returns false \sa unavailable */ bool isValid() const; /** \brief Returns the id of this interface This is the id that was passed in the constructor. */ QString id() const; /** \brief Returns a display-friendly name of this interface The name may be the same as the id. \sa id */ QString name() const; /** \brief Returns the addresses of this interface There will always be at least one address. In some cases there might be multiple, such as on Unix where it is possible for the same interface to have both an IPv4 and an IPv6 address. */ QList addresses() const; /** \brief Returns the gateway of this interface If there is no gateway associated with this interface, a null QHostAddress is returned. */ QHostAddress gateway() const; // optional signals: /** \brief Notifies when the interface becomes unavailable Once this signal is emitted, the NetInterface object becomes invalid and is no longer very useful. A new NetInterface object must be created if a valid object with current information is desired. \note If the interface information changes, the interface is considered to have become unavailable. \sa isValid */ void unavailable(); private: friend class NetInterfacePrivate; NetInterfacePrivate *d; friend class NetInterfaceManagerPrivate; }; /** \brief Manages network interface information NetInterfaceManager keeps track of all available network interfaces. An interface is considered available if it exists, is "Up", has at least one IP address, and is non-Loopback. The interfaces() function returns a list of available interface ids. These ids can be used with NetInterface to get information about the interfaces. For example, here is how you could print the names of the available interfaces: \code NetInterfaceManager netman; QStringList id_list = netman.interfaces(); for(int n = 0; n < id_list.count(); ++n) { NetInterface iface(id_list[n], &netman); printf("name: [%s]\n", qPrintable(iface.name())); } \endcode When a new network interface is available, the interfaceAvailable() signal will be emitted. Note that interface unavailability is not notified by NetInterfaceManager. Instead, use NetInterface to monitor a specific network interface for unavailability. Interface ids obtained through NetInterfaceManager are guaranteed to be valid until the event loop resumes, or until the next call to interfaces() or interfaceForAddress(). \sa NetInterface */ class IRISNET_EXPORT NetInterfaceManager : public QObject { Q_OBJECT public: /** \brief Constructs a new manager object with the given \a parent */ NetInterfaceManager(QObject *parent = 0); /** \brief Destroys the manager object */ ~NetInterfaceManager(); /** \brief Returns the list of available interface ids \sa interfaceAvailable \sa interfaceForAddress */ QStringList interfaces() const; /** \brief Looks up an interface id by IP address This function looks for an interface that has the address \a a. If there is no such interface, a null string is returned. This is useful for determing the network interface associated with an outgoing QTcpSocket: \code QString iface = NetInterfaceManager::interfaceForAddress(tcpSocket->localAddress()); \endcode \sa interfaces */ static QString interfaceForAddress(const QHostAddress &a); signals: /** \brief Notifies when an interface becomes available The \a id parameter is the interface id, ready to use with NetInterface. */ void interfaceAvailable(const QString &id); private: friend class NetInterfaceManagerPrivate; NetInterfaceManagerPrivate *d; friend class NetInterface; friend class NetInterfacePrivate; void *reg(const QString &id, NetInterface *i); void unreg(NetInterface *i); }; } #endif psi-0.14/iris/src/irisnet/corelib/irisnetglobal_p.h0000644000175000017500000000212311305557616020521 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef IRISNETGLOBAL_P_H #define IRISNETGLOBAL_P_H #include "irisnetglobal.h" #include "irisnetplugin.h" namespace XMPP { typedef void (*IrisNetCleanUpFunction)(); IRISNET_EXPORT void irisNetAddPostRoutine(IrisNetCleanUpFunction func); IRISNET_EXPORT QList irisNetProviders(); } #endif psi-0.14/iris/src/irisnet/corelib/irisnetplugin.h0000644000175000017500000001213711305557616020246 0ustar janjan/* * Copyright (C) 2006,2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef IRISNETPLUGIN_H #define IRISNETPLUGIN_H #include "irisnetglobal.h" #include "netinterface.h" #include "netavailability.h" #include "netnames.h" namespace XMPP { class NetInterfaceProvider; class NetAvailabilityProvider; class NameProvider; class ServiceProvider; class IRISNET_EXPORT IrisNetProvider : public QObject { Q_OBJECT public: virtual NetInterfaceProvider *createNetInterfaceProvider(); virtual NetAvailabilityProvider *createNetAvailabilityProvider(); virtual NameProvider *createNameProviderInternet(); virtual NameProvider *createNameProviderLocal(); virtual ServiceProvider *createServiceProvider(); }; class IRISNET_EXPORT NetInterfaceProvider : public QObject { Q_OBJECT public: class Info { public: QString id, name; bool isLoopback; QList addresses; QHostAddress gateway; }; NetInterfaceProvider(QObject *parent = 0) : QObject(parent) { } // calling start should populate an initial list that can be // immediately fetched. do not signal updated() for this. virtual void start() = 0; virtual QList interfaces() const = 0; signals: void updated(); }; class IRISNET_EXPORT NetAvailabilityProvider : public QObject { Q_OBJECT public: NetAvailabilityProvider(QObject *parent = 0) : QObject(parent) { } // calling start should populate an initial value that can be // immediately fetched. do not signal updated() for this. virtual void start() = 0; virtual bool isAvailable() const = 0; signals: void updated(); }; class IRISNET_EXPORT NameProvider : public QObject { Q_OBJECT public: NameProvider(QObject *parent = 0) : QObject(parent) { } virtual bool supportsSingle() const; virtual bool supportsLongLived() const; virtual bool supportsRecordType(int type) const; virtual int resolve_start(const QByteArray &name, int qType, bool longLived) = 0; virtual void resolve_stop(int id) = 0; // transfer from local back to internet virtual void resolve_localResultsReady(int id, const QList &results); virtual void resolve_localError(int id, XMPP::NameResolver::Error e); signals: void resolve_resultsReady(int id, const QList &results); void resolve_error(int id, XMPP::NameResolver::Error e); // transfer from internet to local provider void resolve_useLocal(int id, const QByteArray &name); }; class IRISNET_EXPORT ServiceProvider : public QObject { Q_OBJECT public: class ResolveResult { public: QMap attributes; QHostAddress address; int port; QByteArray hostName; // optional }; ServiceProvider(QObject *parent = 0) : QObject(parent) { } virtual int browse_start(const QString &type, const QString &domain) = 0; virtual void browse_stop(int id) = 0; virtual int resolve_start(const QByteArray &name) = 0; virtual void resolve_stop(int id) = 0; virtual int publish_start(const QString &instance, const QString &type, int port, const QMap &attributes) = 0; virtual void publish_update(int id, const QMap &attributes) = 0; virtual void publish_stop(int id) = 0; virtual int publish_extra_start(int pub_id, const NameRecord &name) = 0; virtual void publish_extra_update(int id, const NameRecord &name) = 0; virtual void publish_extra_stop(int id) = 0; signals: void browse_instanceAvailable(int id, const XMPP::ServiceInstance &instance); void browse_instanceUnavailable(int id, const XMPP::ServiceInstance &instance); void browse_error(int id, XMPP::ServiceBrowser::Error e); void resolve_resultsReady(int id, const QList &results); void resolve_error(int id, XMPP::ServiceResolver::Error e); // update does not cause published() signal to be emitted again void publish_published(int id); void publish_error(int id, XMPP::ServiceLocalPublisher::Error e); // update does not cause published() signal to be emitted again void publish_extra_published(int id); void publish_extra_error(int id, XMPP::ServiceLocalPublisher::Error e); }; } Q_DECLARE_INTERFACE(XMPP::IrisNetProvider, "com.affinix.irisnet.IrisNetProvider/1.0") Q_DECLARE_INTERFACE(XMPP::NetInterfaceProvider, "com.affinix.irisnet.NetInterfaceProvider/1.0") Q_DECLARE_INTERFACE(XMPP::NameProvider, "com.affinix.irisnet.NameProvider/1.0") Q_DECLARE_INTERFACE(XMPP::ServiceProvider, "com.affinix.irisnet.ServiceProvider/1.0") #endif psi-0.14/iris/src/irisnet/corelib/netnames.h0000644000175000017500000003641211305557616017166 0ustar janjan/* * Copyright (C) 2006,2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef NETNAMES_H #define NETNAMES_H #include #include #include "irisnetglobal.h" namespace XMPP { class NameManager; class IRISNET_EXPORT NetNames { public: // free any shared data, shutdown internal dns sessions if necessary. static void cleanup(); // return current diagnostic text, clear the buffer. static QString diagnosticText(); // convert idn names static QByteArray idnaFromString(const QString &in); static QString idnaToString(const QByteArray &in); // dns escaping static QByteArray escapeDomain(const QByteArray &in); static QByteArray unescapeDomain(const QByteArray &in); private: NetNames(); }; /** \brief Provides a DNS record NameRecord provides a DNS (Domain Name System) record, which is information assicated with a domain name. For most purposes, the information is an IP address. However, DNS records are capable of holding a variety of data types, such as named pointers to other domain names and even arbitrary text strings. The results of a NameResolver operation are a list of NameRecords. The most common type is the address record, "A", which contains an IPv4 address. Here is an example of how to get the IP address out of an address record: \code NameRecord record = ... // obtain a record from somewhere if(record.type() == NameRecord::A) { QHostAddress ip = record.address(); // get the IP ... } \endcode Getting the data out of a NameRecord involves calling the right retrieval functions, depending on the type. Many types share retrieval functions. For example, the "AAAA" type holds an IPv6 address, which is accessed the same way as the "A" type, by calling address(). See the NameRecord::Type enum for further information about which retrieval functions should be called for each type. To create a NameRecord, use setOwner() and setTtl() as necessary, and then call one of the setX functions (where X is the desired type). For example, to set an A or AAAA record, use setAddress() like this: \code // make example.com the owner, with 1 hour TTL NameRecord record("example.com", 3600); record.setAddress(QHostAddress("1.2.3.4")); \endcode Note that in the case of setAddress(), the record type need not be specified. NameRecord will determine the type to use based on the given QHostAddress. \sa NameResolver */ class IRISNET_EXPORT NameRecord { public: /** \brief The type of DNS record The retrieval functions are shown for each type. */ enum Type { A, ///< IPv4 address. Use address(). Aaaa, ///< IPv6 address. Use address(). Mx, ///< Mail server. Use name() and priority(). Srv, ///< Generic server. Use name(), port(), priority(), and weight(). Cname, ///< Canonical name. Use name(). Ptr, ///< Pointer. Use name(). Txt, ///< List of text strings. Use texts(). Hinfo, ///< Host information. Use cpu() and os(). Ns, ///< Name server. Use name(). Null, ///< Null type. Use rawData(). Any ///< "Any record", for use with NameResolver::start() only. A NameRecord object will never be of this type. }; /** \brief Constructs a null record object \sa isNull */ NameRecord(); /** \brief Constructs a partially initialized record object, with the given \a owner and \a ttl For the record to be usable, call an appropriate setX function (where X is the desired type) afterwards. */ NameRecord(const QByteArray &owner, int ttl); /** \brief Constructs a copy of \a from */ NameRecord(const NameRecord &from); /** \brief Destroys the record object */ ~NameRecord(); /** \brief Assigns \a from to this object and returns a reference to this object */ NameRecord & operator=(const NameRecord &from); /** \brief Returns true if this record object is null, otherwise returns false Be sure not to confuse a null object with the NULL type (NameRecord::Null). Don't ask why DNS has a type called NULL that contains valid data. */ bool isNull() const; // don't confuse with Null type /** \brief Returns the owner of this record The owner is usually not a useful attribute, since it will be the same as the name searched for with NameResolver. For example, if the A record of "example.com" is looked up, then the resulting records will all have "example.com" as the owner. \sa setOwner */ QByteArray owner() const; /** \brief Returns the TTL (time-to-live) of this record This is the number of seconds the record should be considered valid, which is useful information when performing caching. As a special exception, a TTL of 0 when performing a long-lived lookup indicates that a record is no longer available. \sa setTtl */ int ttl() const; /** \brief Returns the type of this record */ Type type() const; /** \brief Returns the IP address For NameRecord::A and NameRecord::Aaaa types. */ QHostAddress address() const; /** \brief Returns the domain name For NameRecord::Mx, NameRecord::Srv, NameRecord::Cname, NameRecord::Ptr, and NameRecord::Ns types. */ QByteArray name() const; /** \brief Returns the priority For NameRecord::Mx and NameRecord::Srv types. */ int priority() const; /** \brief Returns the weight For the NameRecord::Srv type. */ int weight() const; /** \brief Returns the port For the NameRecord::Srv type. */ int port() const; /** \brief Returns the list of text strings For the NameRecord::Txt type. */ QList texts() const; /** \brief Returns the architecture identifier string For the NameRecord::Hinfo type. */ QByteArray cpu() const; /** \brief Returns the operating system identifier string For the NameRecord::Hinfo type. */ QByteArray os() const; /** \brief Returns the raw data For the NameRecord::Null type. */ QByteArray rawData() const; /** \brief Sets the owner of this record to \a name \sa owner */ void setOwner(const QByteArray &name); /** \brief Sets the TTL (time-to-live) of this record to \a ttl seconds \sa ttl */ void setTtl(int seconds); /** \brief Set as A or AAAA record, with data \a a The protocol of \a a determines whether the type will be NameRecord::A or NameRecord::Aaaa. */ void setAddress(const QHostAddress &a); /** \brief Set as MX record, with data \a name and \a priority */ void setMx(const QByteArray &name, int priority); /** \brief Set as SRV record, with data \a name, \a port, \a priority, and \a weight */ void setSrv(const QByteArray &name, int port, int priority, int weight); /** \brief Set as CNAME record, with data \a name */ void setCname(const QByteArray &name); /** \brief Set as PTR record, with data \a name */ void setPtr(const QByteArray &name); /** \brief Set as TXT record, with data \a texts */ void setTxt(const QList &texts); /** \brief Set as HINFO record, with data \a cpu and \a os */ void setHinfo(const QByteArray &cpu, const QByteArray &os); /** \brief Set as NS record, with data \a name */ void setNs(const QByteArray &name); /** \brief Set as NULL record, with data \a rawData */ void setNull(const QByteArray &rawData); private: class Private; QSharedDataPointer d; }; class IRISNET_EXPORT ServiceInstance { public: ServiceInstance(); ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap &attributes); ServiceInstance(const ServiceInstance &from); ~ServiceInstance(); ServiceInstance & operator=(const ServiceInstance &from); QString instance() const; QString type() const; QString domain() const; QMap attributes() const; QByteArray name() const; // full dns label private: class Private; QSharedDataPointer d; friend class NameManager; }; /** \brief Performs a DNS lookup NameResolver performs an asynchronous DNS lookup for a given domain name and record type. Call start() to begin. The resultsReady() signal is emitted on success, otherwise error() is emitted. To cancel a lookup, call stop(). For example, here is how to obtain the IPv4 addresses of a domain name: \code NameResolver *resolver; void do_lookup() { resolver = new NameResolver; connect(resolver, SIGNAL(resultsReady(const QList &)), SLOT(dns_resultsReady(const QList &))); connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error))); // look up affinix.com resolver->start("affinix.com"); } void dns_resultsReady(const QList &results) { // print IP addresses foreach(NameRecord i, results) printf("%s\n", qPrintable(i.address().toString())); } void dns_error(XMPP::NameResolver::Error error) { // handle error ... } \endcode Yes, a domain name can have multiple IP addresses. Many applications ignore this fact, and use only one of the answers. A proper network application should try connecting to each IP address until one succeeds. To lookup other types, pass the desired type to start(). For example, suppose you want to look up the MX record of a domain name: \code // look up the MX record for affinix.com resolver->start("affinix.com", NameRecord::Mx); \endcode It is also possible to perform long-lived queries. This is generally useful for DNS Service Discovery. Long-lived queries are continuous, and resultsReady() may be emitted multiple times. Unlike a normal lookup, which stops once the results are returned, a long-lived query will keep going until stop() is called. For example, suppose you want to scan the local network for SSH services. According to the DNS-SD protocol, this is done by querying for the name "_ssh._tcp.local." of type PTR. \code // monitor for SSH services on the local network resolver->start("_ssh._tcp.local.", NameRecord::Ptr, NameResolver::LongLived); \endcode Don't be alarmed by the trailing dot (".") character in this last example. It is not well known, but all valid DNS domain names end with a dot. However, NameResolver, like most DNS programming interfaces, allows the dot to be left out. What this means is that if a trailing dot is missing in the input to start(), NameResolver will internally append one before performing the query. \sa NameRecord */ class IRISNET_EXPORT NameResolver : public QObject { Q_OBJECT public: /** \brief Resolve mode */ enum Mode { Single, ///< A normal DNS query with a single result set. LongLived ///< An endless query, with multiple result sets allowed. }; /** \brief Resolve error */ enum Error { ErrorGeneric, ///< General failure during lookup, no further details. ErrorNoName, ///< Name does not exist. ErrorTimeout, ///< The operation timed out. ErrorNoLocal, ///< The query is to the local network, but no mechanism for Multicast DNS is available. ErrorNoLongLived ///< The query requires long-lived capability, but no mechanism for doing so is available. }; /** \brief Constructs a new resolver object with the given \a parent */ NameResolver(QObject *parent = 0); /** \brief Destroys the resolver object The lookup is, of course, stopped. */ ~NameResolver(); /** \brief Starts a lookup A lookup for \a name of \a type is started. For normal queries, \a mode should be NameResolver::Single (this is the default). For long-lived queries, use NameResolver::LongLived. \sa stop */ void start(const QByteArray &name, NameRecord::Type type = NameRecord::A, Mode mode = Single); /** \brief Stops a lookup Use this function if you want to stop the current lookup, such that the resolver object may be reused again later. If you don't plan to reuse the object, then destroying the object is enough. \sa start */ void stop(); signals: /** \brief Notification of result records This signal is emitted when results of the lookup operation have arrived. The \a results parameter is a list of NameRecords. All records will be of the type queried for with start(), unless the NameRecord::Any type was specified, in which case the records may be of any type When using the NameResolver::Single mode, the lookup is stopped once results are ready. However, with the NameResolver::LongLived mode, the lookup stays active, and in that case this signal may be emitted multiple times. */ void resultsReady(const QList &results); /** \brief Notification of error This signal is emitted if an error has occurred while performing a lookup. The reason for error can be found in \a e. Regardless of the mode used, the lookup is stopped when an error occurs. */ void error(XMPP::NameResolver::Error e); private: class Private; friend class Private; Private *d; friend class NameManager; }; class IRISNET_EXPORT ServiceBrowser : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, ErrorNoLocal, ErrorNoWide }; ServiceBrowser(QObject *parent = 0); ~ServiceBrowser(); void start(const QString &type, const QString &domain = "local"); void stop(); signals: void instanceAvailable(const XMPP::ServiceInstance &instance); void instanceUnavailable(const XMPP::ServiceInstance &instance); void error(); private: class Private; friend class Private; Private *d; friend class NameManager; }; class IRISNET_EXPORT ServiceResolver : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, ErrorTimeout, ErrorNoLocal }; ServiceResolver(QObject *parent = 0); ~ServiceResolver(); void startFromInstance(const QByteArray &name); void startFromDomain(const QString &domain, const QString &type); void startFromPlain(const QString &host, int port); // non-SRV void tryNext(); void stop(); signals: void resultsReady(const QHostAddress &address, int port); void finished(); void error(); // SRV lookup failed private: class Private; friend class Private; Private *d; friend class NameManager; }; class IRISNET_EXPORT ServiceLocalPublisher : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, // generic error ErrorConflict, // name in use ErrorNoLocal // unable to setup multicast dns }; ServiceLocalPublisher(QObject *parent = 0); ~ServiceLocalPublisher(); void publish(const QString &instance, const QString &type, int port, const QMap &attributes); void updateAttributes(const QMap &attributes); void addRecord(const NameRecord &rec); void cancel(); signals: void published(); void error(XMPP::ServiceLocalPublisher::Error e); private: class Private; friend class Private; Private *d; friend class NameManager; }; } #endif psi-0.14/iris/src/irisnet/corelib/netinterface_win.cpp0000644000175000017500000000253511305557616021232 0ustar janjan/* * Copyright (C) 2008 Barracuda Networks * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "irisnetplugin.h" namespace XMPP { class WinNet : public NetInterfaceProvider { Q_OBJECT Q_INTERFACES(XMPP::NetInterfaceProvider) public: WinNet() { } void start() { } QList interfaces() const { return QList(); } }; class WinNetProvider : public IrisNetProvider { Q_OBJECT Q_INTERFACES(XMPP::IrisNetProvider) public: virtual NetInterfaceProvider *createNetInterfaceProvider() { return new WinNet; } }; IrisNetProvider *irisnet_createWinNetProvider() { return new WinNetProvider; } } #include "netinterface_win.moc" psi-0.14/iris/src/irisnet/corelib/netavailability.cpp0000644000175000017500000000234611305557616021067 0ustar janjan/* * Copyright (C) 2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "netavailability.h" namespace XMPP { class NetAvailability::Private : public QObject { Q_OBJECT public: NetAvailability *q; Private(NetAvailability *_q) : QObject(_q), q(_q) { } }; NetAvailability::NetAvailability(QObject *parent) : QObject(parent) { d = new Private(this); } NetAvailability::~NetAvailability() { delete d; } bool NetAvailability::isAvailable() const { // TODO return true; } } #include "netavailability.moc" psi-0.14/iris/src/irisnet/corelib/netavailability.h0000644000175000017500000000221011305557616020522 0ustar janjan/* * Copyright (C) 2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef NETAVAILABILITY_H #define NETAVAILABILITY_H #include "irisnetglobal.h" namespace XMPP { class NetAvailability : public QObject { Q_OBJECT public: NetAvailability(QObject *parent = 0); ~NetAvailability(); bool isAvailable() const; signals: void changed(bool available); private: class Private; friend class Private; Private *d; }; } #endif psi-0.14/iris/src/irisnet/corelib/corelib.pro0000644000175000017500000000057511305557616017345 0ustar janjanIRIS_BASE = ../../.. TEMPLATE = lib QT -= gui TARGET = irisnetcore DESTDIR = $$IRIS_BASE/lib windows:DLLDESTDIR = $$IRIS_BASE/bin VERSION = 1.0.0 include(../../libbase.pri) include(corelib.pri) # fixme: irisnetcore builds as dll or bundled, never static? CONFIG += create_prl windows:!staticlib:DEFINES += IRISNET_MAKEDLL staticlib:PRL_EXPORT_DEFINES += IRISNET_STATIC psi-0.14/iris/src/irisnet/corelib/irisnetexport.h0000644000175000017500000000203211305557616020262 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef IRISNETEXPORT_H #define IRISNETEXPORT_H #include #ifdef IRISNET_STATIC # define IRISNET_EXPORT #else # ifdef IRISNET_MAKEDLL # define IRISNET_EXPORT Q_DECL_EXPORT # else # define IRISNET_EXPORT Q_DECL_IMPORT # endif #endif #endif psi-0.14/iris/src/irisnet/corelib/netnames_jdns.cpp0000644000175000017500000015277211305557616020547 0ustar janjan/* * Copyright (C) 2005-2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "irisnetplugin.h" #include "objectsession.h" #include "jdnsshared.h" #include "netinterface.h" //#define JDNS_DEBUG Q_DECLARE_METATYPE(XMPP::NameRecord) Q_DECLARE_METATYPE(XMPP::NameResolver::Error) Q_DECLARE_METATYPE(XMPP::ServiceBrowser::Error) Q_DECLARE_METATYPE(XMPP::ServiceResolver::Error) Q_DECLARE_METATYPE(XMPP::ServiceLocalPublisher::Error) namespace XMPP { static NameRecord importJDNSRecord(const QJDns::Record &in) { NameRecord out; switch(in.type) { case QJDns::A: out.setAddress(in.address); break; case QJDns::Aaaa: out.setAddress(in.address); break; case QJDns::Mx: out.setMx(in.name, in.priority); break; case QJDns::Srv: out.setSrv(in.name, in.port, in.priority, in.weight); break; case QJDns::Cname: out.setCname(in.name); break; case QJDns::Ptr: out.setPtr(in.name); break; case QJDns::Txt: out.setTxt(in.texts); break; case QJDns::Hinfo: out.setHinfo(in.cpu, in.os); break; case QJDns::Ns: out.setNs(in.name); break; case 10: out.setNull(in.rdata); break; default: return out; } out.setOwner(in.owner); out.setTtl(in.ttl); return out; } static QJDns::Record exportJDNSRecord(const NameRecord &in) { QJDns::Record out; switch(in.type()) { case NameRecord::A: out.type = QJDns::A; out.haveKnown = true; out.address = in.address(); break; case NameRecord::Aaaa: out.type = QJDns::Aaaa; out.haveKnown = true; out.address = in.address(); break; case NameRecord::Mx: out.type = QJDns::Mx; out.haveKnown = true; out.name = in.name(); out.priority = in.priority(); break; case NameRecord::Srv: out.type = QJDns::Srv; out.haveKnown = true; out.name = in.name(); out.port = in.port(); out.priority = in.priority(); out.weight = in.weight(); break; case NameRecord::Cname: out.type = QJDns::Cname; out.haveKnown = true; out.name = in.name(); break; case NameRecord::Ptr: out.type = QJDns::Ptr; out.haveKnown = true; out.name = in.name(); break; case NameRecord::Txt: out.type = QJDns::Txt; out.haveKnown = true; out.texts = in.texts(); break; case NameRecord::Hinfo: out.type = QJDns::Hinfo; out.haveKnown = true; out.cpu = in.cpu(); out.os = in.os(); break; case NameRecord::Ns: out.type = QJDns::Ns; out.haveKnown = true; out.name = in.name(); break; case NameRecord::Null: out.type = 10; out.rdata = in.rawData(); break; default: return out; } out.owner = in.owner(); out.ttl = in.ttl(); return out; } static bool validServiceType(const QByteArray &in) { // can't be empty, or start/end with a dot if(in.isEmpty() || in[0] == '.' || in[in.length() - 1] == '.') return false; // must contain exactly one dot int dotcount = 0; for(int n = 0; n < in.length(); ++n) { if(in[n] == '.') { ++dotcount; // no need to count more than 2 if(dotcount >= 2) break; } } if(dotcount != 1) return false; return true; } static QByteArray escapeDomainPart(const QByteArray &in) { QByteArray out; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') out += "\\\\"; else if(in[n] == '.') out += "\\."; else out += in[n]; } return out; } static QByteArray unescapeDomainPart(const QByteArray &in) { QByteArray out; for(int n = 0; n < in.length(); ++n) { if(in[n] == '\\') { if(n + 1 >= in.length()) return QByteArray(); out += in[n + 1]; } else out += in[n]; } return out; } class IdManager { private: QSet set; int at; inline void bump_at() { if(at == 0x7fffffff) at = 0; else ++at; } public: IdManager() : at(0) { } int reserveId() { while(1) { if(!set.contains(at)) { int id = at; set.insert(id); bump_at(); return id; } bump_at(); } } void releaseId(int id) { set.remove(id); } void clear() { set.clear(); at = 0; } }; //---------------------------------------------------------------------------- // JDnsGlobal //---------------------------------------------------------------------------- class JDnsGlobal : public QObject { Q_OBJECT public: JDnsSharedDebug db; JDnsShared *uni_net, *uni_local, *mul; QHostAddress mul_addr4, mul_addr6; NetInterfaceManager netman; QList ifaces; QTimer *updateTimer; JDnsGlobal() : netman(this) { uni_net = 0; uni_local = 0; mul = 0; qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); connect(&db, SIGNAL(readyRead()), SLOT(jdns_debugReady())); updateTimer = new QTimer(this); connect(updateTimer, SIGNAL(timeout()), SLOT(doUpdateMulticastInterfaces())); updateTimer->setSingleShot(true); } ~JDnsGlobal() { updateTimer->disconnect(this); updateTimer->setParent(0); updateTimer->deleteLater(); qDeleteAll(ifaces); QList list; if(uni_net) list += uni_net; if(uni_local) list += uni_local; if(mul) list += mul; // calls shutdown on the list, waits for shutdownFinished, deletes JDnsShared::waitForShutdown(list); // get final debug jdns_debugReady(); } JDnsShared *ensure_uni_net() { if(!uni_net) { uni_net = new JDnsShared(JDnsShared::UnicastInternet, this); uni_net->setDebug(&db, "U"); bool ok4 = uni_net->addInterface(QHostAddress::Any); bool ok6 = uni_net->addInterface(QHostAddress::AnyIPv6); if(!ok4 && !ok6) { delete uni_net; uni_net = 0; } } return uni_net; } JDnsShared *ensure_uni_local() { if(!uni_local) { uni_local = new JDnsShared(JDnsShared::UnicastLocal, this); uni_local->setDebug(&db, "L"); bool ok4 = uni_local->addInterface(QHostAddress::Any); bool ok6 = uni_local->addInterface(QHostAddress::AnyIPv6); if(!ok4 && !ok6) { delete uni_local; uni_local = 0; } } return uni_local; } JDnsShared *ensure_mul() { if(!mul) { mul = new JDnsShared(JDnsShared::Multicast, this); mul->setDebug(&db, "M"); connect(&netman, SIGNAL(interfaceAvailable(const QString &)), SLOT(iface_available(const QString &))); // get the current network interfaces. this initial // fetching should not trigger any calls to // updateMulticastInterfaces(). only future // activity should do that. foreach(const QString &id, netman.interfaces()) { NetInterface *iface = new NetInterface(id, &netman); connect(iface, SIGNAL(unavailable()), SLOT(iface_unavailable())); ifaces += iface; } updateMulticastInterfaces(false); } return mul; } bool haveMulticast4() const { return !mul_addr4.isNull(); } bool haveMulticast6() const { return !mul_addr6.isNull(); } signals: void interfacesChanged(); private slots: void jdns_debugReady() { QStringList lines = db.readDebugLines(); #ifdef JDNS_DEBUG for(int n = 0; n < lines.count(); ++n) printf("jdns: %s\n", qPrintable(lines[n])); #else Q_UNUSED(lines); #endif } void iface_available(const QString &id) { NetInterface *iface = new NetInterface(id, &netman); connect(iface, SIGNAL(unavailable()), SLOT(iface_unavailable())); ifaces += iface; updateTimer->start(100); } void iface_unavailable() { NetInterface *iface = (NetInterface *)sender(); ifaces.removeAll(iface); delete iface; updateTimer->start(100); } void doUpdateMulticastInterfaces() { updateMulticastInterfaces(true); } private: void updateMulticastInterfaces(bool useSignals) { QHostAddress addr4 = QJDns::detectPrimaryMulticast(QHostAddress::Any); QHostAddress addr6 = QJDns::detectPrimaryMulticast(QHostAddress::AnyIPv6); bool had4 = !mul_addr4.isNull(); bool had6 = !mul_addr6.isNull(); updateMulticastInterface(&mul_addr4, addr4); updateMulticastInterface(&mul_addr6, addr6); bool have4 = !mul_addr4.isNull(); bool have6 = !mul_addr6.isNull(); // did we gain/lose something? if(had4 != have4 || had6 != have6) { if(useSignals) emit interfacesChanged(); } } void updateMulticastInterface(QHostAddress *curaddr, const QHostAddress &newaddr) { if(!(newaddr == *curaddr)) // QHostAddress doesn't have operator!= { if(!curaddr->isNull()) mul->removeInterface(*curaddr); *curaddr = newaddr; if(!curaddr->isNull()) { if(!mul->addInterface(*curaddr)) *curaddr = QHostAddress(); } } } }; //---------------------------------------------------------------------------- // JDnsNameProvider //---------------------------------------------------------------------------- class JDnsNameProvider : public NameProvider { Q_OBJECT Q_INTERFACES(XMPP::NameProvider) public: enum Mode { Internet, Local }; JDnsGlobal *global; Mode mode; IdManager idman; ObjectSession sess; class Item { public: int id; JDnsSharedRequest *req; int type; bool longLived; ObjectSession sess; bool localResult; Item(QObject *parent = 0) : id(-1), req(0), sess(parent), localResult(false) { } ~Item() { delete req; } }; QList items; static JDnsNameProvider *create(JDnsGlobal *global, Mode mode, QObject *parent = 0) { if(mode == Internet) { if(!global->ensure_uni_net()) return 0; } else { if(!global->ensure_uni_local()) return 0; } return new JDnsNameProvider(global, mode, parent); } JDnsNameProvider(JDnsGlobal *_global, Mode _mode, QObject *parent = 0) : NameProvider(parent) { global = _global; mode = _mode; } ~JDnsNameProvider() { qDeleteAll(items); } Item *getItemById(int id) { for(int n = 0; n < items.count(); ++n) { if(items[n]->id == id) return items[n]; } return 0; } Item *getItemByReq(JDnsSharedRequest *req) { for(int n = 0; n < items.count(); ++n) { if(items[n]->req == req) return items[n]; } return 0; } void releaseItem(Item *i) { idman.releaseId(i->id); items.removeAll(i); delete i; } virtual bool supportsSingle() const { return true; } virtual bool supportsLongLived() const { if(mode == Local) return true; // we support long-lived local queries else return false; // we do NOT support long-lived internet queries } virtual bool supportsRecordType(int type) const { // all record types supported Q_UNUSED(type); return true; } virtual int resolve_start(const QByteArray &name, int qType, bool longLived) { if(mode == Internet) { // if query ends in .local, switch to local resolver if(name.right(6) == ".local" || name.right(7) == ".local.") { Item *i = new Item(this); i->id = idman.reserveId(); i->longLived = longLived; items += i; i->sess.defer(this, "do_local", Q_ARG(int, i->id), Q_ARG(QByteArray, name)); return i->id; } // we don't support long-lived internet queries if(longLived) { Item *i = new Item(this); i->id = idman.reserveId(); items += i; i->sess.defer(this, "do_error", Q_ARG(int, i->id), Q_ARG(XMPP::NameResolver::Error, NameResolver::ErrorNoLongLived)); return i->id; } // perform the query Item *i = new Item(this); i->id = idman.reserveId(); i->req = new JDnsSharedRequest(global->uni_net); connect(i->req, SIGNAL(resultsReady()), SLOT(req_resultsReady())); i->type = qType; i->longLived = false; items += i; i->req->query(name, qType); return i->id; } else { Item *i = new Item(this); i->id = idman.reserveId(); i->type = qType; if(longLived) { if(!global->ensure_mul()) { items += i; i->sess.defer(this, "do_error", Q_ARG(int, i->id), Q_ARG(XMPP::NameResolver::Error, NameResolver::ErrorNoLocal)); return i->id; } i->req = new JDnsSharedRequest(global->mul); i->longLived = true; } else { i->req = new JDnsSharedRequest(global->uni_local); i->longLived = false; } connect(i->req, SIGNAL(resultsReady()), SLOT(req_resultsReady())); items += i; i->req->query(name, qType); return i->id; } } virtual void resolve_stop(int id) { Item *i = getItemById(id); Q_ASSERT(i); if(i->req) i->req->cancel(); releaseItem(i); } virtual void resolve_localResultsReady(int id, const QList &results) { Item *i = getItemById(id); Q_ASSERT(i); Q_ASSERT(!i->localResult); i->localResult = true; i->sess.defer(this, "do_local_ready", Q_ARG(int, id), Q_ARG(QList, results)); } virtual void resolve_localError(int id, XMPP::NameResolver::Error e) { Item *i = getItemById(id); Q_ASSERT(i); Q_ASSERT(!i->localResult); i->localResult = true; i->sess.defer(this, "do_local_error", Q_ARG(int, id), Q_ARG(XMPP::NameResolver::Error, e)); } private slots: void req_resultsReady() { JDnsSharedRequest *req = (JDnsSharedRequest *)sender(); Item *i = getItemByReq(req); Q_ASSERT(i); int id = i->id; if(req->success()) { QList out; foreach(const QJDns::Record &r, req->results()) { // unless we are asking for all types, only // accept the type we asked for if(i->type == QJDns::Any || r.type == i->type) { NameRecord rec = importJDNSRecord(r); if(!rec.isNull()) out += rec; } } // don't report anything if long-lived gives no results if(i->longLived && out.isEmpty()) return; // only emit success if we have at least 1 result if(!out.isEmpty()) { if(!i->longLived) releaseItem(i); emit resolve_resultsReady(id, out); } else { releaseItem(i); emit resolve_error(id, NameResolver::ErrorGeneric); } } else { JDnsSharedRequest::Error e = req->error(); releaseItem(i); NameResolver::Error error = NameResolver::ErrorGeneric; if(e == JDnsSharedRequest::ErrorNXDomain) error = NameResolver::ErrorNoName; else if(e == JDnsSharedRequest::ErrorTimeout) error = NameResolver::ErrorTimeout; else // ErrorGeneric or ErrorNoNet error = NameResolver::ErrorGeneric; emit resolve_error(id, error); } } void do_error(int id, XMPP::NameResolver::Error e) { Item *i = getItemById(id); Q_ASSERT(i); releaseItem(i); emit resolve_error(id, e); } void do_local(int id, const QByteArray &name) { Item *i = getItemById(id); Q_ASSERT(i); // resolve_useLocal has two behaviors: // - if longlived, then it indicates a hand-off // - if non-longlived, then it indicates we want a subquery if(i->longLived) releaseItem(i); emit resolve_useLocal(id, name); } void do_local_ready(int id, const QList &results) { Item *i = getItemById(id); Q_ASSERT(i); // only non-longlived queries come through here, so we're done releaseItem(i); emit resolve_resultsReady(id, results); } void do_local_error(int id, XMPP::NameResolver::Error e) { Item *i = getItemById(id); Q_ASSERT(i); releaseItem(i); emit resolve_error(id, e); } }; //---------------------------------------------------------------------------- // JDnsBrowse //---------------------------------------------------------------------------- class JDnsBrowse : public QObject { Q_OBJECT public: QByteArray type, typeAndDomain; JDnsSharedRequest req; JDnsBrowse(JDnsShared *_jdns, QObject *parent = 0) : QObject(parent), req(_jdns, this) { connect(&req, SIGNAL(resultsReady()), SLOT(jdns_resultsReady())); } void start(const QByteArray &_type) { type = _type; Q_ASSERT(validServiceType(type)); typeAndDomain = type + ".local."; req.query(typeAndDomain, QJDns::Ptr); } signals: void available(const QByteArray &instance); void unavailable(const QByteArray &instance); private: QByteArray parseInstanceName(const QByteArray &name) { // needs to be at least X + '.' + typeAndDomain if(name.length() < typeAndDomain.length() + 2) return QByteArray(); // index of the '.' character int at = name.length() - typeAndDomain.length() - 1; if(name[at] != '.') return QByteArray(); if(name.mid(at + 1) != typeAndDomain) return QByteArray(); QByteArray friendlyName = unescapeDomainPart(name.mid(0, at)); if(friendlyName.isEmpty()) return QByteArray(); return friendlyName; } private slots: void jdns_resultsReady() { // ignore errors if(!req.success()) return; QJDns::Record rec = req.results().first(); Q_ASSERT(rec.type == QJDns::Ptr); QByteArray name = rec.name; QByteArray instance = parseInstanceName(name); if(instance.isEmpty()) return; if(rec.ttl == 0) { emit unavailable(instance); return; } emit available(instance); } }; //---------------------------------------------------------------------------- // JDnsServiceResolve //---------------------------------------------------------------------------- // 5 second timeout waiting for both A and AAAA // 8 second timeout waiting for at least one record class JDnsServiceResolve : public QObject { Q_OBJECT public: enum SrvState { Srv = 0, AddressWait = 1, AddressFirstCome = 2 }; JDnsSharedRequest reqtxt; // for TXT JDnsSharedRequest req; // for SRV/A JDnsSharedRequest req6; // for AAAA bool haveTxt; SrvState srvState; QTimer *opTimer; // out QList attribs; QByteArray host; int port; bool have4, have6; QHostAddress addr4, addr6; JDnsServiceResolve(JDnsShared *_jdns, QObject *parent = 0) : QObject(parent), reqtxt(_jdns, this), req(_jdns, this), req6(_jdns, this) { connect(&reqtxt, SIGNAL(resultsReady()), SLOT(reqtxt_ready())); connect(&req, SIGNAL(resultsReady()), SLOT(req_ready())); connect(&req6, SIGNAL(resultsReady()), SLOT(req6_ready())); opTimer = new QTimer(this); connect(opTimer, SIGNAL(timeout()), SLOT(op_timeout())); opTimer->setSingleShot(true); } ~JDnsServiceResolve() { opTimer->disconnect(this); opTimer->setParent(0); opTimer->deleteLater(); } void start(const QByteArray name) { haveTxt = false; srvState = Srv; have4 = false; have6 = false; opTimer->start(8000); reqtxt.query(name, QJDns::Txt); req.query(name, QJDns::Srv); } signals: void finished(); void error(JDnsSharedRequest::Error e); private: void cleanup() { if(opTimer->isActive()) opTimer->stop(); if(!haveTxt) reqtxt.cancel(); if(srvState == Srv || !have4) req.cancel(); if(srvState >= AddressWait && !have6) req6.cancel(); } bool tryDone() { // we're done when we have txt and addresses if(haveTxt && ( (have4 && have6) || (srvState == AddressFirstCome && (have4 || have6)) )) { cleanup(); emit finished(); return true; } return false; } private slots: void reqtxt_ready() { if(!reqtxt.success()) { cleanup(); emit error(reqtxt.error()); return; } QJDns::Record rec = reqtxt.results().first(); reqtxt.cancel(); Q_ASSERT(rec.type == QJDns::Txt); attribs.clear(); if(!rec.texts.isEmpty()) { // if there is only 1 text, it needs to be // non-empty for us to care if(rec.texts.count() != 1 || !rec.texts[0].isEmpty()) attribs = rec.texts; } haveTxt = true; tryDone(); } void req_ready() { if(!req.success()) { cleanup(); emit error(req.error()); return; } QJDns::Record rec = req.results().first(); req.cancel(); if(srvState == Srv) { // in Srv state, req is used for SRV records Q_ASSERT(rec.type == QJDns::Srv); host = rec.name; port = rec.port; srvState = AddressWait; opTimer->start(5000); req.query(host, QJDns::A); req6.query(host, QJDns::Aaaa); } else { // in the other states, req is used for A records Q_ASSERT(rec.type == QJDns::A); addr4 = rec.address; have4 = true; tryDone(); } } void req6_ready() { if(!req6.success()) { cleanup(); emit error(req6.error()); return; } QJDns::Record rec = req6.results().first(); req6.cancel(); Q_ASSERT(rec.type == QJDns::Aaaa); addr6 = rec.address; have6 = true; tryDone(); } void op_timeout() { if(srvState == Srv) { // timeout getting SRV. it is possible that we could // have obtained the TXT record, but if SRV times // out then we consider the whole job to have // failed. cleanup(); emit error(JDnsSharedRequest::ErrorTimeout); } else if(srvState == AddressWait) { // timeout while waiting for both A and AAAA. we now // switch to the AddressFirstCome state, where an // answer for either will do srvState = AddressFirstCome; // if we have at least one of these, we're done if(have4 || have6) { // well, almost. we might still be waiting // for the TXT record if(tryDone()) return; } // if we are here, then it means we are missing TXT // still, or we have neither A nor AAAA. // wait 3 more seconds opTimer->start(3000); } else // AddressFirstCome { // last chance! if(!tryDone()) { cleanup(); emit error(JDnsSharedRequest::ErrorTimeout); } } } }; //---------------------------------------------------------------------------- // JDnsPublishAddresses //---------------------------------------------------------------------------- // helper class for JDnsPublishAddresses. publishes A+PTR or AAAA+PTR pair. class JDnsPublishAddress : public QObject { Q_OBJECT public: enum Type { IPv4, IPv6 }; Type type; QByteArray host; JDnsSharedRequest pub_addr; JDnsSharedRequest pub_ptr; bool success_; JDnsPublishAddress(JDnsShared *_jdns, QObject *parent = 0) : QObject(parent), pub_addr(_jdns, this), pub_ptr(_jdns, this) { connect(&pub_addr, SIGNAL(resultsReady()), SLOT(pub_addr_ready())); connect(&pub_ptr, SIGNAL(resultsReady()), SLOT(pub_ptr_ready())); } void start(Type _type, const QByteArray &_host) { type = _type; host = _host; success_ = false; QJDns::Record rec; if(type == IPv6) rec.type = QJDns::Aaaa; else rec.type = QJDns::A; rec.owner = host; rec.ttl = 120; rec.haveKnown = true; rec.address = QHostAddress(); // null address, will be filled in pub_addr.publish(QJDns::Unique, rec); } void cancel() { pub_addr.cancel(); pub_ptr.cancel(); } bool success() const { return success_; } signals: void resultsReady(); private slots: void pub_addr_ready() { if(pub_addr.success()) { QJDns::Record rec; rec.type = QJDns::Ptr; if(type == IPv6) rec.owner = ".ip6.arpa."; else rec.owner = ".in-addr.arpa."; rec.ttl = 120; rec.haveKnown = true; rec.name = host; pub_ptr.publish(QJDns::Shared, rec); } else { pub_ptr.cancel(); // needed if addr fails during or after ptr success_ = false; emit resultsReady(); } } void pub_ptr_ready() { if(pub_ptr.success()) { success_ = true; } else { pub_addr.cancel(); success_ = false; } emit resultsReady(); } }; // This class publishes A/AAAA records for the machine, using a derived // hostname (it will use QHostInfo::localHostName(), but append a unique // suffix if necessary). If there is ever a record conflict, it will // republish under a unique name. // // The hostName() signal is emitted when a hostname is successfully // published as. When there is a conflict, hostName() is emitted with // an empty value, and will again be emitted with a non-empty value // once the conflict is resolved. A missing hostname is considered a // temporary problem, and so other publish operations that depend on a // hostname (SRV, etc) should block until a hostname is available. class JDnsPublishAddresses : public QObject { Q_OBJECT public: bool started; bool use6, use4; JDnsPublishAddress pub6; JDnsPublishAddress pub4; int counter; QByteArray host; bool success; bool have6, have4; ObjectSession sess; JDnsPublishAddresses(JDnsShared *_jdns, QObject *parent = 0) : QObject(parent), started(false), use6(false), use4(false), pub6(_jdns, this), pub4(_jdns, this), sess(this) { connect(&pub6, SIGNAL(resultsReady()), SLOT(pub6_ready())); connect(&pub4, SIGNAL(resultsReady()), SLOT(pub4_ready())); } void start() { counter = 1; success = false; have6 = false; have4 = false; started = true; tryPublish(); } bool isStarted() const { return started; } // comments in this method apply to setUseIPv4 as well. void setUseIPv6(bool b) { if(b == use6) return; use6 = b; if(!started) return; // a "deferred call to doDisable" and "publish operations" // are mutually exclusive. thus, a deferred call is only // invoked when both publishes are canceled, and the // deferred call is canceled if any of the publishes are // reinstantiated. if(use6) { if(use4) { // if the other is already active, then // just activate this one without // recomputing the hostname tryPublish6(); } else { sess.reset(); // otherwise, recompute the hostname tryPublish(); } } else { pub6.cancel(); have6 = false; if(!use4) sess.defer(this, "doDisable"); } } void setUseIPv4(bool b) { if(b == use4) return; use4 = b; if(!started) return; if(use4) { if(use6) { tryPublish4(); } else { sess.reset(); tryPublish(); } } else { pub4.cancel(); have4 = false; if(!use6) sess.defer(this, "doDisable"); } } signals: void hostName(const QByteArray &str); private: void tryPublish() { QString me = QHostInfo::localHostName(); // some hosts may already have ".local" in their name if(me.endsWith(".local")) me.truncate(me.length() - 6); // prefix our hostname so we don't conflict with a system // mdns daemon me.prepend("jdns-"); if(counter > 1) me += QString("-%1").arg(counter); host = escapeDomainPart(me.toUtf8()) + ".local."; if(use6) tryPublish6(); if(use4) tryPublish4(); } void tryPublish6() { pub6.start(JDnsPublishAddress::IPv6, host); } void tryPublish4() { pub4.start(JDnsPublishAddress::IPv4, host); } void tryDone() { bool done = true; if(use6 && !have6) done = false; if(use4 && !have4) done = false; if(done) { success = true; emit hostName(host); } } void handleFail() { // we get here if we fail to publish at all, or if we // successfully publish but then fail later on. in the // latter case it means we "lost" our host records. bool lostHost = success; // as in earlier publish success success = false; // if we lost a hostname with a suffix, or counter is // at 99, then start counter over at 1 (no suffix). if((lostHost && counter > 1) || counter >= 99) counter = 1; else ++counter; tryPublish(); // only emit lost host signal once if(lostHost) emit hostName(QByteArray()); } private slots: void doDisable() { bool lostHost = success; success = false; if(lostHost) emit hostName(QByteArray()); } void pub6_ready() { if(pub6.success()) { have6 = true; tryDone(); } else { have6 = false; have4 = false; pub4.cancel(); handleFail(); } } void pub4_ready() { if(pub4.success()) { have4 = true; tryDone(); } else { have4 = false; have6 = false; pub6.cancel(); handleFail(); } } }; //---------------------------------------------------------------------------- // JDnsPublish //---------------------------------------------------------------------------- class JDnsPublish; class JDnsPublishExtra : public QObject { Q_OBJECT public: JDnsPublishExtra(JDnsPublish *_jdnsPub); ~JDnsPublishExtra(); void start(const QJDns::Record &_rec); void update(const QJDns::Record &_rec); signals: void published(); void error(JDnsSharedRequest::Error e); private: friend class JDnsPublish; JDnsPublish *jdnsPub; bool started; JDnsSharedRequest pub; QJDns::Record rec; bool have; bool need_update; }; // This class publishes SRV/TXT/PTR for a service. if a hostName is not // is not available (see JDnsPublishAddresses) then the publish action // will be deferred until one is available. SRV and TXT are published // as unique records, and once they both succeed then the PTR record // is published. once the PTR succeeds, then published() is emitted. // if a conflict occurs with any action, then the whole thing fails and // error() is emitted. if, at any time, the hostName is lost, then // then the SRV operation is canceled, but no error is emitted. when the // hostName is regained, then the SRV record is republished. // // It's important to note that published() is only emitted once ever, even // if a hostName change causes a republishing. this way, hostName changes // are completely transparent. class JDnsPublish : public QObject { Q_OBJECT public: JDnsShared *jdns; JDnsSharedRequest pub_srv; JDnsSharedRequest pub_txt; JDnsSharedRequest pub_ptr; bool have_srv, have_txt, have_ptr; bool need_update_txt; QByteArray fullname; QByteArray instance; QByteArray type; QByteArray host; int port; QList attribs; QSet extraList; JDnsPublish(JDnsShared *_jdns, QObject *parent = 0) : QObject(parent), jdns(_jdns), pub_srv(_jdns, this), pub_txt(_jdns, this), pub_ptr(_jdns, this) { connect(&pub_srv, SIGNAL(resultsReady()), SLOT(pub_srv_ready())); connect(&pub_txt, SIGNAL(resultsReady()), SLOT(pub_txt_ready())); connect(&pub_ptr, SIGNAL(resultsReady()), SLOT(pub_ptr_ready())); } ~JDnsPublish() { qDeleteAll(extraList); } void start(const QString &_instance, const QByteArray &_type, const QByteArray &localHost, int _port, const QMap &attributes) { type = _type; Q_ASSERT(validServiceType(type)); instance = escapeDomainPart(_instance.toUtf8()); fullname = instance + '.' + type + ".local."; host = localHost; port = _port; attribs = makeTxtList(attributes); have_srv = false; have_txt = false; have_ptr = false; need_update_txt = false; // no host? defer publishing till we have one if(host.isEmpty()) return; doPublish(); } void update(const QMap &attributes) { attribs = makeTxtList(attributes); // still publishing the initial txt? if(!have_txt) { // flag that we want to update once the publish // succeeds. need_update_txt = true; return; } // no SRV, but have TXT? this means we lost SRV due to // a hostname change. if(!have_srv) { // in that case, revoke the TXT. it'll get // republished after SRV then. have_txt = false; pub_txt.cancel(); return; } doPublishTxt(); } public slots: // pass empty host if host lost void hostChanged(const QByteArray &_host) { bool changed = (host != _host); if(changed) { host = _host; if(host.isEmpty()) { // cancel srv record momentarily have_srv = false; pub_srv.cancel(); } else { // we now have a host, publish doPublish(); } } } signals: void published(); void error(JDnsSharedRequest::Error e); private: friend class JDnsPublishExtra; static QList makeTxtList(const QMap &attributes) { QList out; QMapIterator it(attributes); while(it.hasNext()) { it.next(); out += it.key().toLatin1() + '=' + it.value(); } if(out.isEmpty()) out += QByteArray(); return out; } void doPublish() { // SRV QJDns::Record rec; rec.type = QJDns::Srv; rec.owner = fullname; rec.ttl = 120; rec.haveKnown = true; rec.name = host; rec.port = port; rec.priority = 0; rec.weight = 0; pub_srv.publish(QJDns::Unique, rec); // if we're just republishing SRV after losing/regaining // our hostname, then TXT is already published if(!have_txt) doPublishTxt(); // publish extra records as needed foreach(JDnsPublishExtra *extra, extraList) { if(!extra->have) doPublishExtra(extra); } } void doPublishTxt() { // TXT QJDns::Record rec; rec.type = QJDns::Txt; rec.owner = fullname; rec.ttl = 4500; rec.haveKnown = true; rec.texts = attribs; if(!have_txt) pub_txt.publish(QJDns::Unique, rec); else pub_txt.publishUpdate(rec); } void tryDone() { if(have_srv && have_txt) { // PTR QJDns::Record rec; rec.type = QJDns::Ptr; rec.owner = type + ".local."; rec.ttl = 4500; rec.haveKnown = true; rec.name = fullname; pub_ptr.publish(QJDns::Shared, rec); } } void cleanup() { foreach(JDnsPublishExtra *extra, extraList) cleanupExtra(extra); qDeleteAll(extraList); extraList.clear(); have_srv = false; have_txt = false; have_ptr = false; pub_srv.cancel(); pub_txt.cancel(); pub_ptr.cancel(); } void publishExtra(JDnsPublishExtra *extra) { Q_ASSERT(!extraList.contains(extra)); connect(&extra->pub, SIGNAL(resultsReady()), SLOT(pub_extra_ready())); extraList += extra; // defer publishing until SRV is ready if(!have_srv) return; doPublishExtra(extra); } void publishExtraUpdate(JDnsPublishExtra *extra) { if(!extra->have) { extra->need_update = true; return; } if(!have_srv) { extra->have = false; extra->pub.cancel(); return; } doPublishExtra(extra); } void unpublishExtra(JDnsPublishExtra *extra) { extraList.remove(extra); } void doPublishExtra(JDnsPublishExtra *extra) { if(!extra->have) extra->pub.publish(QJDns::Unique, extra->rec); else extra->pub.publishUpdate(extra->rec); } void cleanupExtra(JDnsPublishExtra *extra) { extra->pub.cancel(); extra->disconnect(this); extra->started = false; extra->have = false; } private slots: void pub_srv_ready() { if(pub_srv.success()) { have_srv = true; tryDone(); } else { JDnsSharedRequest::Error e = pub_srv.error(); cleanup(); emit error(e); } } void pub_txt_ready() { if(pub_txt.success()) { have_txt = true; if(need_update_txt) { need_update_txt = false; doPublishTxt(); } tryDone(); } else { JDnsSharedRequest::Error e = pub_txt.error(); cleanup(); emit error(e); } } void pub_ptr_ready() { if(pub_ptr.success()) { have_ptr = true; emit published(); } else { JDnsSharedRequest::Error e = pub_ptr.error(); cleanup(); emit error(e); } } void pub_extra_ready() { JDnsSharedRequest *req = (JDnsSharedRequest *)sender(); JDnsPublishExtra *extra = 0; foreach(JDnsPublishExtra *e, extraList) { if(&e->pub == req) { extra = e; break; } } Q_ASSERT(extra); if(extra->pub.success()) { extra->have = true; if(extra->need_update) { extra->need_update = false; doPublishExtra(extra); } emit extra->published(); } else { JDnsSharedRequest::Error e = extra->pub.error(); cleanupExtra(extra); emit extra->error(e); } } }; JDnsPublishExtra::JDnsPublishExtra(JDnsPublish *_jdnsPub) : QObject(_jdnsPub), jdnsPub(_jdnsPub), started(false), pub(_jdnsPub->jdns, this) { } JDnsPublishExtra::~JDnsPublishExtra() { if(started) jdnsPub->unpublishExtra(this); } void JDnsPublishExtra::start(const QJDns::Record &_rec) { rec = _rec; started = true; have = false; need_update = false; jdnsPub->publishExtra(this); } void JDnsPublishExtra::update(const QJDns::Record &_rec) { rec = _rec; jdnsPub->publishExtraUpdate(this); } //---------------------------------------------------------------------------- // JDnsServiceProvider //---------------------------------------------------------------------------- class BrowseItem { public: const int id; JDnsBrowse * const browse; ObjectSession *sess; BrowseItem(int _id, JDnsBrowse *_browse) : id(_id), browse(_browse), sess(0) { } ~BrowseItem() { delete browse; delete sess; } }; class BrowseItemList { private: QSet items; QHash indexById; QHash indexByBrowse; IdManager idman; public: ~BrowseItemList() { qDeleteAll(items); } int reserveId() { return idman.reserveId(); } void insert(BrowseItem *item) { items.insert(item); indexById.insert(item->id, item); indexByBrowse.insert(item->browse, item); } void remove(BrowseItem *item) { indexById.remove(item->id); indexByBrowse.remove(item->browse); items.remove(item); if(item->id != -1) idman.releaseId(item->id); delete item; } BrowseItem *itemById(int id) const { return indexById.value(id); } BrowseItem *itemByBrowse(JDnsBrowse *browse) const { return indexByBrowse.value(browse); } }; class ResolveItem { public: const int id; JDnsServiceResolve * const resolve; ObjectSession *sess; ResolveItem(int _id, JDnsServiceResolve *_resolve) : id(_id), resolve(_resolve), sess(0) { } ~ResolveItem() { delete resolve; delete sess; } }; class ResolveItemList { private: QSet items; QHash indexById; QHash indexByResolve; IdManager idman; public: ~ResolveItemList() { qDeleteAll(items); } int reserveId() { return idman.reserveId(); } void insert(ResolveItem *item) { items.insert(item); indexById.insert(item->id, item); indexByResolve.insert(item->resolve, item); } void remove(ResolveItem *item) { indexById.remove(item->id); indexByResolve.remove(item->resolve); items.remove(item); if(item->id != -1) idman.releaseId(item->id); delete item; } ResolveItem *itemById(int id) const { return indexById.value(id); } ResolveItem *itemByResolve(JDnsServiceResolve *resolve) const { return indexByResolve.value(resolve); } }; class PublishItem { public: const int id; JDnsPublish * const publish; ObjectSession *sess; PublishItem(int _id, JDnsPublish *_publish) : id(_id), publish(_publish), sess(0) { } ~PublishItem() { delete publish; delete sess; } }; class PublishItemList { public: QSet items; private: QHash indexById; QHash indexByPublish; IdManager idman; public: ~PublishItemList() { qDeleteAll(items); } int reserveId() { return idman.reserveId(); } void insert(PublishItem *item) { items.insert(item); indexById.insert(item->id, item); indexByPublish.insert(item->publish, item); } void remove(PublishItem *item) { indexById.remove(item->id); indexByPublish.remove(item->publish); items.remove(item); if(item->id != -1) idman.releaseId(item->id); delete item; } PublishItem *itemById(int id) const { return indexById.value(id); } PublishItem *itemByPublish(JDnsPublish *publish) const { return indexByPublish.value(publish); } }; class PublishExtraItem { public: const int id; JDnsPublishExtra * const publish; ObjectSession *sess; PublishExtraItem(int _id, JDnsPublishExtra *_publish) : id(_id), publish(_publish), sess(0) { } ~PublishExtraItem() { delete publish; delete sess; } }; class PublishExtraItemList { public: QSet items; private: QHash indexById; QHash indexByPublish; IdManager idman; public: ~PublishExtraItemList() { qDeleteAll(items); } void clear() { qDeleteAll(items); items.clear(); indexById.clear(); indexByPublish.clear(); idman.clear(); } int reserveId() { return idman.reserveId(); } void insert(PublishExtraItem *item) { items.insert(item); indexById.insert(item->id, item); indexByPublish.insert(item->publish, item); } void remove(PublishExtraItem *item) { indexById.remove(item->id); indexByPublish.remove(item->publish); items.remove(item); if(item->id != -1) idman.releaseId(item->id); delete item; } PublishExtraItem *itemById(int id) const { return indexById.value(id); } PublishExtraItem *itemByPublish(JDnsPublishExtra *publish) const { return indexByPublish.value(publish); } }; class JDnsServiceProvider : public ServiceProvider { Q_OBJECT public: JDnsGlobal *global; // browse BrowseItemList browseItemList; QHash items; // resolve ResolveItemList resolveItemList; // publish JDnsPublishAddresses *pub_addresses; QByteArray localHost; PublishItemList publishItemList; PublishExtraItemList publishExtraItemList; static JDnsServiceProvider *create(JDnsGlobal *global, QObject *parent = 0) { return new JDnsServiceProvider(global, parent); } JDnsServiceProvider(JDnsGlobal *_global, QObject *parent = 0) : ServiceProvider(parent), pub_addresses(0) { global = _global; connect(global, SIGNAL(interfacesChanged()), SLOT(interfacesChanged())); } ~JDnsServiceProvider() { // make sure extra items are deleted before normal ones publishExtraItemList.clear(); } virtual int browse_start(const QString &_type, const QString &_domain) { QString domain; if(_domain.isEmpty() || _domain == ".") domain = "local."; else domain = _domain; if(domain[domain.length() - 1] != '.') domain += '.'; Q_ASSERT(domain.length() >= 2 && domain[domain.length() - 1] == '.'); int id = browseItemList.reserveId(); // no support for non-local domains if(domain != "local.") { BrowseItem *i = new BrowseItem(id, 0); i->sess = new ObjectSession(this); browseItemList.insert(i); i->sess->defer(this, "do_browse_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceBrowser::Error, ServiceBrowser::ErrorNoWide)); return i->id; } if(!global->ensure_mul()) { BrowseItem *i = new BrowseItem(id, 0); i->sess = new ObjectSession(this); browseItemList.insert(i); i->sess->defer(this, "do_browse_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceBrowser::Error, ServiceBrowser::ErrorNoLocal)); return i->id; } QByteArray type = _type.toUtf8(); if(!validServiceType(type)) { BrowseItem *i = new BrowseItem(id, 0); i->sess = new ObjectSession(this); browseItemList.insert(i); i->sess->defer(this, "do_browse_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceBrowser::Error, ServiceBrowser::ErrorGeneric)); return i->id; } BrowseItem *i = new BrowseItem(id, new JDnsBrowse(global->mul, this)); connect(i->browse, SIGNAL(available(const QByteArray &)), SLOT(jb_available(const QByteArray &))); connect(i->browse, SIGNAL(unavailable(const QByteArray &)), SLOT(jb_unavailable(const QByteArray &))); browseItemList.insert(i); i->browse->start(type); return i->id; } virtual void browse_stop(int id) { BrowseItem *i = browseItemList.itemById(id); Q_ASSERT(i); browseItemList.remove(i); } virtual int resolve_start(const QByteArray &name) { int id = resolveItemList.reserveId(); if(!global->ensure_mul()) { ResolveItem *i = new ResolveItem(id, 0); i->sess = new ObjectSession(this); resolveItemList.insert(i); i->sess->defer(this, "do_resolve_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceResolver::Error, ServiceResolver::ErrorNoLocal)); return i->id; } ResolveItem *i = new ResolveItem(id, new JDnsServiceResolve(global->mul, this)); connect(i->resolve, SIGNAL(finished()), SLOT(jr_finished())); connect(i->resolve, SIGNAL(error(JDnsSharedRequest::Error)), SLOT(jr_error(JDnsSharedRequest::Error))); resolveItemList.insert(i); i->resolve->start(name); return i->id; } virtual void resolve_stop(int id) { ResolveItem *i = resolveItemList.itemById(id); Q_ASSERT(i); resolveItemList.remove(i); } virtual int publish_start(const QString &instance, const QString &_type, int port, const QMap &attributes) { int id = publishItemList.reserveId(); if(!global->ensure_mul()) { PublishItem *i = new PublishItem(id, 0); i->sess = new ObjectSession(this); publishItemList.insert(i); i->sess->defer(this, "do_publish_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceLocalPublisher::Error, ServiceLocalPublisher::ErrorNoLocal)); return i->id; } QByteArray type = _type.toUtf8(); if(!validServiceType(type)) { PublishItem *i = new PublishItem(id, 0); i->sess = new ObjectSession(this); publishItemList.insert(i); i->sess->defer(this, "do_publish_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceLocalPublisher::Error, ServiceLocalPublisher::ErrorGeneric)); return i->id; } // make sure A/AAAA records are published if(!pub_addresses) { pub_addresses = new JDnsPublishAddresses(global->mul, this); connect(pub_addresses, SIGNAL(hostName(const QByteArray &)), SLOT(pub_addresses_hostName(const QByteArray &))); pub_addresses->setUseIPv6(global->haveMulticast6()); pub_addresses->setUseIPv4(global->haveMulticast4()); pub_addresses->start(); } // it's okay to attempt to publish even if pub_addresses // hasn't succeeded yet. JDnsPublish is smart enough to // defer the operation until a host is acquired. PublishItem *i = new PublishItem(id, new JDnsPublish(global->mul, this)); connect(i->publish, SIGNAL(published()), SLOT(jp_published())); connect(i->publish, SIGNAL(error(JDnsSharedRequest::Error)), SLOT(jp_error(JDnsSharedRequest::Error))); publishItemList.insert(i); i->publish->start(instance, type, localHost, port, attributes); return i->id; } virtual void publish_update(int id, const QMap &attributes) { PublishItem *i = publishItemList.itemById(id); Q_ASSERT(i); // if we already have an error queued, do nothing if(i->sess->isDeferred(this, "do_publish_error")) return; i->publish->update(attributes); } virtual void publish_stop(int id) { PublishItem *i = publishItemList.itemById(id); Q_ASSERT(i); cleanupExtra(i); publishItemList.remove(i); } virtual int publish_extra_start(int pub_id, const NameRecord &name) { PublishItem *pi = publishItemList.itemById(pub_id); Q_ASSERT(pi); int id = publishItemList.reserveId(); QJDns::Record rec = exportJDNSRecord(name); if(rec.type == -1) { PublishExtraItem *i = new PublishExtraItem(id, 0); i->sess = new ObjectSession(this); publishExtraItemList.insert(i); i->sess->defer(this, "do_publish_extra_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceLocalPublisher::Error, ServiceLocalPublisher::ErrorGeneric)); return i->id; } // fill in owner if necessary if(rec.owner.isEmpty()) rec.owner = pi->publish->fullname; // fill in the ttl if necessary if(rec.ttl == 0) rec.ttl = 4500; PublishExtraItem *i = new PublishExtraItem(id, new JDnsPublishExtra(pi->publish)); connect(i->publish, SIGNAL(published()), SLOT(jpe_published())); connect(i->publish, SIGNAL(error(JDnsSharedRequest::Error)), SLOT(jpe_error(JDnsSharedRequest::Error))); publishExtraItemList.insert(i); i->publish->start(rec); return i->id; } virtual void publish_extra_update(int id, const NameRecord &name) { PublishExtraItem *i = publishExtraItemList.itemById(id); Q_ASSERT(i); // if we already have an error queued, do nothing if(i->sess->isDeferred(this, "do_publish_extra_error")) return; QJDns::Record rec = exportJDNSRecord(name); if(rec.type == -1) { i->sess = new ObjectSession(this); i->sess->defer(this, "do_publish_extra_error", Q_ARG(int, i->id), Q_ARG(XMPP::ServiceLocalPublisher::Error, ServiceLocalPublisher::ErrorGeneric)); return; } // fill in owner if necessary if(rec.owner.isEmpty()) rec.owner = static_cast(i->publish->parent())->fullname; // fill in the ttl if necessary if(rec.ttl == 0) rec.ttl = 4500; i->publish->update(rec); } virtual void publish_extra_stop(int id) { PublishExtraItem *i = publishExtraItemList.itemById(id); Q_ASSERT(i); publishExtraItemList.remove(i); } private: void cleanupExtra(PublishItem *pi) { // remove all extra publishes associated with this publish. // the association can be checked via QObject parenting. QSet remove; foreach(PublishExtraItem *i, publishExtraItemList.items) { if(static_cast(i->publish->parent()) == pi->publish) remove += i; } foreach(PublishExtraItem *i, remove) publishExtraItemList.remove(i); } private slots: void interfacesChanged() { if(pub_addresses) { pub_addresses->setUseIPv6(global->haveMulticast6()); pub_addresses->setUseIPv4(global->haveMulticast4()); } } void jb_available(const QByteArray &instance) { JDnsBrowse *jb = (JDnsBrowse *)sender(); BrowseItem *i = browseItemList.itemByBrowse(jb); Q_ASSERT(i); QByteArray name = instance + '.' + jb->typeAndDomain; ServiceInstance si(QString::fromLatin1(instance), QString::fromLatin1(jb->type), "local.", QMap()); items.insert(name, si); emit browse_instanceAvailable(i->id, si); } void jb_unavailable(const QByteArray &instance) { JDnsBrowse *jb = (JDnsBrowse *)sender(); BrowseItem *i = browseItemList.itemByBrowse(jb); Q_ASSERT(i); QByteArray name = instance + '.' + jb->typeAndDomain; Q_ASSERT(items.contains(name)); ServiceInstance si = items.value(name); items.remove(name); emit browse_instanceUnavailable(i->id, si); } void do_browse_error(int id, XMPP::ServiceBrowser::Error e) { BrowseItem *i = browseItemList.itemById(id); Q_ASSERT(i); browseItemList.remove(i); emit browse_error(id, e); } void jr_finished() { JDnsServiceResolve *jr = (JDnsServiceResolve *)sender(); ResolveItem *i = resolveItemList.itemByResolve(jr); Q_ASSERT(i); // parse TXT list into attribute map QMap attribs; for(int n = 0; n < jr->attribs.count(); ++n) { const QByteArray &a = jr->attribs[n]; QString key; QByteArray value; int x = a.indexOf('='); if(x != -1) { key = QString::fromLatin1(a.mid(0, x)); value = a.mid(x + 1); } else { key = QString::fromLatin1(a); } attribs.insert(key, value); } // one of these must be true Q_ASSERT(jr->have4 || jr->have6); QList results; if(jr->have6) { ResolveResult r; r.attributes = attribs; r.address = jr->addr6; r.port = jr->port; r.hostName = jr->host; results += r; } if(jr->have4) { ResolveResult r; r.attributes = attribs; r.address = jr->addr4; r.port = jr->port; r.hostName = jr->host; results += r; } int id = i->id; resolveItemList.remove(i); emit resolve_resultsReady(id, results); } void jr_error(JDnsSharedRequest::Error e) { JDnsServiceResolve *jr = (JDnsServiceResolve *)sender(); ResolveItem *i = resolveItemList.itemByResolve(jr); Q_ASSERT(i); ServiceResolver::Error err; if(e == JDnsSharedRequest::ErrorTimeout) err = ServiceResolver::ErrorTimeout; else err = ServiceResolver::ErrorGeneric; int id = i->id; resolveItemList.remove(i); emit resolve_error(id, err); } void do_resolve_error(int id, XMPP::ServiceResolver::Error e) { ResolveItem *i = resolveItemList.itemById(id); Q_ASSERT(i); resolveItemList.remove(i); emit resolve_error(id, e); } void pub_addresses_hostName(const QByteArray &name) { // tell all active publishes about the change foreach(PublishItem *item, publishItemList.items) item->publish->hostChanged(name); } void jp_published() { JDnsPublish *jp = (JDnsPublish *)sender(); PublishItem *i = publishItemList.itemByPublish(jp); Q_ASSERT(i); emit publish_published(i->id); } void jp_error(JDnsSharedRequest::Error e) { JDnsPublish *jp = (JDnsPublish *)sender(); PublishItem *i = publishItemList.itemByPublish(jp); Q_ASSERT(i); ServiceLocalPublisher::Error err; if(e == JDnsSharedRequest::ErrorConflict) err = ServiceLocalPublisher::ErrorConflict; else err = ServiceLocalPublisher::ErrorGeneric; int id = i->id; cleanupExtra(i); publishItemList.remove(i); emit publish_error(id, err); } void do_publish_error(int id, XMPP::ServiceLocalPublisher::Error e) { PublishItem *i = publishItemList.itemById(id); Q_ASSERT(i); cleanupExtra(i); publishItemList.remove(i); emit publish_error(id, e); } void jpe_published() { JDnsPublishExtra *jp = (JDnsPublishExtra *)sender(); PublishExtraItem *i = publishExtraItemList.itemByPublish(jp); Q_ASSERT(i); emit publish_extra_published(i->id); } void jpe_error(JDnsSharedRequest::Error e) { JDnsPublishExtra *jp = (JDnsPublishExtra *)sender(); PublishExtraItem *i = publishExtraItemList.itemByPublish(jp); Q_ASSERT(i); ServiceLocalPublisher::Error err; if(e == JDnsSharedRequest::ErrorConflict) err = ServiceLocalPublisher::ErrorConflict; else err = ServiceLocalPublisher::ErrorGeneric; int id = i->id; publishExtraItemList.remove(i); emit publish_extra_error(id, err); } void do_publish_extra_error(int id, XMPP::ServiceLocalPublisher::Error e) { PublishExtraItem *i = publishExtraItemList.itemById(id); Q_ASSERT(i); publishExtraItemList.remove(i); emit publish_extra_error(id, e); } }; //---------------------------------------------------------------------------- // JDnsProvider //---------------------------------------------------------------------------- class JDnsProvider : public IrisNetProvider { Q_OBJECT Q_INTERFACES(XMPP::IrisNetProvider) public: JDnsGlobal *global; JDnsProvider() { global = 0; } ~JDnsProvider() { delete global; } void ensure_global() { if(!global) global = new JDnsGlobal; } virtual NameProvider *createNameProviderInternet() { ensure_global(); return JDnsNameProvider::create(global, JDnsNameProvider::Internet); } virtual NameProvider *createNameProviderLocal() { ensure_global(); return JDnsNameProvider::create(global, JDnsNameProvider::Local); } virtual ServiceProvider *createServiceProvider() { ensure_global(); return JDnsServiceProvider::create(global); } }; IrisNetProvider *irisnet_createJDnsProvider() { return new JDnsProvider; } } #include "netnames_jdns.moc" psi-0.14/iris/src/irisnet/corelib/netinterface.cpp0000644000175000017500000002146711305557616020362 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "netinterface.h" #include "irisnetplugin.h" #include "irisnetglobal_p.h" #include #include #include namespace XMPP { //---------------------------------------------------------------------------- // NetTracker //---------------------------------------------------------------------------- class NetTracker : public QObject { Q_OBJECT public: QList getInterfaces() { QMutexLocker locker(&m); return info; } NetTracker() { QList list = irisNetProviders(); c = 0; foreach(IrisNetProvider* p, list) { c = p->createNetInterfaceProvider(); if(c) break; } Q_ASSERT(c); // we have built-in support, so this should never fail connect(c, SIGNAL(updated()), SLOT(c_updated())); c->start(); info = filterList(c->interfaces()); } ~NetTracker() { QMutexLocker locker(&m); delete c; } signals: void updated(); private: static QList filterList(const QList &in) { QList out; for(int n = 0; n < in.count(); ++n) { if(!in[n].isLoopback) out += in[n]; } return out; } private slots: void c_updated() { { QMutexLocker locker(&m); info = filterList(c->interfaces()); } emit updated(); } private: // this are all protected by m NetInterfaceProvider *c; QMutex m; QList info; }; // Global because static getRef needs this too. Q_GLOBAL_STATIC(QMutex, nettracker_mutex) class NetTrackerThread : public QThread { Q_OBJECT public: /** Get a reference to the NetTracker singleton. Calls to getInterfaces will immediately give valid results */ static NetTrackerThread* getRef() { QMutexLocker locker(nettracker_mutex()); if (!self) { self = new NetTrackerThread(); } self->refs++; return self; } /** Release reference. */ void releaseRef() { QMutexLocker locker(nettracker_mutex()); Q_ASSERT(refs > 0); refs--; if (refs <= 0) { exit(0); wait(); delete this; self = 0; } } QList getInterfaces() { return nettracker->getInterfaces(); } ~NetTrackerThread() { // locked from caller } signals: void updated(); private: NetTrackerThread() { // locked from caller refs = 0; moveToThread(QCoreApplication::instance()->thread()); startMutex = new QMutex(); { QMutexLocker startLocker(startMutex); start(); startCond.wait(startMutex); // wait for thread startup finished } delete startMutex; startMutex = 0; } void run() { { QMutexLocker locker(startMutex); nettracker = new NetTracker(); connect(nettracker, SIGNAL(updated()), SIGNAL(updated()), Qt::DirectConnection); startCond.wakeOne(); // we're ready to serve. } exec(); delete nettracker; nettracker = 0; } private: QWaitCondition startCond; QMutex *startMutex; // these are all protected by global nettracker_mutex. int refs; static NetTrackerThread *self; NetTracker *nettracker; }; NetTrackerThread *NetTrackerThread::self = 0; //---------------------------------------------------------------------------- // NetInterface //---------------------------------------------------------------------------- class NetInterfacePrivate : public QObject { Q_OBJECT public: friend class NetInterfaceManagerPrivate; NetInterface *q; QPointer man; bool valid; QString id, name; QList addrs; QHostAddress gw; NetInterfacePrivate(NetInterface *_q) : QObject(_q), q(_q) { valid = false; } void doUnavailable() { if (!valid) return; valid = false; if (man.isNull()) return; man->unreg(q); emit q->unavailable(); } }; NetInterface::NetInterface(const QString &id, NetInterfaceManager *manager) : QObject(manager) { d = new NetInterfacePrivate(this); d->man = manager; NetInterfaceProvider::Info *info = (NetInterfaceProvider::Info *)d->man->reg(id, this); if (info) { d->valid = true; d->id = info->id; d->name = info->name; d->addrs = info->addresses; d->gw = info->gateway; delete info; } } NetInterface::~NetInterface() { if (d->valid && !d->man.isNull()) d->man->unreg(this); delete d; } bool NetInterface::isValid() const { return d->valid && !d->man.isNull(); } QString NetInterface::id() const { return d->id; } QString NetInterface::name() const { return d->name; } QList NetInterface::addresses() const { return d->addrs; } QHostAddress NetInterface::gateway() const { return d->gw; } //---------------------------------------------------------------------------- // NetInterfaceManager //---------------------------------------------------------------------------- class NetInterfaceManagerPrivate : public QObject { Q_OBJECT public: NetInterfaceManager *q; QList info; QList listeners; NetTrackerThread *tracker; bool pending; NetInterfaceManagerPrivate(NetInterfaceManager *_q) : QObject(_q), q(_q) { tracker = NetTrackerThread::getRef(); pending = false; connect(tracker, SIGNAL(updated()), SLOT(tracker_updated())); } ~NetInterfaceManagerPrivate() { tracker->releaseRef(); tracker = 0; } static int lookup(const QList &list, const QString &id) { for(int n = 0; n < list.count(); ++n) { if(list[n].id == id) return n; } return -1; } static bool sameContent(const NetInterfaceProvider::Info &a, const NetInterfaceProvider::Info &b) { // assume ids are the same already return (a.name == b.name && a.isLoopback == b.isLoopback && a.addresses == b.addresses && a.gateway == b.gateway); } void do_update() { // grab the latest info QList newinfo = tracker->getInterfaces(); QStringList here_ids, gone_ids; // removed / changed for(int n = 0; n < info.count(); ++n) { int i = lookup(newinfo, info[n].id); // id is still here if(i != -1) { // content changed? if(!sameContent(info[n], newinfo[i])) { gone_ids += info[n].id; here_ids += info[n].id; } } else { // id is gone gone_ids += info[n].id; } } // added for(int n = 0; n < newinfo.count(); ++n) { int i = lookup(info, newinfo[n].id); if(i == -1) here_ids += newinfo[n].id; } info = newinfo; // announce gone for(int n = 0; n < gone_ids.count(); ++n) { // work on a copy, just in case the list changes. // it is important to make the copy here, and not // outside the outer loop, in case the items // get deleted QList list = listeners; for(int i = 0; i < list.count(); ++i) { if(list[i]->d->id == gone_ids[n]) { list[i]->d->doUnavailable(); } } } // announce here for(int n = 0; n < here_ids.count(); ++n) emit q->interfaceAvailable(here_ids[n]); } public slots: void tracker_updated() { // collapse multiple updates by queuing up an update if there isn't any queued yet. if(!pending) { QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); pending = true; } } void update() { pending = false; do_update(); } }; NetInterfaceManager::NetInterfaceManager(QObject *parent) :QObject(parent) { d = new NetInterfaceManagerPrivate(this); } NetInterfaceManager::~NetInterfaceManager() { delete d; } QStringList NetInterfaceManager::interfaces() const { d->info = d->tracker->getInterfaces(); QStringList out; for(int n = 0; n < d->info.count(); ++n) { out += d->info[n].id; } return out; } QString NetInterfaceManager::interfaceForAddress(const QHostAddress &a) { NetInterfaceManager netman; QStringList list = netman.interfaces(); for(int n = 0; n < list.count(); ++n) { NetInterface iface(list[n], &netman); if(iface.addresses().contains(a)) return list[n]; } return QString(); } void *NetInterfaceManager::reg(const QString &id, NetInterface *i) { for(int n = 0; n < d->info.count(); ++n) { if(d->info[n].id == id) { d->listeners += i; return new NetInterfaceProvider::Info(d->info[n]); } } return 0; } void NetInterfaceManager::unreg(NetInterface *i) { d->listeners.removeAll(i); } } #include "netinterface.moc" psi-0.14/iris/src/irisnet/corelib/netnames.cpp0000644000175000017500000005336711305557616017531 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "netnames.h" //#include #include "irisnetplugin.h" #include "irisnetglobal_p.h" namespace XMPP { //---------------------------------------------------------------------------- // NameRecord //---------------------------------------------------------------------------- class NameRecord::Private : public QSharedData { public: QByteArray owner; NameRecord::Type type; int ttl; QHostAddress address; QByteArray name; int priority, weight, port; QList texts; QByteArray cpu, os; QByteArray rawData; }; #define ENSURE_D { if(!d) d = new Private; } NameRecord::NameRecord() { d = 0; } NameRecord::NameRecord(const QByteArray &owner, int ttl) { d = 0; setOwner(owner); setTtl(ttl); } NameRecord::NameRecord(const NameRecord &from) { d = 0; *this = from; } NameRecord::~NameRecord() { } NameRecord & NameRecord::operator=(const NameRecord &from) { d = from.d; return *this; } bool NameRecord::isNull() const { return (d ? false : true); } QByteArray NameRecord::owner() const { Q_ASSERT(d); return d->owner; } int NameRecord::ttl() const { Q_ASSERT(d); return d->ttl; } NameRecord::Type NameRecord::type() const { Q_ASSERT(d); return d->type; } QHostAddress NameRecord::address() const { Q_ASSERT(d); return d->address; } QByteArray NameRecord::name() const { Q_ASSERT(d); return d->name; } int NameRecord::priority() const { Q_ASSERT(d); return d->priority; } int NameRecord::weight() const { Q_ASSERT(d); return d->weight; } int NameRecord::port() const { Q_ASSERT(d); return d->port; } QList NameRecord::texts() const { Q_ASSERT(d); return d->texts; } QByteArray NameRecord::cpu() const { Q_ASSERT(d); return d->cpu; } QByteArray NameRecord::os() const { Q_ASSERT(d); return d->os; } QByteArray NameRecord::rawData() const { Q_ASSERT(d); return d->rawData; } void NameRecord::setOwner(const QByteArray &name) { ENSURE_D d->owner = name; } void NameRecord::setTtl(int seconds) { ENSURE_D d->ttl = seconds; } void NameRecord::setAddress(const QHostAddress &a) { ENSURE_D if(a.protocol() == QAbstractSocket::IPv6Protocol) d->type = NameRecord::Aaaa; else d->type = NameRecord::A; d->address = a; } void NameRecord::setMx(const QByteArray &name, int priority) { ENSURE_D d->type = NameRecord::Mx; d->name = name; d->priority = priority; } void NameRecord::setSrv(const QByteArray &name, int port, int priority, int weight) { ENSURE_D d->type = NameRecord::Srv; d->name = name; d->port = port; d->priority = priority; d->weight = weight; } void NameRecord::setCname(const QByteArray &name) { ENSURE_D d->type = NameRecord::Cname; d->name = name; } void NameRecord::setPtr(const QByteArray &name) { ENSURE_D d->type = NameRecord::Ptr; d->name = name; } void NameRecord::setTxt(const QList &texts) { ENSURE_D d->type = NameRecord::Txt; d->texts = texts; } void NameRecord::setHinfo(const QByteArray &cpu, const QByteArray &os) { ENSURE_D d->type = NameRecord::Hinfo; d->cpu = cpu; d->os = os; } void NameRecord::setNs(const QByteArray &name) { ENSURE_D d->type = NameRecord::Ns; d->name = name; } void NameRecord::setNull(const QByteArray &rawData) { ENSURE_D d->type = NameRecord::Null; d->rawData = rawData; } //---------------------------------------------------------------------------- // ServiceInstance //---------------------------------------------------------------------------- class ServiceInstance::Private : public QSharedData { public: QString instance, type, domain; QMap attribs; QByteArray name; }; ServiceInstance::ServiceInstance() { d = new Private; } ServiceInstance::ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap &attribs) { d = new Private; d->instance = instance; d->type = type; d->domain = domain; d->attribs = attribs; // FIXME: escape the items d->name = instance.toLatin1() + '.' + type.toLatin1() + '.' + domain.toLatin1(); } ServiceInstance::ServiceInstance(const ServiceInstance &from) { d = 0; *this = from; } ServiceInstance::~ServiceInstance() { } ServiceInstance & ServiceInstance::operator=(const ServiceInstance &from) { d = from.d; return *this; } QString ServiceInstance::instance() const { return d->instance; } QString ServiceInstance::type() const { return d->type; } QString ServiceInstance::domain() const { return d->domain; } QMap ServiceInstance::attributes() const { return d->attribs; } QByteArray ServiceInstance::name() const { return d->name; } //---------------------------------------------------------------------------- // NameManager //---------------------------------------------------------------------------- class NameManager; Q_GLOBAL_STATIC(QMutex, nman_mutex) static NameManager *g_nman = 0; class NameResolver::Private { public: NameResolver *q; int type; bool longLived; int id; Private(NameResolver *_q) : q(_q) { } }; class ServiceBrowser::Private { public: ServiceBrowser *q; int id; Private(ServiceBrowser *_q) : q(_q) { } }; class ServiceResolver::Private : public QObject { Q_OBJECT public: ServiceResolver *q; int id; int mode; NameResolver dns; int port; class Server { public: QByteArray host; int port; int priority; int weight; }; QList servers; QList addrs; Private(ServiceResolver *_q) : q(_q) { mode = 3; connect(&dns, SIGNAL(resultsReady(const QList &)), SLOT(dns_resultsReady(const QList &))); connect(&dns, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error))); } void tryNext() { if(mode == 3) { QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } if(mode == 2) { if(!addrs.isEmpty()) { QHostAddress addr = addrs.takeFirst(); QMetaObject::invokeMethod(q, "resultsReady", Qt::QueuedConnection, Q_ARG(QHostAddress, addr), Q_ARG(int, port)); return; } if(servers.isEmpty()) { QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); return; } Server serv = servers.takeFirst(); port = serv.port; dns.start(serv.host, NameRecord::A); // TODO: ipv6! } else { if(addrs.isEmpty()) { QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); return; } QHostAddress addr = addrs.takeFirst(); QMetaObject::invokeMethod(q, "resultsReady", Qt::QueuedConnection, Q_ARG(QHostAddress, addr), Q_ARG(int, port)); } } private slots: void dns_resultsReady(const QList &results) { if(mode == 0) { mode = 2; servers.clear(); for(int n = 0; n < results.count(); ++n) { Server serv; serv.host = results[n].name(); serv.port = results[n].port(); serv.priority = results[n].priority(); serv.weight = results[n].weight(); servers += serv; } tryNext(); } else if(mode == 1) { addrs.clear(); // TODO: don't forget about ipv6 for(int n = 0; n < results.count(); ++n) addrs += results[n].address(); tryNext(); } else { QList tmp; for(int n = 0; n < results.count(); ++n) tmp += results[n].address(); addrs += tmp; tryNext(); } } void dns_error(XMPP::NameResolver::Error) { if(mode == 0 || mode == 1) emit q->error(); else tryNext(); // FIXME: probably shouldn't share this } }; class ServiceLocalPublisher::Private { public: ServiceLocalPublisher *q; int id; Private(ServiceLocalPublisher *_q) : q(_q) { } }; class NameManager : public QObject { Q_OBJECT public: NameProvider *p_net, *p_local; ServiceProvider *p_serv; QHash res_instances; QHash res_sub_instances; QHash br_instances; QHash sres_instances; QHash slp_instances; NameManager(QObject *parent = 0) : QObject(parent) { p_net = 0; p_local = 0; p_serv = 0; } ~NameManager() { delete p_net; delete p_local; delete p_serv; } static NameManager *instance() { QMutexLocker locker(nman_mutex()); if(!g_nman) { g_nman = new NameManager; irisNetAddPostRoutine(NetNames::cleanup); } return g_nman; } static void cleanup() { delete g_nman; g_nman = 0; } void resolve_start(NameResolver::Private *np, const QByteArray &name, int qType, bool longLived) { QMutexLocker locker(nman_mutex()); np->type = qType; np->longLived = longLived; if(!p_net) { NameProvider *c = 0; QList list = irisNetProviders(); for(int n = 0; n < list.count(); ++n) { IrisNetProvider *p = list[n]; c = p->createNameProviderInternet(); if(c) break; } Q_ASSERT(c); // we have built-in support, so this should never fail p_net = c; // use queued connections qRegisterMetaType< QList >("QList"); qRegisterMetaType("XMPP::NameResolver::Error"); connect(p_net, SIGNAL(resolve_resultsReady(int, const QList &)), SLOT(provider_resolve_resultsReady(int, const QList &))); connect(p_net, SIGNAL(resolve_error(int, XMPP::NameResolver::Error)), SLOT(provider_resolve_error(int, XMPP::NameResolver::Error))); connect(p_net, SIGNAL(resolve_useLocal(int, const QByteArray &)), SLOT(provider_resolve_useLocal(int, const QByteArray &))); } np->id = p_net->resolve_start(name, qType, longLived); //printf("assigning %d to %p\n", req_id, np); res_instances.insert(np->id, np); } void resolve_stop(NameResolver::Private *np) { // FIXME: stop sub instances? p_net->resolve_stop(np->id); resolve_cleanup(np); } void resolve_cleanup(NameResolver::Private *np) { res_instances.remove(np->id); NameResolver *q = np->q; delete q->d; q->d = 0; } void browse_start(ServiceBrowser::Private *np, const QString &type, const QString &domain) { QMutexLocker locker(nman_mutex()); if(!p_serv) { ServiceProvider *c = 0; QList list = irisNetProviders(); for(int n = 0; n < list.count(); ++n) { IrisNetProvider *p = list[n]; c = p->createServiceProvider(); if(c) break; } Q_ASSERT(c); // we have built-in support, so this should never fail p_serv = c; // use queued connections qRegisterMetaType("XMPP::ServiceInstance"); qRegisterMetaType("XMPP::ServiceBrowser::Error"); connect(p_serv, SIGNAL(browse_instanceAvailable(int, const XMPP::ServiceInstance &)), SLOT(provider_browse_instanceAvailable(int, const XMPP::ServiceInstance &)), Qt::QueuedConnection); connect(p_serv, SIGNAL(browse_instanceUnavailable(int, const XMPP::ServiceInstance &)), SLOT(provider_browse_instanceUnavailable(int, const XMPP::ServiceInstance &)), Qt::QueuedConnection); connect(p_serv, SIGNAL(browse_error(int, XMPP::ServiceBrowser::Error)), SLOT(provider_browse_error(int, XMPP::ServiceBrowser::Error)), Qt::QueuedConnection); } /*np->id = */ np->id = p_serv->browse_start(type, domain); br_instances.insert(np->id, np); } void resolve_instance_start(ServiceResolver::Private *np, const QByteArray &name) { QMutexLocker locker(nman_mutex()); if(!p_serv) { ServiceProvider *c = 0; QList list = irisNetProviders(); for(int n = 0; n < list.count(); ++n) { IrisNetProvider *p = list[n]; c = p->createServiceProvider(); if(c) break; } Q_ASSERT(c); // we have built-in support, so this should never fail p_serv = c; // use queued connections qRegisterMetaType("QHostAddress"); qRegisterMetaType< QList >("QList"); connect(p_serv, SIGNAL(resolve_resultsReady(int, const QList &)), SLOT(provider_resolve_resultsReady(int, const QList &)), Qt::QueuedConnection); } /*np->id = */ np->id = p_serv->resolve_start(name); sres_instances.insert(np->id, np); } void publish_start(ServiceLocalPublisher::Private *np, const QString &instance, const QString &type, int port, const QMap &attribs) { QMutexLocker locker(nman_mutex()); if(!p_serv) { ServiceProvider *c = 0; QList list = irisNetProviders(); for(int n = 0; n < list.count(); ++n) { IrisNetProvider *p = list[n]; c = p->createServiceProvider(); if(c) break; } Q_ASSERT(c); // we have built-in support, so this should never fail p_serv = c; // use queued connections qRegisterMetaType("XMPP::ServiceLocalPublisher::Error"); connect(p_serv, SIGNAL(publish_published(int)), SLOT(provider_publish_published(int)), Qt::QueuedConnection); connect(p_serv, SIGNAL(publish_extra_published(int)), SLOT(provider_publish_extra_published(int)), Qt::QueuedConnection); } /*np->id = */ np->id = p_serv->publish_start(instance, type, port, attribs); slp_instances.insert(np->id, np); } void publish_extra_start(ServiceLocalPublisher::Private *np, const NameRecord &rec) { np->id = p_serv->publish_extra_start(np->id, rec); } private slots: void provider_resolve_resultsReady(int id, const QList &results) { // is it a sub-request? if(res_sub_instances.contains(id)) { int par_id = res_sub_instances.value(id); res_sub_instances.remove(id); p_net->resolve_localResultsReady(par_id, results); return; } NameResolver::Private *np = res_instances.value(id); NameResolver *q = np->q; // resolve_cleanup deletes np if(!np->longLived) resolve_cleanup(np); emit q->resultsReady(results); } void provider_resolve_error(int id, XMPP::NameResolver::Error e) { // is it a sub-request? if(res_sub_instances.contains(id)) { int par_id = res_sub_instances.value(id); res_sub_instances.remove(id); p_net->resolve_localError(par_id, e); return; } NameResolver::Private *np = res_instances.value(id); NameResolver *q = np->q; // resolve_cleanup deletes np resolve_cleanup(np); emit q->error(e); } void provider_resolve_useLocal(int id, const QByteArray &name) { // transfer to local if(!p_local) { NameProvider *c = 0; QList list = irisNetProviders(); for(int n = 0; n < list.count(); ++n) { IrisNetProvider *p = list[n]; c = p->createNameProviderLocal(); if(c) break; } Q_ASSERT(c); // we have built-in support, so this should never fail // FIXME: not true, binding can fail p_local = c; // use queued connections qRegisterMetaType< QList >("QList"); qRegisterMetaType("XMPP::NameResolver::Error"); connect(p_local, SIGNAL(resolve_resultsReady(int, const QList &)), SLOT(provider_resolve_resultsReady(int, const QList &)), Qt::QueuedConnection); connect(p_local, SIGNAL(resolve_error(int, XMPP::NameResolver::Error)), SLOT(provider_resolve_error(int, XMPP::NameResolver::Error)), Qt::QueuedConnection); } NameResolver::Private *np = res_instances.value(id); // transfer to local only if(np->longLived) { res_instances.remove(np->id); np->id = p_local->resolve_start(name, np->type, true); res_instances.insert(np->id, np); } // sub request else { int req_id = p_local->resolve_start(name, np->type, false); res_sub_instances.insert(req_id, np->id); } } void provider_browse_instanceAvailable(int id, const XMPP::ServiceInstance &i) { ServiceBrowser::Private *np = br_instances.value(id); emit np->q->instanceAvailable(i); } void provider_browse_instanceUnavailable(int id, const XMPP::ServiceInstance &i) { ServiceBrowser::Private *np = br_instances.value(id); emit np->q->instanceUnavailable(i); } void provider_browse_error(int id, XMPP::ServiceBrowser::Error e) { Q_UNUSED(e); ServiceBrowser::Private *np = br_instances.value(id); // TODO emit np->q->error(); } void provider_resolve_resultsReady(int id, const QList &results) { ServiceResolver::Private *np = sres_instances.value(id); emit np->q->resultsReady(results[0].address, results[0].port); } void provider_publish_published(int id) { ServiceLocalPublisher::Private *np = slp_instances.value(id); emit np->q->published(); } void provider_publish_extra_published(int id) { Q_UNUSED(id); //ServiceLocalPublisher::Private *np = slp_instances.value(id); //emit np->q->published(); } }; //---------------------------------------------------------------------------- // NameResolver //---------------------------------------------------------------------------- // copied from JDNS #define JDNS_RTYPE_A 1 #define JDNS_RTYPE_AAAA 28 #define JDNS_RTYPE_MX 15 #define JDNS_RTYPE_SRV 33 #define JDNS_RTYPE_CNAME 5 #define JDNS_RTYPE_PTR 12 #define JDNS_RTYPE_TXT 16 #define JDNS_RTYPE_HINFO 13 #define JDNS_RTYPE_NS 2 #define JDNS_RTYPE_ANY 255 static int recordType2Rtype(NameRecord::Type type) { switch(type) { case NameRecord::A: return JDNS_RTYPE_A; case NameRecord::Aaaa: return JDNS_RTYPE_AAAA; case NameRecord::Mx: return JDNS_RTYPE_MX; case NameRecord::Srv: return JDNS_RTYPE_SRV; case NameRecord::Cname: return JDNS_RTYPE_CNAME; case NameRecord::Ptr: return JDNS_RTYPE_PTR; case NameRecord::Txt: return JDNS_RTYPE_TXT; case NameRecord::Hinfo: return JDNS_RTYPE_HINFO; case NameRecord::Ns: return JDNS_RTYPE_NS; case NameRecord::Null: return 10; case NameRecord::Any: return JDNS_RTYPE_ANY; } return -1; } NameResolver::NameResolver(QObject *parent) :QObject(parent) { d = 0; } NameResolver::~NameResolver() { stop(); } void NameResolver::start(const QByteArray &name, NameRecord::Type type, Mode mode) { stop(); d = new Private(this); int qType = recordType2Rtype(type); if(qType == -1) qType = JDNS_RTYPE_A; NameManager::instance()->resolve_start(d, name, qType, mode == NameResolver::LongLived ? true : false); } void NameResolver::stop() { if(d) { NameManager::instance()->resolve_stop(d); delete d; d = 0; } } //---------------------------------------------------------------------------- // ServiceBrowser //---------------------------------------------------------------------------- ServiceBrowser::ServiceBrowser(QObject *parent) :QObject(parent) { d = new Private(this); } ServiceBrowser::~ServiceBrowser() { delete d; } void ServiceBrowser::start(const QString &type, const QString &domain) { NameManager::instance()->browse_start(d, type, domain); } void ServiceBrowser::stop() { } //---------------------------------------------------------------------------- // ServiceResolver //---------------------------------------------------------------------------- ServiceResolver::ServiceResolver(QObject *parent) :QObject(parent) { qRegisterMetaType("QHostAddress"); d = new Private(this); } ServiceResolver::~ServiceResolver() { delete d; } void ServiceResolver::startFromInstance(const QByteArray &name) { NameManager::instance()->resolve_instance_start(d, name); } void ServiceResolver::startFromDomain(const QString &domain, const QString &type) { d->mode = 0; d->dns.start(type.toLatin1() + '.' + domain.toLatin1(), NameRecord::Srv); } void ServiceResolver::startFromPlain(const QString &host, int port) { d->mode = 1; d->port = port; d->dns.start(host.toLatin1(), NameRecord::A); // TODO: try Aaaa first, fallback to A } void ServiceResolver::tryNext() { d->tryNext(); } void ServiceResolver::stop() { } //---------------------------------------------------------------------------- // ServiceLocalPublisher //---------------------------------------------------------------------------- ServiceLocalPublisher::ServiceLocalPublisher(QObject *parent) :QObject(parent) { d = new Private(this); } ServiceLocalPublisher::~ServiceLocalPublisher() { delete d; } void ServiceLocalPublisher::publish(const QString &instance, const QString &type, int port, const QMap &attributes) { NameManager::instance()->publish_start(d, instance, type, port, attributes); } void ServiceLocalPublisher::updateAttributes(const QMap &attributes) { Q_UNUSED(attributes); } void ServiceLocalPublisher::addRecord(const NameRecord &rec) { NameManager::instance()->publish_extra_start(d, rec); } void ServiceLocalPublisher::cancel() { } //---------------------------------------------------------------------------- // NetNames //---------------------------------------------------------------------------- void NetNames::cleanup() { NameManager::cleanup(); } QString NetNames::diagnosticText() { // TODO return QString(); } QByteArray NetNames::idnaFromString(const QString &in) { // TODO Q_UNUSED(in); return QByteArray(); } QString NetNames::idnaToString(const QByteArray &in) { // TODO Q_UNUSED(in); return QString(); } QByteArray NetNames::escapeDomain(const QByteArray &in) { // TODO Q_UNUSED(in); return QByteArray(); } QByteArray NetNames::unescapeDomain(const QByteArray &in) { // TODO Q_UNUSED(in); return QByteArray(); } } #include "netnames.moc" psi-0.14/iris/src/irisnet/corelib/jdnsshared.cpp0000644000175000017500000007604411305557616020041 0ustar janjan/* * Copyright (C) 2006-2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ // Note: JDnsShared supports multiple interfaces for multicast, but only one // for IPv4 and one for IPv6. Sharing multiple interfaces of the same IP // version for multicast is unfortunately not possible without reworking // the jdns subsystem. // // The reason for this limitation is that in order to do multi-interface // multicast, you have to do a single bind to Any, and then use special // functions to determine which interface a packet came from and to // specify which interface a packet should go out on. Again this is just // not possible with the current system and the assumptions made by jdns. // Note: When quering against multiple interfaces with multicast, it is // possible that different answers for a unique record may be reported // on each interface. We don't do anything about this. #include "jdnsshared.h" namespace { // safeobj stuff, from qca void releaseAndDeleteLater(QObject *owner, QObject *obj) { obj->disconnect(owner); obj->setParent(0); obj->deleteLater(); } class SafeTimer : public QObject { Q_OBJECT public: SafeTimer(QObject *parent = 0) : QObject(parent) { t = new QTimer(this); connect(t, SIGNAL(timeout()), SIGNAL(timeout())); } ~SafeTimer() { releaseAndDeleteLater(this, t); } int interval() const { return t->interval(); } bool isActive() const { return t->isActive(); } bool isSingleShot() const { return t->isSingleShot(); } void setInterval(int msec) { t->setInterval(msec); } void setSingleShot(bool singleShot) { t->setSingleShot(singleShot); } int timerId() const { return t->timerId(); } public slots: void start(int msec) { t->start(msec); } void start() { t->start(); } void stop() { t->stop(); } signals: void timeout(); private: QTimer *t; }; // for caching system info class SystemInfoCache { public: QJDns::SystemInfo info; QTime time; }; } Q_GLOBAL_STATIC(QMutex, jdnsshared_mutex) Q_GLOBAL_STATIC(SystemInfoCache, jdnsshared_infocache) static QJDns::SystemInfo get_sys_info() { QMutexLocker locker(jdnsshared_mutex()); SystemInfoCache *c = jdnsshared_infocache(); // cache info for 1/2 second, enough to prevent re-reading of sys // info 20 times because of all the different resolves if(c->time.isNull() || c->time.elapsed() >= 500) { c->info = QJDns::systemInfo(); c->time.start(); } return c->info; } static bool domainCompare(const QByteArray &a, const QByteArray &b) { return (qstricmp(a.data(), b.data()) == 0) ? true: false; } // adapted from jdns_mdnsd.c, _a_match() static bool matchRecordExceptTtl(const QJDns::Record &a, const QJDns::Record &b) { if(a.type != b.type || !domainCompare(a.owner, b.owner)) return false; if(a.type == QJDns::Srv) { if(domainCompare(a.name, b.name) && a.port == b.port && a.priority == b.priority && a.weight == b.weight) { return true; } } else if(a.type == QJDns::Ptr || a.type == QJDns::Ns || a.type == QJDns::Cname) { if(domainCompare(a.name, b.name)) return true; } else if(a.rdata == b.rdata) return true; return false; } static void getHex(unsigned char in, char *hi, char *lo) { QString str; str.sprintf("%02x", in); *hi = str[0].toLatin1(); *lo = str[1].toLatin1(); } static QByteArray getDec(int in) { return QString::number(in).toLatin1(); } static QByteArray makeReverseName(const QHostAddress &addr) { QByteArray out; if(addr.protocol() == QAbstractSocket::IPv6Protocol) { Q_IPV6ADDR raw = addr.toIPv6Address(); for(int n = 0; n < 32; ++n) { char hi, lo; getHex(raw.c[31 - n], &hi, &lo); out += lo; out += '.'; out += hi; out += '.'; } out += "ip6.arpa."; } else { quint32 rawi = addr.toIPv4Address(); int raw[4]; raw[0] = (rawi >> 24) & 0xff; raw[1] = (rawi >> 16) & 0xff; raw[2] = (rawi >> 8) & 0xff; raw[3] = rawi & 0xff; for(int n = 0; n < 4; ++n) { out += getDec(raw[3 - n]); out += '.'; } out += "in-addr.arpa."; } return out; } //---------------------------------------------------------------------------- // Handle //---------------------------------------------------------------------------- namespace { // QJDns uses integer handle ids, but they are only unique within // the relevant QJDns instance. Since we want our handles to be // unique across all instances, we'll make an instance/id pair. class Handle { public: QJDns *jdns; int id; Handle() : jdns(0), id(-1) { } Handle(QJDns *_jdns, int _id) : jdns(_jdns), id(_id) { } bool operator==(const Handle &a) const { if(a.jdns == jdns && a.id == id) return true; return false; } bool operator!=(const Handle &a) const { return !(operator==(a)); } }; // adapted from qHash static inline uint qHash(const Handle &key) { uint h1 = ::qHash(key.jdns); uint h2 = ::qHash(key.id); return ((h1 << 16) | (h1 >> 16)) ^ h2; } } //---------------------------------------------------------------------------- // JDnsShutdown //---------------------------------------------------------------------------- namespace { class JDnsShutdownAgent : public QObject { Q_OBJECT public: void start() { QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection); } signals: void started(); }; class JDnsShutdownWorker : public QObject { Q_OBJECT public: QList list; JDnsShutdownWorker(const QList &_list) : QObject(0), list(_list) { foreach(JDnsShared *i, list) { connect(i, SIGNAL(shutdownFinished()), SLOT(jdns_shutdownFinished())); i->shutdown(); // MUST support DOR-DS, and it does } } signals: void finished(); private slots: void jdns_shutdownFinished() { JDnsShared *i = (JDnsShared *)sender(); list.removeAll(i); delete i; if(list.isEmpty()) emit finished(); } }; class JDnsShutdown : public QThread { Q_OBJECT public: QMutex m; QWaitCondition w; QList list; JDnsShutdownAgent *agent; JDnsShutdownWorker *worker; int phase; void waitForShutdown(const QList &_list) { list = _list; phase = 0; m.lock(); start(); w.wait(&m); foreach(JDnsShared *i, list) { i->setParent(0); i->moveToThread(this); } phase = 1; agent->start(); wait(); } protected: virtual void run() { m.lock(); agent = new JDnsShutdownAgent; connect(agent, SIGNAL(started()), SLOT(agent_started()), Qt::DirectConnection); agent->start(); exec(); delete agent; } private slots: void agent_started() { if(phase == 0) { w.wakeOne(); m.unlock(); } else { worker = new JDnsShutdownWorker(list); connect(worker, SIGNAL(finished()), SLOT(worker_finished()), Qt::DirectConnection); } } void worker_finished() { delete worker; worker = 0; quit(); } }; } //---------------------------------------------------------------------------- // JDnsSharedDebug //---------------------------------------------------------------------------- class JDnsSharedDebugPrivate : public QObject { Q_OBJECT public: JDnsSharedDebug *q; QMutex m; QStringList lines; bool dirty; JDnsSharedDebugPrivate(JDnsSharedDebug *_q) : QObject(_q), q(_q) { dirty = false; } void addDebug(const QString &name, const QStringList &_lines) { if(!_lines.isEmpty()) { QMutexLocker locker(&m); for(int n = 0; n < _lines.count(); ++n) lines += name + ": " + _lines[n]; if(!dirty) { dirty = true; QMetaObject::invokeMethod(this, "doUpdate", Qt::QueuedConnection); } } } private slots: void doUpdate() { { QMutexLocker locker(&m); if(!dirty) return; } emit q->readyRead(); } }; JDnsSharedDebug::JDnsSharedDebug(QObject *parent) :QObject(parent) { d = new JDnsSharedDebugPrivate(this); } JDnsSharedDebug::~JDnsSharedDebug() { delete d; } QStringList JDnsSharedDebug::readDebugLines() { QMutexLocker locker(&d->m); QStringList tmplines = d->lines; d->lines.clear(); d->dirty = false; return tmplines; } //---------------------------------------------------------------------------- // JDnsSharedRequest //---------------------------------------------------------------------------- class JDnsSharedPrivate : public QObject { Q_OBJECT public: class Instance { public: QJDns *jdns; QHostAddress addr; int index; Instance() : jdns(0) { } }; enum PreprocessMode { None, // don't muck with anything FillInAddress, // for A/AAAA FillInPtrOwner6, // for PTR, IPv6 FillInPtrOwner4, // for PTR, IPv4 }; JDnsShared *q; JDnsShared::Mode mode; bool shutting_down; JDnsSharedDebug *db; QString dbname; QList instances; QHash instanceForQJDns; QSet requests; QHash requestForHandle; JDnsSharedPrivate(JDnsShared *_q) : QObject(_q), q(_q) { } JDnsSharedRequest *findRequest(QJDns *jdns, int id) const { Handle h(jdns, id); return requestForHandle.value(h); } void jdns_link(QJDns *jdns) { connect(jdns, SIGNAL(resultsReady(int, const QJDns::Response &)), SLOT(jdns_resultsReady(int, const QJDns::Response &))); connect(jdns, SIGNAL(published(int)), SLOT(jdns_published(int))); connect(jdns, SIGNAL(error(int, QJDns::Error)), SLOT(jdns_error(int, QJDns::Error))); connect(jdns, SIGNAL(shutdownFinished()), SLOT(jdns_shutdownFinished())); connect(jdns, SIGNAL(debugLinesReady()), SLOT(jdns_debugLinesReady())); } int getNewIndex() const { // find lowest unused value for(int n = 0;; ++n) { bool found = false; foreach(Instance *i, instances) { if(i->index == n) { found = true; break; } } if(!found) return n; } } void addDebug(int index, const QString &line) { if(db) db->d->addDebug(dbname + QString::number(index), QStringList() << line); } void doDebug(QJDns *jdns, int index) { QStringList lines = jdns->debugLines(); if(db) db->d->addDebug(dbname + QString::number(index), lines); } PreprocessMode determinePpMode(const QJDns::Record &in) { // Note: since our implementation only allows 1 ipv4 and 1 ipv6 // interface to exist, it is safe to publish both kinds of // records on both interfaces, with the same values. For // example, an A record can be published on both interfaces, // with the value set to the ipv4 interface. If we supported // multiple ipv4 interfaces, then this wouldn't work, because // we wouldn't know which value to use for the A record when // publishing on the ipv6 interface. // publishing our own IP address? null address means the user // wants us to fill in the blank with our address. if((in.type == QJDns::Aaaa || in.type == QJDns::A) && in.address.isNull()) { return FillInAddress; } // publishing our own reverse lookup? partial owner means // user wants us to fill in the rest. else if(in.type == QJDns::Ptr && in.owner == ".ip6.arpa.") { return FillInPtrOwner6; } else if(in.type == QJDns::Ptr && in.owner == ".in-addr.arpa.") { return FillInPtrOwner4; } return None; } QJDns::Record manipulateRecord(const QJDns::Record &in, PreprocessMode ppmode, bool *modified = 0) { if(ppmode == FillInAddress) { QJDns::Record out = in; if(in.type == QJDns::Aaaa) { // are we operating on ipv6? foreach(Instance *i, instances) { if(i->addr.protocol() == QAbstractSocket::IPv6Protocol) { if(modified && !(out.address == i->addr)) *modified = true; out.address = i->addr; break; } } } else // A { // are we operating on ipv4? foreach(Instance *i, instances) { if(i->addr.protocol() == QAbstractSocket::IPv4Protocol) { if(modified && !(out.address == i->addr)) *modified = true; out.address = i->addr; break; } } } return out; } else if(ppmode == FillInPtrOwner6) { QJDns::Record out = in; // are we operating on ipv6? foreach(Instance *i, instances) { if(i->addr.protocol() == QAbstractSocket::IPv6Protocol) { QByteArray newOwner = makeReverseName(i->addr); if(modified && !(out.owner == newOwner)) *modified = true; out.owner = newOwner; break; } } return out; } else if(ppmode == FillInPtrOwner4) { QJDns::Record out = in; // are we operating on ipv4? foreach(Instance *i, instances) { if(i->addr.protocol() == QAbstractSocket::IPv4Protocol) { QByteArray newOwner = makeReverseName(i->addr); if(modified && !(out.owner == newOwner)) *modified = true; out.owner = newOwner; break; } } return out; } if(modified) *modified = false; return in; } bool addInterface(const QHostAddress &addr); void removeInterface(const QHostAddress &addr); void queryStart(JDnsSharedRequest *obj, const QByteArray &name, int qType); void queryCancel(JDnsSharedRequest *obj); void publishStart(JDnsSharedRequest *obj, QJDns::PublishMode m, const QJDns::Record &record); void publishUpdate(JDnsSharedRequest *obj, const QJDns::Record &record); void publishCancel(JDnsSharedRequest *obj); public slots: void late_shutdown() { shutting_down = false; emit q->shutdownFinished(); } private slots: void jdns_resultsReady(int id, const QJDns::Response &results); void jdns_published(int id); void jdns_error(int id, QJDns::Error e); void jdns_shutdownFinished(); void jdns_debugLinesReady(); }; class JDnsSharedRequestPrivate : public QObject { Q_OBJECT public: JDnsSharedRequest *q; JDnsSharedPrivate *jsp; // current action JDnsSharedRequest::Type type; QByteArray name; int qType; QJDns::PublishMode pubmode; JDnsSharedPrivate::PreprocessMode ppmode; QJDns::Record pubrecord; // a single request might have to perform multiple QJDns operations QList handles; // keep a list of handles that successfully publish QList published; // use to weed out dups for multicast QList queryCache; bool success; JDnsSharedRequest::Error error; QList results; SafeTimer lateTimer; JDnsSharedRequestPrivate(JDnsSharedRequest *_q) : QObject(_q), q(_q), lateTimer(this) { connect(&lateTimer, SIGNAL(timeout()), SLOT(lateTimer_timeout())); } void resetSession() { name = QByteArray(); pubrecord = QJDns::Record(); handles.clear(); published.clear(); queryCache.clear(); } private slots: void lateTimer_timeout() { emit q->resultsReady(); } }; JDnsSharedRequest::JDnsSharedRequest(JDnsShared *jdnsShared, QObject *parent) :QObject(parent) { d = new JDnsSharedRequestPrivate(this); d->jsp = jdnsShared->d; } JDnsSharedRequest::~JDnsSharedRequest() { cancel(); delete d; } JDnsSharedRequest::Type JDnsSharedRequest::type() { return d->type; } void JDnsSharedRequest::query(const QByteArray &name, int type) { cancel(); d->jsp->queryStart(this, name, type); } void JDnsSharedRequest::publish(QJDns::PublishMode m, const QJDns::Record &record) { cancel(); d->jsp->publishStart(this, m, record); } void JDnsSharedRequest::publishUpdate(const QJDns::Record &record) { // only allowed to update if we have an active publish if(!d->handles.isEmpty() && d->type == Publish) d->jsp->publishUpdate(this, record); } void JDnsSharedRequest::cancel() { d->lateTimer.stop(); if(!d->handles.isEmpty()) { if(d->type == Query) d->jsp->queryCancel(this); else d->jsp->publishCancel(this); } d->resetSession(); } bool JDnsSharedRequest::success() const { return d->success; } JDnsSharedRequest::Error JDnsSharedRequest::error() const { return d->error; } QList JDnsSharedRequest::results() const { return d->results; } //---------------------------------------------------------------------------- // JDnsShared //---------------------------------------------------------------------------- JDnsShared::JDnsShared(Mode mode, QObject *parent) :QObject(parent) { d = new JDnsSharedPrivate(this); d->mode = mode; d->shutting_down = false; d->db = 0; } JDnsShared::~JDnsShared() { foreach(JDnsSharedPrivate::Instance *i, d->instances) { delete i->jdns; delete i; } delete d; } void JDnsShared::setDebug(JDnsSharedDebug *db, const QString &name) { d->db = db; d->dbname = name; } bool JDnsShared::addInterface(const QHostAddress &addr) { return d->addInterface(addr); } void JDnsShared::removeInterface(const QHostAddress &addr) { d->removeInterface(addr); } void JDnsShared::shutdown() { d->shutting_down = true; if(!d->instances.isEmpty()) { foreach(JDnsSharedPrivate::Instance *i, d->instances) i->jdns->shutdown(); } else QMetaObject::invokeMethod(d, "late_shutdown", Qt::QueuedConnection); } QList JDnsShared::domains() { return get_sys_info().domains; } void JDnsShared::waitForShutdown(const QList &instances) { JDnsShutdown s; s.waitForShutdown(instances); } bool JDnsSharedPrivate::addInterface(const QHostAddress &addr) { if(shutting_down) return false; // make sure we don't have this one already foreach(Instance *i, instances) { if(i->addr == addr) return false; } int index = getNewIndex(); addDebug(index, QString("attempting to use interface %1").arg(addr.toString())); QJDns *jdns; if(mode == JDnsShared::UnicastInternet || mode == JDnsShared::UnicastLocal) { jdns = new QJDns(this); jdns_link(jdns); if(!jdns->init(QJDns::Unicast, addr)) { doDebug(jdns, index); delete jdns; return false; } if(mode == JDnsShared::UnicastLocal) { QJDns::NameServer host; if(addr.protocol() == QAbstractSocket::IPv6Protocol) host.address = QHostAddress("FF02::FB"); else host.address = QHostAddress("224.0.0.251"); host.port = 5353; jdns->setNameServers(QList() << host); } } else // Multicast { // only one multicast interface allowed per IP protocol version. // this is because we bind to INADDR_ANY. bool have_v6 = false; bool have_v4 = false; foreach(Instance *i, instances) { if(i->addr.protocol() == QAbstractSocket::IPv6Protocol) have_v6 = true; else have_v4 = true; } bool is_v6 = (addr.protocol() == QAbstractSocket::IPv6Protocol) ? true : false; if(is_v6 && have_v6) { addDebug(index, "already have an ipv6 interface"); return false; } if(!is_v6 && have_v4) { addDebug(index, "already have an ipv4 interface"); return false; } QHostAddress actualBindAddress; if(is_v6) actualBindAddress = QHostAddress::AnyIPv6; else actualBindAddress = QHostAddress::Any; jdns = new QJDns(this); jdns_link(jdns); if(!jdns->init(QJDns::Multicast, actualBindAddress)) { doDebug(jdns, index); delete jdns; return false; } } Instance *i = new Instance; i->jdns = jdns; i->addr = addr; i->index = index; instances += i; instanceForQJDns.insert(i->jdns, i); addDebug(index, "interface ready"); if(mode == JDnsShared::Multicast) { // extend active requests to this interface foreach(JDnsSharedRequest *obj, requests) { if(obj->d->type == JDnsSharedRequest::Query) { Handle h(i->jdns, i->jdns->queryStart(obj->d->name, obj->d->qType)); obj->d->handles += h; requestForHandle.insert(h, obj); } else // Publish { bool modified; obj->d->pubrecord = manipulateRecord(obj->d->pubrecord, obj->d->ppmode, &modified); // if the record changed, update on the other (existing) interfaces if(modified) { foreach(Handle h, obj->d->handles) h.jdns->publishUpdate(h.id, obj->d->pubrecord); } // publish the record on the new interface Handle h(i->jdns, i->jdns->publishStart(obj->d->pubmode, obj->d->pubrecord)); obj->d->handles += h; requestForHandle.insert(h, obj); } } } return true; } void JDnsSharedPrivate::removeInterface(const QHostAddress &addr) { Instance *i = 0; for(int n = 0; n < instances.count(); ++n) { if(instances[n]->addr == addr) { i = instances[n]; break; } } if(!i) return; int index = i->index; // we don't cancel operations or shutdown jdns, we simply // delete our references. this is because if the interface // is gone, then we have nothing to send on anyway. foreach(JDnsSharedRequest *obj, requests) { for(int n = 0; n < obj->d->handles.count(); ++n) { Handle h = obj->d->handles[n]; if(h.jdns == i->jdns) { // see above, no need to cancel the operation obj->d->handles.removeAt(n); requestForHandle.remove(h); break; } } // remove published reference if(obj->d->type == JDnsSharedRequest::Publish) { for(int n = 0; n < obj->d->published.count(); ++n) { Handle h = obj->d->published[n]; if(h.jdns == i->jdns) { obj->d->published.removeAt(n); break; } } } } // see above, no need to shutdown jdns instanceForQJDns.remove(i->jdns); instances.removeAll(i); delete i->jdns; delete i; // if that was the last interface to be removed, then there should // be no more handles left. let's take action with these // handleless requests. foreach(JDnsSharedRequest *obj, requests) { if(obj->d->handles.isEmpty()) { if(mode == JDnsShared::UnicastInternet || mode == JDnsShared::UnicastLocal) { // for unicast, we'll invalidate with ErrorNoNet obj->d->success = false; obj->d->error = JDnsSharedRequest::ErrorNoNet; obj->d->lateTimer.start(); } else // Multicast { // for multicast, we'll keep all requests alive. // activity will resume when an interface is // added. } } } addDebug(index, QString("removing from %1").arg(addr.toString())); } void JDnsSharedPrivate::queryStart(JDnsSharedRequest *obj, const QByteArray &name, int qType) { obj->d->type = JDnsSharedRequest::Query; obj->d->success = false; obj->d->results.clear(); obj->d->name = name; obj->d->qType = qType; // is the input an IP address and the qType is an address record? if(qType == QJDns::Aaaa || qType == QJDns::A) { QHostAddress addr; if(addr.setAddress(QString::fromLocal8Bit(name))) { if(qType == QJDns::Aaaa && addr.protocol() == QAbstractSocket::IPv6Protocol) { QJDns::Record rec; rec.owner = name; rec.type = QJDns::Aaaa; rec.ttl = 120; rec.haveKnown = true; rec.address = addr; obj->d->success = true; obj->d->results = QList() << rec; obj->d->lateTimer.start(); return; } else if(qType == QJDns::A && addr.protocol() == QAbstractSocket::IPv4Protocol) { QJDns::Record rec; rec.owner = name; rec.type = QJDns::A; rec.ttl = 120; rec.haveKnown = true; rec.address = addr; obj->d->success = true; obj->d->results = QList() << rec; obj->d->lateTimer.start(); return; } } } QJDns::SystemInfo sysInfo = get_sys_info(); // is the input name a known host and the qType is an address record? if(qType == QJDns::Aaaa || qType == QJDns::A) { QByteArray lname = name.toLower(); QList known = sysInfo.hosts; foreach(QJDns::DnsHost host, known) { if(((qType == QJDns::Aaaa && host.address.protocol() == QAbstractSocket::IPv6Protocol) || (qType == QJDns::A && host.address.protocol() == QAbstractSocket::IPv4Protocol)) && host.name.toLower() == lname) { QJDns::Record rec; rec.owner = name; rec.type = qType; rec.ttl = 120; rec.haveKnown = true; rec.address = host.address; obj->d->success = true; obj->d->results = QList() << rec; obj->d->lateTimer.start(); return; } } } // if we have no QJDns instances to operate on, then error if(instances.isEmpty()) { obj->d->error = JDnsSharedRequest::ErrorNoNet; obj->d->lateTimer.start(); return; } if(mode == JDnsShared::UnicastInternet) { // get latest nameservers, split into ipv6/v4, apply to jdns instances QList ns_v6; QList ns_v4; { QList nameServers = sysInfo.nameServers; foreach(QJDns::NameServer ns, nameServers) { if(ns.address.protocol() == QAbstractSocket::IPv6Protocol) ns_v6 += ns; else ns_v4 += ns; } } foreach(Instance *i, instances) { if(i->addr.protocol() == QAbstractSocket::IPv6Protocol) i->jdns->setNameServers(ns_v6); else i->jdns->setNameServers(ns_v4); } } // keep track of this request requests += obj; // query on all jdns instances foreach(Instance *i, instances) { Handle h(i->jdns, i->jdns->queryStart(name, qType)); obj->d->handles += h; // keep track of this handle for this request requestForHandle.insert(h, obj); } } void JDnsSharedPrivate::queryCancel(JDnsSharedRequest *obj) { if(!requests.contains(obj)) return; foreach(Handle h, obj->d->handles) { h.jdns->queryCancel(h.id); requestForHandle.remove(h); } obj->d->handles.clear(); requests.remove(obj); } void JDnsSharedPrivate::publishStart(JDnsSharedRequest *obj, QJDns::PublishMode m, const QJDns::Record &record) { obj->d->type = JDnsSharedRequest::Publish; obj->d->success = false; obj->d->results.clear(); obj->d->pubmode = m; obj->d->ppmode = determinePpMode(record); obj->d->pubrecord = manipulateRecord(record, obj->d->ppmode); // if we have no QJDns instances to operate on, then error if(instances.isEmpty()) { obj->d->error = JDnsSharedRequest::ErrorNoNet; obj->d->lateTimer.start(); return; } // keep track of this request requests += obj; // attempt to publish on all jdns instances foreach(JDnsSharedPrivate::Instance *i, instances) { Handle h(i->jdns, i->jdns->publishStart(m, obj->d->pubrecord)); obj->d->handles += h; // keep track of this handle for this request requestForHandle.insert(h, obj); } } void JDnsSharedPrivate::publishUpdate(JDnsSharedRequest *obj, const QJDns::Record &record) { if(!requests.contains(obj)) return; obj->d->ppmode = determinePpMode(record); obj->d->pubrecord = manipulateRecord(record, obj->d->ppmode); // publish update on all handles for this request foreach(Handle h, obj->d->handles) h.jdns->publishUpdate(h.id, obj->d->pubrecord); } void JDnsSharedPrivate::publishCancel(JDnsSharedRequest *obj) { if(!requests.contains(obj)) return; foreach(Handle h, obj->d->handles) { h.jdns->publishCancel(h.id); requestForHandle.remove(h); } obj->d->handles.clear(); obj->d->published.clear(); requests.remove(obj); } void JDnsSharedPrivate::jdns_resultsReady(int id, const QJDns::Response &results) { QJDns *jdns = (QJDns *)sender(); JDnsSharedRequest *obj = findRequest(jdns, id); Q_ASSERT(obj); obj->d->success = true; obj->d->results = results.answerRecords; if(mode == JDnsShared::UnicastInternet || mode == JDnsShared::UnicastLocal) { // only one response, so "cancel" it for(int n = 0; n < obj->d->handles.count(); ++n) { Handle h = obj->d->handles[n]; if(h.jdns == jdns && h.id == id) { obj->d->handles.removeAt(n); requestForHandle.remove(h); break; } } // cancel related handles foreach(Handle h, obj->d->handles) { h.jdns->queryCancel(h.id); requestForHandle.remove(h); } obj->d->handles.clear(); requests.remove(obj); } else // Multicast { // check our cache to see how we should report these results for(int n = 0; n < obj->d->results.count(); ++n) { QJDns::Record &r = obj->d->results[n]; // do we have this answer already in our cache? QJDns::Record *c = 0; int c_at = -1; for(int k = 0; k < obj->d->queryCache.count(); ++k) { QJDns::Record &tmp = obj->d->queryCache[k]; if(matchRecordExceptTtl(r, tmp)) { c = &tmp; c_at = k; break; } } // don't report duplicates or unknown removals if((c && r.ttl != 0) || (!c && r.ttl == 0)) { obj->d->results.removeAt(n); --n; // adjust position continue; } // if we have it, and it is removed, remove from cache if(c && r.ttl == 0) { obj->d->queryCache.removeAt(c_at); } // otherwise, if we don't have it, add it to the cache else if(!c) { obj->d->queryCache += r; } } if(obj->d->results.isEmpty()) return; } emit obj->resultsReady(); } void JDnsSharedPrivate::jdns_published(int id) { QJDns *jdns = (QJDns *)sender(); JDnsSharedRequest *obj = findRequest(jdns, id); Q_ASSERT(obj); // find handle Handle handle; for(int n = 0; n < obj->d->handles.count(); ++n) { Handle h = obj->d->handles[n]; if(h.jdns == jdns && h.id == id) { handle = h; break; } } obj->d->published += handle; // if this publish has already been considered successful, then // a publish has succeeded on a new interface and there's no // need to report success for this request again if(obj->d->success) return; // all handles published? if(obj->d->published.count() == obj->d->handles.count()) { obj->d->success = true; emit obj->resultsReady(); } } void JDnsSharedPrivate::jdns_error(int id, QJDns::Error e) { QJDns *jdns = (QJDns *)sender(); JDnsSharedRequest *obj = findRequest(jdns, id); Q_ASSERT(obj); // "cancel" it for(int n = 0; n < obj->d->handles.count(); ++n) { Handle h = obj->d->handles[n]; if(h.jdns == jdns && h.id == id) { obj->d->handles.removeAt(n); requestForHandle.remove(h); break; } } if(obj->d->type == JDnsSharedRequest::Query) { // ignore the error if it is not the last error if(!obj->d->handles.isEmpty()) return; requests.remove(obj); obj->d->success = false; JDnsSharedRequest::Error x = JDnsSharedRequest::ErrorGeneric; if(e == QJDns::ErrorNXDomain) x = JDnsSharedRequest::ErrorNXDomain; else if(e == QJDns::ErrorTimeout) x = JDnsSharedRequest::ErrorTimeout; else // ErrorGeneric x = JDnsSharedRequest::ErrorGeneric; obj->d->error = x; emit obj->resultsReady(); } else // Publish { // cancel related handles foreach(Handle h, obj->d->handles) { h.jdns->publishCancel(h.id); requestForHandle.remove(h); } obj->d->handles.clear(); obj->d->published.clear(); requests.remove(obj); obj->d->success = false; JDnsSharedRequest::Error x = JDnsSharedRequest::ErrorGeneric; if(e == QJDns::ErrorConflict) x = JDnsSharedRequest::ErrorConflict; else // ErrorGeneric x = JDnsSharedRequest::ErrorGeneric; obj->d->error = x; emit obj->resultsReady(); } } void JDnsSharedPrivate::jdns_shutdownFinished() { QJDns *jdns = (QJDns *)sender(); addDebug(instanceForQJDns.value(jdns)->index, "jdns_shutdownFinished, removing interface"); Instance *instance = instanceForQJDns.value(jdns); delete instance->jdns; delete instance; instanceForQJDns.remove(jdns); instances.removeAll(instance); if(instances.isEmpty()) late_shutdown(); } void JDnsSharedPrivate::jdns_debugLinesReady() { QJDns *jdns = (QJDns *)sender(); doDebug(jdns, instanceForQJDns.value(jdns)->index); } #include "jdnsshared.moc" psi-0.14/iris/src/irisnet/irisnet.pro0000644000175000017500000000054111305557616015755 0ustar janjanTEMPLATE = subdirs include(../libbase.pri) sub_corelib.subdir = corelib sub_appledns.subdir = appledns sub_appledns.depends = sub_corelib sub_noncore.subdir = noncore !irisnetcore_bundle:sub_noncore.depends = sub_corelib !irisnetcore_bundle:SUBDIRS += sub_corelib appledns:!appledns_bundle:SUBDIRS += sub_appledns !iris_bundle:SUBDIRS += sub_noncore psi-0.14/iris/src/irisnet/appledns/0000755000175000017500000000000011305557616015364 5ustar janjanpsi-0.14/iris/src/irisnet/appledns/qdnssd.cpp0000644000175000017500000005747511305557616017406 0ustar janjan/* * Copyright (C) 2007,2008 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "qdnssd.h" #include #include // for ntohs #ifdef Q_OS_WIN # include #else # include #endif #include "dns_sd.h" namespace { // safeobj stuff, from qca void releaseAndDeleteLater(QObject *owner, QObject *obj) { obj->disconnect(owner); obj->setParent(0); obj->deleteLater(); } class SafeTimer : public QObject { Q_OBJECT public: SafeTimer(QObject *parent = 0) : QObject(parent) { t = new QTimer(this); connect(t, SIGNAL(timeout()), SIGNAL(timeout())); } ~SafeTimer() { releaseAndDeleteLater(this, t); } int interval() const { return t->interval(); } bool isActive() const { return t->isActive(); } bool isSingleShot() const { return t->isSingleShot(); } void setInterval(int msec) { t->setInterval(msec); } void setSingleShot(bool singleShot) { t->setSingleShot(singleShot); } int timerId() const { return t->timerId(); } public slots: void start(int msec) { t->start(msec); } void start() { t->start(); } void stop() { t->stop(); } signals: void timeout(); private: QTimer *t; }; class SafeSocketNotifier : public QObject { Q_OBJECT public: SafeSocketNotifier(int socket, QSocketNotifier::Type type, QObject *parent = 0) : QObject(parent) { sn = new QSocketNotifier(socket, type, this); connect(sn, SIGNAL(activated(int)), SIGNAL(activated(int))); } ~SafeSocketNotifier() { sn->setEnabled(false); releaseAndDeleteLater(this, sn); } bool isEnabled() const { return sn->isEnabled(); } int socket() const { return sn->socket(); } QSocketNotifier::Type type() const { return sn->type(); } public slots: void setEnabled(bool enable) { sn->setEnabled(enable); } signals: void activated(int socket); private: QSocketNotifier *sn; }; // DNSServiceRef must be allocated by the user and initialized by the // API. Additionally, it is unclear from the API whether or not // DNSServiceRef can be copied (it is an opaque data structure). // What we'll do is allocate DNSServiceRef on the heap, allowing us // to maintain a pointer which /can/ be copied. Also, we'll keep // a flag to indicate whether the allocated DNSServiceRef has been // initialized yet. class ServiceRef { private: DNSServiceRef *_p; bool _initialized; public: ServiceRef() : _initialized(false) { _p = (DNSServiceRef *)malloc(sizeof(DNSServiceRef)); } ~ServiceRef() { if(_initialized) DNSServiceRefDeallocate(*_p); free(_p); } DNSServiceRef *data() { return _p; } void setInitialized() { _initialized = true; } }; class RecordRef { private: DNSRecordRef *_p; public: RecordRef() { _p = (DNSRecordRef *)malloc(sizeof(DNSRecordRef)); } ~RecordRef() { free(_p); } DNSRecordRef *data() { return _p; } }; class IdManager { private: QSet set; int at; inline void bump_at() { if(at == 0x7fffffff) at = 0; else ++at; } public: IdManager() : at(0) { } int reserveId() { while(1) { if(!set.contains(at)) { int id = at; set.insert(id); bump_at(); return id; } bump_at(); } } void releaseId(int id) { set.remove(id); } }; } //---------------------------------------------------------------------------- // QDnsSd //---------------------------------------------------------------------------- class QDnsSd::Private : public QObject { Q_OBJECT public: QDnsSd *q; IdManager idManager; class SubRecord { public: Private *_self; int _id; RecordRef *_sdref; SubRecord(Private *self) : _self(self), _id(-1), _sdref(0) { } ~SubRecord() { delete _sdref; _self->idManager.releaseId(_id); } }; class Request { public: enum Type { Query, Browse, Resolve, Reg }; Private *_self; int _type; int _id; ServiceRef *_sdref; int _sockfd; SafeSocketNotifier *_sn_read; SafeTimer *_errorTrigger; bool _doSignal; LowLevelError _lowLevelError; QList _queryRecords; QList _browseEntries; QByteArray _resolveFullName; QByteArray _resolveHost; int _resolvePort; QByteArray _resolveTxtRecord; QByteArray _regDomain; bool _regConflict; QList _subRecords; Request(Private *self) : _self(self), _id(-1), _sdref(0), _sockfd(-1), _sn_read(0), _errorTrigger(0), _doSignal(false) { } ~Request() { qDeleteAll(_subRecords); delete _errorTrigger; delete _sn_read; delete _sdref; _self->idManager.releaseId(_id); } int subRecordIndexById(int rec_id) const { for(int n = 0; n < _subRecords.count(); ++n) { if(_subRecords[n]->_id == rec_id) return n; } return -1; } }; QHash _requestsById; QHash _requestsBySocket; QHash _requestsByTimer; QHash _requestsByRecId; Private(QDnsSd *_q) : QObject(_q), q(_q) { } ~Private() { qDeleteAll(_requestsById); } void setDelayedError(Request *req, const LowLevelError &lowLevelError) { delete req->_sdref; req->_sdref = 0; req->_lowLevelError = lowLevelError; req->_errorTrigger = new SafeTimer(this); connect(req->_errorTrigger, SIGNAL(timeout()), SLOT(doError())); req->_errorTrigger->setSingleShot(true); _requestsByTimer.insert(req->_errorTrigger, req); req->_errorTrigger->start(); } void removeRequest(Request *req) { foreach(const SubRecord *srec, req->_subRecords) _requestsByRecId.remove(srec->_id); if(req->_errorTrigger) _requestsByTimer.remove(req->_errorTrigger); if(req->_sn_read) _requestsBySocket.remove(req->_sn_read); _requestsById.remove(req->_id); delete req; } int regIdForRecId(int rec_id) const { Request *req = _requestsByRecId.value(rec_id); if(req) return req->_id; return -1; } int query(const QByteArray &name, int qType) { int id = idManager.reserveId(); Request *req = new Request(this); req->_type = Request::Query; req->_id = id; req->_sdref = new ServiceRef; DNSServiceErrorType err = DNSServiceQueryRecord( req->_sdref->data(), kDNSServiceFlagsLongLivedQuery, 0, name.constData(), qType, kDNSServiceClass_IN, cb_queryRecordReply, req); if(err != kDNSServiceErr_NoError) { setDelayedError(req, LowLevelError( "DNSServiceQueryRecord", err)); return id; } req->_sdref->setInitialized(); int sockfd = DNSServiceRefSockFD(*(req->_sdref->data())); if(sockfd == -1) { setDelayedError(req, LowLevelError( "DNSServiceRefSockFD", -1)); return id; } req->_sockfd = sockfd; req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this); connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated())); _requestsById.insert(id, req); _requestsBySocket.insert(req->_sn_read, req); return id; } int browse(const QByteArray &serviceType, const QByteArray &domain) { int id = idManager.reserveId(); Request *req = new Request(this); req->_type = Request::Browse; req->_id = id; req->_sdref = new ServiceRef; DNSServiceErrorType err = DNSServiceBrowse( req->_sdref->data(), 0, 0, serviceType.constData(), !domain.isEmpty() ? domain.constData() : NULL, cb_browseReply, req); if(err != kDNSServiceErr_NoError) { setDelayedError(req, LowLevelError( "DNSServiceBrowse", err)); return id; } req->_sdref->setInitialized(); int sockfd = DNSServiceRefSockFD(*(req->_sdref->data())); if(sockfd == -1) { setDelayedError(req, LowLevelError( "DNSServiceRefSockFD", -1)); return id; } req->_sockfd = sockfd; req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this); connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated())); _requestsById.insert(id, req); _requestsBySocket.insert(req->_sn_read, req); return id; } int resolve(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain) { int id = idManager.reserveId(); Request *req = new Request(this); req->_type = Request::Resolve; req->_id = id; req->_sdref = new ServiceRef; DNSServiceErrorType err = DNSServiceResolve( req->_sdref->data(), 0, 0, serviceName.constData(), serviceType.constData(), domain.constData(), (DNSServiceResolveReply)cb_resolveReply, req); if(err != kDNSServiceErr_NoError) { setDelayedError(req, LowLevelError( "DNSServiceResolve", err)); return id; } req->_sdref->setInitialized(); int sockfd = DNSServiceRefSockFD(*(req->_sdref->data())); if(sockfd == -1) { setDelayedError(req, LowLevelError( "DNSServiceRefSockFD", -1)); return id; } req->_sockfd = sockfd; req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this); connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated())); _requestsById.insert(id, req); _requestsBySocket.insert(req->_sn_read, req); return id; } int reg(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain, int port, const QByteArray &txtRecord) { int id = idManager.reserveId(); Request *req = new Request(this); req->_type = Request::Reg; req->_id = id; if(port < 1 || port > 0xffff) { setDelayedError(req, LowLevelError()); return id; } uint16_t sport = port; sport = htons(sport); req->_sdref = new ServiceRef; DNSServiceErrorType err = DNSServiceRegister( req->_sdref->data(), kDNSServiceFlagsNoAutoRename, 0, serviceName.constData(), serviceType.constData(), domain.constData(), NULL, sport, txtRecord.size(), txtRecord.data(), cb_regReply, req); if(err != kDNSServiceErr_NoError) { setDelayedError(req, LowLevelError( "DNSServiceRegister", err)); return id; } req->_sdref->setInitialized(); int sockfd = DNSServiceRefSockFD(*(req->_sdref->data())); if(sockfd == -1) { setDelayedError(req, LowLevelError( "DNSServiceRefSockFD", -1)); return id; } req->_sockfd = sockfd; req->_sn_read = new SafeSocketNotifier(sockfd, QSocketNotifier::Read, this); connect(req->_sn_read, SIGNAL(activated(int)), SLOT(sn_activated())); _requestsById.insert(id, req); _requestsBySocket.insert(req->_sn_read, req); return id; } int recordAdd(int reg_id, const Record &rec, LowLevelError *lowLevelError) { Request *req = _requestsById.value(reg_id); if(!req) { if(lowLevelError) *lowLevelError = LowLevelError(); return -1; } RecordRef *recordRef = new RecordRef; DNSServiceErrorType err = DNSServiceAddRecord( *(req->_sdref->data()), recordRef->data(), 0, rec.rrtype, rec.rdata.size(), rec.rdata.data(), rec.ttl); if(err != kDNSServiceErr_NoError) { if(lowLevelError) *lowLevelError = LowLevelError("DNSServiceAddRecord", err); delete recordRef; return -1; } int id = idManager.reserveId(); SubRecord *srec = new SubRecord(this); srec->_id = id; srec->_sdref = recordRef; req->_subRecords += srec; _requestsByRecId.insert(id, req); return id; } bool recordUpdate(int reg_id, int rec_id, const Record &rec, LowLevelError *lowLevelError) { Request *req = _requestsById.value(reg_id); if(!req) { if(lowLevelError) *lowLevelError = LowLevelError(); return false; } SubRecord *srec = 0; if(rec_id != -1) { int at = req->subRecordIndexById(rec_id); if(at == -1) { if(lowLevelError) *lowLevelError = LowLevelError(); return false; } srec = req->_subRecords[at]; } DNSServiceErrorType err = DNSServiceUpdateRecord( *(req->_sdref->data()), srec ? *(srec->_sdref->data()) : NULL, 0, rec.rdata.size(), rec.rdata.data(), rec.ttl); if(err != kDNSServiceErr_NoError) { if(lowLevelError) *lowLevelError = LowLevelError("DNSServiceUpdateRecord", err); return false; } return true; } void recordRemove(int rec_id) { Request *req = _requestsByRecId.value(rec_id); if(!req) return; // this can't fail int at = req->subRecordIndexById(rec_id); SubRecord *srec = req->_subRecords[at]; DNSServiceRemoveRecord(*(req->_sdref->data()), *(srec->_sdref->data()), 0); _requestsByRecId.remove(srec->_id); req->_subRecords.removeAt(at); delete srec; } void stop(int id) { Request *req = _requestsById.value(id); if(req) removeRequest(req); } private slots: void sn_activated() { SafeSocketNotifier *sn_read = (SafeSocketNotifier *)sender(); Request *req = _requestsBySocket.value(sn_read); if(!req) return; int id = req->_id; DNSServiceErrorType err = DNSServiceProcessResult(*(req->_sdref->data())); // do error if the above function returns an error, or if we // collected an error during a callback if(err != kDNSServiceErr_NoError || !req->_lowLevelError.func.isEmpty()) { LowLevelError lowLevelError; if(err != kDNSServiceErr_NoError) lowLevelError = LowLevelError("DNSServiceProcessResult", err); else lowLevelError = req->_lowLevelError; // reg conflict indicated via callback bool regConflict = false; if(req->_type == Request::Reg && !req->_lowLevelError.func.isEmpty()) regConflict = req->_regConflict; removeRequest(req); if(req->_type == Request::Query) { QDnsSd::QueryResult r; r.success = false; r.lowLevelError = lowLevelError; emit q->queryResult(id, r); } else if(req->_type == Request::Browse) { QDnsSd::BrowseResult r; r.success = false; r.lowLevelError = lowLevelError; emit q->browseResult(id, r); } else if(req->_type == Request::Resolve) { QDnsSd::ResolveResult r; r.success = false; r.lowLevelError = lowLevelError; emit q->resolveResult(id, r); } else // Reg { QDnsSd::RegResult r; r.success = false; if(regConflict) r.errorCode = QDnsSd::RegResult::ErrorConflict; else r.errorCode = QDnsSd::RegResult::ErrorGeneric; r.lowLevelError = lowLevelError; emit q->regResult(id, r); } return; } // handle success if(req->_type == Request::Query) { if(req->_doSignal) { QDnsSd::QueryResult r; r.success = true; r.records = req->_queryRecords; req->_queryRecords.clear(); req->_doSignal = false; emit q->queryResult(id, r); } } else if(req->_type == Request::Browse) { if(req->_doSignal) { QDnsSd::BrowseResult r; r.success = true; r.entries = req->_browseEntries; req->_browseEntries.clear(); req->_doSignal = false; emit q->browseResult(id, r); } } else if(req->_type == Request::Resolve) { if(req->_doSignal) { QDnsSd::ResolveResult r; r.success = true; r.fullName = req->_resolveFullName; r.hostTarget = req->_resolveHost; r.port = req->_resolvePort; r.txtRecord = req->_resolveTxtRecord; req->_doSignal = false; // there is only one response removeRequest(req); emit q->resolveResult(id, r); } } else // Reg { if(req->_doSignal) { QDnsSd::RegResult r; r.success = true; r.domain = req->_regDomain; req->_doSignal = false; emit q->regResult(id, r); } } } void doError() { SafeTimer *t = (SafeTimer *)sender(); Request *req = _requestsByTimer.value(t); if(!req) return; int id = req->_id; int type = req->_type; removeRequest(req); if(type == Request::Query) { QDnsSd::QueryResult r; r.success = false; r.lowLevelError = req->_lowLevelError; emit q->queryResult(id, r); } else if(type == Request::Browse) { QDnsSd::BrowseResult r; r.success = false; r.lowLevelError = req->_lowLevelError; emit q->browseResult(id, r); } else if(type == Request::Resolve) { QDnsSd::ResolveResult r; r.success = false; r.lowLevelError = req->_lowLevelError; emit q->resolveResult(id, r); } else // Reg { QDnsSd::RegResult r; r.success = false; r.errorCode = QDnsSd::RegResult::ErrorGeneric; r.lowLevelError = req->_lowLevelError; emit q->regResult(id, r); } } private: static void cb_queryRecordReply(DNSServiceRef ref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context) { Q_UNUSED(ref); Q_UNUSED(interfaceIndex); Q_UNUSED(rrclass); Request *req = static_cast(context); req->_self->handle_queryRecordReply(req, flags, errorCode, fullname, rrtype, rdlen, (const char *)rdata, ttl); } static void cb_browseReply(DNSServiceRef ref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) { Q_UNUSED(ref); Q_UNUSED(interfaceIndex); Request *req = static_cast(context); req->_self->handle_browseReply(req, flags, errorCode, serviceName, regtype, replyDomain); } static void cb_resolveReply(DNSServiceRef ref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) { Q_UNUSED(ref); Q_UNUSED(flags); Q_UNUSED(interfaceIndex); Request *req = static_cast(context); req->_self->handle_resolveReply(req, errorCode, fullname, hosttarget, port, txtLen, txtRecord); } static void cb_regReply(DNSServiceRef ref, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { Q_UNUSED(ref); Q_UNUSED(flags); Request *req = static_cast(context); req->_self->handle_regReply(req, errorCode, name, regtype, domain); } void handle_queryRecordReply(Request *req, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint16_t ttl) { if(errorCode != kDNSServiceErr_NoError) { req->_doSignal = true; req->_lowLevelError = LowLevelError("DNSServiceQueryRecordReply", errorCode); return; } QDnsSd::Record rec; rec.added = (flags & kDNSServiceFlagsAdd) ? true: false; rec.name = QByteArray(fullname); rec.rrtype = rrtype; rec.rdata = QByteArray(rdata, rdlen); rec.ttl = ttl; req->_queryRecords += rec; if(!(flags & kDNSServiceFlagsMoreComing)) req->_doSignal = true; } void handle_browseReply(Request *req, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain) { if(errorCode != kDNSServiceErr_NoError) { req->_doSignal = true; req->_lowLevelError = LowLevelError("DNSServiceBrowseReply", errorCode); return; } QDnsSd::BrowseEntry e; e.added = (flags & kDNSServiceFlagsAdd) ? true: false; e.serviceName = QByteArray(serviceName); e.serviceType = QByteArray(regtype); e.replyDomain = QByteArray(replyDomain); req->_browseEntries += e; if(!(flags & kDNSServiceFlagsMoreComing)) req->_doSignal = true; } void handle_resolveReply(Request *req, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord) { if(errorCode != kDNSServiceErr_NoError) { req->_doSignal = true; req->_lowLevelError = LowLevelError("DNSServiceResolveReply", errorCode); return; } req->_resolveFullName = QByteArray(fullname); req->_resolveHost = QByteArray(hosttarget); req->_resolvePort = ntohs(port); req->_resolveTxtRecord = QByteArray((const char *)txtRecord, txtLen); req->_doSignal = true; } void handle_regReply(Request *req, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) { Q_UNUSED(name); Q_UNUSED(regtype); if(errorCode != kDNSServiceErr_NoError) { req->_doSignal = true; req->_lowLevelError = LowLevelError("DNSServiceRegisterReply", errorCode); if(errorCode == kDNSServiceErr_NameConflict) req->_regConflict = true; else req->_regConflict = false; return; } req->_regDomain = QByteArray(domain); req->_doSignal = true; } }; QDnsSd::QDnsSd(QObject *parent) : QObject(parent) { d = new Private(this); } QDnsSd::~QDnsSd() { delete d; } int QDnsSd::query(const QByteArray &name, int qType) { return d->query(name, qType); } int QDnsSd::browse(const QByteArray &serviceType, const QByteArray &domain) { return d->browse(serviceType, domain); } int QDnsSd::resolve(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain) { return d->resolve(serviceName, serviceType, domain); } int QDnsSd::reg(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain, int port, const QByteArray &txtRecord) { return d->reg(serviceName, serviceType, domain, port, txtRecord); } int QDnsSd::recordAdd(int reg_id, const Record &rec, LowLevelError *lowLevelError) { return d->recordAdd(reg_id, rec, lowLevelError); } bool QDnsSd::recordUpdate(int rec_id, const Record &rec, LowLevelError *lowLevelError) { int reg_id = d->regIdForRecId(rec_id); if(reg_id == -1) return false; return d->recordUpdate(reg_id, rec_id, rec, lowLevelError); } bool QDnsSd::recordUpdateTxt(int reg_id, const QByteArray &txtRecord, quint32 ttl, LowLevelError *lowLevelError) { Record rec; rec.rrtype = kDNSServiceType_TXT; rec.rdata = txtRecord; rec.ttl = ttl; return d->recordUpdate(reg_id, -1, rec, lowLevelError); } void QDnsSd::recordRemove(int rec_id) { d->recordRemove(rec_id); } void QDnsSd::stop(int id) { d->stop(id); } QByteArray QDnsSd::createTxtRecord(const QList &strings) { // split into var/val and validate QList vars; QList vals; // null = no value, empty = empty value foreach(const QByteArray &i, strings) { QByteArray var; QByteArray val; int n = i.indexOf('='); if(n != -1) { var = i.mid(0, n); val = i.mid(n + 1); } else var = i; for(int n = 0; n < var.size(); ++n) { unsigned char c = var[n]; if(c < 0x20 || c > 0x7e) return QByteArray(); } vars += var; vals += val; } TXTRecordRef ref; QByteArray buf(256, 0); TXTRecordCreate(&ref, buf.size(), buf.data()); for(int n = 0; n < vars.count(); ++n) { int valueSize = vals[n].size(); char *value; if(!vals[n].isNull()) value = vals[n].data(); else value = 0; DNSServiceErrorType err = TXTRecordSetValue(&ref, vars[n].data(), valueSize, value); if(err != kDNSServiceErr_NoError) { TXTRecordDeallocate(&ref); return QByteArray(); } } QByteArray out((const char *)TXTRecordGetBytesPtr(&ref), TXTRecordGetLength(&ref)); TXTRecordDeallocate(&ref); return out; } QList QDnsSd::parseTxtRecord(const QByteArray &txtRecord) { QList out; int count = TXTRecordGetCount(txtRecord.size(), txtRecord.data()); for(int n = 0; n < count; ++n) { QByteArray keyBuf(256, 0); uint8_t valueLen; const void *value; DNSServiceErrorType err = TXTRecordGetItemAtIndex( txtRecord.size(), txtRecord.data(), n, keyBuf.size(), keyBuf.data(), &valueLen, &value); if(err != kDNSServiceErr_NoError) return QList(); keyBuf.resize(qstrlen(keyBuf.data())); QByteArray entry = keyBuf; if(value) { entry += '='; entry += QByteArray((const char *)value, valueLen); } out += entry; } return out; } #include "qdnssd.moc" psi-0.14/iris/src/irisnet/appledns/sdtest.pro0000644000175000017500000000021411305557616017411 0ustar janjanCONFIG += console CONFIG -= app_bundle QT -= gui QT += network HEADERS += qdnssd.h SOURCES += qdnssd.cpp sdtest.cpp !mac:LIBS += -ldns_sd psi-0.14/iris/src/irisnet/appledns/qdnssd.h0000644000175000017500000000701311305557616017032 0ustar janjan/* * Copyright (C) 2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef QDNSSD_H #define QDNSSD_H #include #include #include // DOR-compliant class QDnsSd : public QObject { Q_OBJECT public: class LowLevelError { public: QString func; int code; LowLevelError() : code(0) { } LowLevelError(const QString &_func, int _code) : func(_func), code(_code) { } }; class Record { public: bool added; // only used by QueryResult QByteArray name; int rrtype; QByteArray rdata; quint32 ttl; }; class BrowseEntry { public: bool added; QByteArray serviceName; // these may be different from request, see dns_sd docs QByteArray serviceType; QByteArray replyDomain; }; class QueryResult { public: bool success; LowLevelError lowLevelError; QList records; }; class BrowseResult { public: bool success; LowLevelError lowLevelError; QList entries; }; class ResolveResult { public: bool success; LowLevelError lowLevelError; QByteArray fullName; QByteArray hostTarget; int port; // host byte-order QByteArray txtRecord; }; class RegResult { public: enum Error { ErrorGeneric, ErrorConflict }; bool success; Error errorCode; LowLevelError lowLevelError; QByteArray domain; }; QDnsSd(QObject *parent = 0); ~QDnsSd(); int query(const QByteArray &name, int qType); // domain may be empty int browse(const QByteArray &serviceType, const QByteArray &domain); int resolve(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain); // domain may be empty int reg(const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain, int port, const QByteArray &txtRecord); // return -1 on error, else a record id int recordAdd(int reg_id, const Record &rec, LowLevelError *lowLevelError = 0); bool recordUpdate(int rec_id, const Record &rec, LowLevelError *lowLevelError = 0); bool recordUpdateTxt(int reg_id, const QByteArray &txtRecord, quint32 ttl, LowLevelError *lowLevelError = 0); void recordRemove(int rec_id); void stop(int id); // return empty array on error static QByteArray createTxtRecord(const QList &strings); // return empty list on error (note that it is possible to have a // txt record with no entries, but in that case txtRecord will be // empty and so you shouldn't call this function) static QList parseTxtRecord(const QByteArray &txtRecord); signals: void queryResult(int id, const QDnsSd::QueryResult &result); void browseResult(int id, const QDnsSd::BrowseResult &result); void resolveResult(int id, const QDnsSd::ResolveResult &result); void regResult(int id, const QDnsSd::RegResult &result); private: class Private; friend class Private; Private *d; }; #endif psi-0.14/iris/src/irisnet/appledns/appledns.pro0000644000175000017500000000035211305557616017714 0ustar janjanIRIS_BASE = ../../.. include(../../libbase.pri) TEMPLATE = lib CONFIG += plugin QT -= gui DESTDIR = $$IRIS_BASE/plugins VERSION = 1.0.0 INCLUDEPATH *= $$PWD/../corelib LIBS += -L$$IRIS_BASE/lib -lirisnetcore include(appledns.pri) psi-0.14/iris/src/irisnet/appledns/sdtest.cpp0000644000175000017500000002525211305557616017404 0ustar janjan/* * Copyright (C) 2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include #include #include "qdnssd.h" // for ntohl #ifdef Q_OS_WIN # include #else # include #endif class Command { public: enum Type { Query, Browse, Resolve, Reg }; Type type; QString name; // query, resolve, reg int rtype; // query QString stype; // browse, resolve, reg QString domain; // browse, resolve, reg int port; // reg QByteArray txtRecord; // reg int id; int dnsId; bool error; bool done; // for resolve Command() : error(false), done(false) { } }; static QString nameToString(const QByteArray &in) { QStringList parts; int at = 0; while(at < in.size()) { int len = in[at++]; parts += QString::fromUtf8(in.mid(at, len)); at += len; } return parts.join("."); } static QString recordToDesc(const QDnsSd::Record &rec) { QString desc; if(rec.rrtype == 1) // A { quint32 *p = (quint32 *)rec.rdata.data(); desc = QHostAddress(ntohl(*p)).toString(); } else if(rec.rrtype == 28) // AAAA { desc = QHostAddress((quint8 *)rec.rdata.data()).toString(); } else if(rec.rrtype == 12) // PTR { desc = QString("[%1]").arg(nameToString(rec.rdata)); } else desc = QString("%1 bytes").arg(rec.rdata.size()); return desc; } static QStringList txtRecordToStringList(const QByteArray &rdata) { QList txtEntries = QDnsSd::parseTxtRecord(rdata); if(txtEntries.isEmpty()) return QStringList(); QStringList out; foreach(const QByteArray &entry, txtEntries) out += QString::fromUtf8(entry); return out; } static void printIndentedTxt(const QByteArray &txtRecord) { QStringList list = txtRecordToStringList(txtRecord); if(!list.isEmpty()) { foreach(const QString &s, list) printf(" %s\n", qPrintable(s)); } else printf(" (TXT parsing error)\n"); } class App : public QObject { Q_OBJECT public: QList commands; QDnsSd *dns; App() { dns = new QDnsSd(this); connect(dns, SIGNAL(queryResult(int, const QDnsSd::QueryResult &)), SLOT(dns_queryResult(int, const QDnsSd::QueryResult &))); connect(dns, SIGNAL(browseResult(int, const QDnsSd::BrowseResult &)), SLOT(dns_browseResult(int, const QDnsSd::BrowseResult &))); connect(dns, SIGNAL(resolveResult(int, const QDnsSd::ResolveResult &)), SLOT(dns_resolveResult(int, const QDnsSd::ResolveResult &))); connect(dns, SIGNAL(regResult(int, const QDnsSd::RegResult &)), SLOT(dns_regResult(int, const QDnsSd::RegResult &))); } public slots: void start() { for(int n = 0; n < commands.count(); ++n) { Command &c = commands[n]; c.id = n; if(c.type == Command::Query) { printf("%2d: Query name=[%s], type=%d ...\n", c.id, qPrintable(c.name), c.rtype); c.dnsId = dns->query(c.name.toUtf8(), c.rtype); } else if(c.type == Command::Browse) { printf("%2d: Browse type=[%s]", c.id, qPrintable(c.stype)); if(!c.domain.isEmpty()) printf(", domain=[%s]", qPrintable(c.domain)); printf(" ...\n"); c.dnsId = dns->browse(c.stype.toUtf8(), c.domain.toUtf8()); } else if(c.type == Command::Resolve) { printf("%2d: Resolve name=[%s], type=[%s], domain=[%s] ...\n", c.id, qPrintable(c.name), qPrintable(c.stype), qPrintable(c.domain)); c.dnsId = dns->resolve(c.name.toUtf8(), c.stype.toUtf8(), c.domain.toUtf8()); } else if(c.type == Command::Reg) { printf("%2d: Register name=[%s], type=[%s]", c.id, qPrintable(c.name), qPrintable(c.stype)); if(!c.domain.isEmpty()) printf(", domain=[%s]", qPrintable(c.domain)); printf(", port=%d ...\n", c.port); if(!c.txtRecord.isEmpty()) printIndentedTxt(c.txtRecord); c.dnsId = dns->reg(c.name.toUtf8(), c.stype.toUtf8(), c.domain.toUtf8(), c.port, c.txtRecord); } } } signals: void quit(); private: int cmdIdToCmdIndex(int cmdId) { for(int n = 0; n < commands.count(); ++n) { const Command &c = commands[n]; if(c.id == cmdId) return n; } return -1; } int dnsIdToCmdIndex(int dnsId) { for(int n = 0; n < commands.count(); ++n) { const Command &c = commands[n]; if(c.dnsId == dnsId) return n; } return -1; } void tryQuit() { // quit if there are nothing but errors or completed resolves bool doQuit = true; foreach(const Command &c, commands) { if(c.error || (c.type == Command::Resolve && c.done)) continue; doQuit = false; break; } if(doQuit) emit quit(); } private slots: void dns_queryResult(int id, const QDnsSd::QueryResult &result) { int at = dnsIdToCmdIndex(id); Command &c = commands[at]; if(!result.success) { printf("%2d: Error.", c.id); if(!result.lowLevelError.func.isEmpty()) printf(" (%s, %d)", qPrintable(result.lowLevelError.func), result.lowLevelError.code); printf("\n"); c.error = true; tryQuit(); return; } foreach(const QDnsSd::Record &rec, result.records) { if(rec.added) { printf("%2d: Added: %s, ttl=%d\n", c.id, qPrintable(recordToDesc(rec)), rec.ttl); if(rec.rrtype == 16) printIndentedTxt(rec.rdata); } else printf("%2d: Removed: %s, ttl=%d\n", c.id, qPrintable(recordToDesc(rec)), rec.ttl); } } void dns_browseResult(int id, const QDnsSd::BrowseResult &result) { int at = dnsIdToCmdIndex(id); Command &c = commands[at]; if(!result.success) { printf("%2d: Error.", c.id); if(!result.lowLevelError.func.isEmpty()) printf(" (%s, %d)", qPrintable(result.lowLevelError.func), result.lowLevelError.code); printf("\n"); c.error = true; tryQuit(); return; } foreach(const QDnsSd::BrowseEntry &e, result.entries) { if(e.added) printf("%2d: Added: [%s] [%s] [%s]\n", c.id, qPrintable(QString::fromUtf8(e.serviceName)), qPrintable(QString::fromUtf8(e.serviceType)), qPrintable(QString::fromUtf8(e.replyDomain))); else printf("%2d: Removed: [%s]\n", c.id, qPrintable(QString::fromUtf8(e.serviceName))); } } void dns_resolveResult(int id, const QDnsSd::ResolveResult &result) { int at = dnsIdToCmdIndex(id); Command &c = commands[at]; if(!result.success) { printf("%2d: Error.", c.id); if(!result.lowLevelError.func.isEmpty()) printf(" (%s, %d)", qPrintable(result.lowLevelError.func), result.lowLevelError.code); printf("\n"); c.error = true; tryQuit(); return; } printf("%2d: Result: host=[%s] port=%d\n", c.id, qPrintable(QString::fromUtf8(result.hostTarget)), result.port); if(!result.txtRecord.isEmpty()) printIndentedTxt(result.txtRecord); c.done = true; tryQuit(); } void dns_regResult(int id, const QDnsSd::RegResult &result) { int at = dnsIdToCmdIndex(id); Command &c = commands[at]; if(!result.success) { QString errstr; if(result.errorCode == QDnsSd::RegResult::ErrorConflict) errstr = "Conflict"; else errstr = "Generic"; printf("%2d: Error (%s).", c.id, qPrintable(errstr)); if(!result.lowLevelError.func.isEmpty()) printf(" (%s, %d)", qPrintable(result.lowLevelError.func), result.lowLevelError.code); printf("\n"); c.error = true; tryQuit(); return; } printf("%2d: Registered: domain=[%s]\n", c.id, qPrintable(QString::fromUtf8(result.domain))); } }; #include "sdtest.moc" void usage() { printf("usage: sdtest [[command] (command) ...]\n"); printf(" options: --txt=str0,...,strn\n"); printf("\n"); printf(" q=name,type# query for a record\n"); printf(" b=type(,domain) browse for services\n"); printf(" r=name,type,domain resolve a service\n"); printf(" e=name,type,port(,domain) register a service\n"); printf("\n"); } int main(int argc, char **argv) { QCoreApplication qapp(argc, argv); QStringList args = qapp.arguments(); args.removeFirst(); if(args.count() < 1) { usage(); return 1; } // options QStringList txt; for(int n = 0; n < args.count(); ++n) { QString s = args[n]; if(!s.startsWith("--")) continue; QString var; QString val; int x = s.indexOf('='); if(x != -1) { var = s.mid(2, x - 2); val = s.mid(x + 1); } else { var = s.mid(2); } bool known = true; if(var == "txt") { txt = val.split(','); } else known = false; if(known) { args.removeAt(n); --n; // adjust position } } // commands QList commands; for(int n = 0; n < args.count(); ++n) { QString str = args[n]; int n = str.indexOf('='); if(n == -1) { printf("Error: bad format of command.\n"); return 1; } QString type = str.mid(0, n); QString rest = str.mid(n + 1); QStringList parts = rest.split(','); if(type == "q") { if(parts.count() < 2) { usage(); return 1; } Command c; c.type = Command::Query; c.name = parts[0]; c.rtype = parts[1].toInt(); commands += c; } else if(type == "b") { if(parts.count() < 1) { usage(); return 1; } Command c; c.type = Command::Browse; c.stype = parts[0]; if(parts.count() >= 2) c.domain = parts[1]; commands += c; } else if(type == "r") { if(parts.count() < 3) { usage(); return 1; } Command c; c.type = Command::Resolve; c.name = parts[0]; c.stype = parts[1]; c.domain = parts[2]; commands += c; } else if(type == "e") { if(parts.count() < 3) { usage(); return 1; } Command c; c.type = Command::Reg; c.name = parts[0]; c.stype = parts[1]; c.port = parts[2].toInt(); if(parts.count() >= 4) c.domain = parts[3]; if(!txt.isEmpty()) { QList strings; foreach(const QString &str, txt) strings += str.toUtf8(); QByteArray txtRecord = QDnsSd::createTxtRecord(strings); if(txtRecord.isEmpty()) { printf("Error: failed to create TXT record, input too large or invalid\n"); return 1; } c.txtRecord = txtRecord; } commands += c; } else { printf("Error: unknown command type '%s'.\n", qPrintable(type)); return 1; } } App app; app.commands = commands; QObject::connect(&app, SIGNAL(quit()), &qapp, SLOT(quit())); QTimer::singleShot(0, &app, SLOT(start())); qapp.exec(); return 0; } psi-0.14/iris/src/irisnet/appledns/appledns.cpp0000644000175000017500000005410711305557616017705 0ustar janjan/* * Copyright (C) 2007 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "irisnetplugin.h" #include #include #include "qdnssd.h" // for ntohl #ifdef Q_OS_WIN # include #else # include #endif static QByteArray nameToDottedString(const QByteArray &in) { QByteArray out; int at = 0; while(at < in.size()) { int len = in[at++]; if(len > 0) out += in.mid(at, len); out += '.'; at += len; } return out; } static QMap textsToAttribs(const QList &texts) { QMap out; foreach(const QByteArray &a, texts) { QString key; QByteArray value; int x = a.indexOf('='); if(x != -1) { key = QString::fromLatin1(a.mid(0, x)); value = a.mid(x + 1); } else { key = QString::fromLatin1(a); } out.insert(key, value); } return out; } static QByteArray attribsToTxtRecord(const QMap &attribs) { QList texts; QMapIterator it(attribs); while(it.hasNext()) { it.next(); QByteArray line = it.key().toLatin1() + '=' + it.value(); texts += line; } return QDnsSd::createTxtRecord(texts); } // returns a list of 3 items, or an empty list on error static QList nameToInstanceParts(const QByteArray &name) { // FIXME: improve this parsing... (what about escaping??) int at = name.indexOf('.'); QByteArray sname = name.mid(0, at); ++at; int next = name.indexOf('.', at); ++next; next = name.indexOf('.', next); QByteArray stype = name.mid(at, next - at); at = next + 1; QByteArray sdomain = name.mid(at); QList out; out += sname; out += stype; out += sdomain; return out; } static XMPP::NameRecord importQDnsSdRecord(const QDnsSd::Record &in) { XMPP::NameRecord out; switch(in.rrtype) { case 1: // A { quint32 *p = (quint32 *)in.rdata.data(); out.setAddress(QHostAddress(ntohl(*p))); } break; case 28: // AAAA { out.setAddress(QHostAddress((quint8 *)in.rdata.data())); } break; case 12: // PTR { out.setPtr(nameToDottedString(in.rdata)); } break; case 10: // NULL { out.setNull(in.rdata); } break; case 16: // TXT { QList txtEntries = QDnsSd::parseTxtRecord(in.rdata); if(txtEntries.isEmpty()) return out; out.setTxt(txtEntries); } break; default: // unsupported { return out; } } out.setOwner(in.name); out.setTtl(in.ttl); return out; } namespace { class QDnsSdDelegate { public: virtual ~QDnsSdDelegate() { } virtual void dns_queryResult(int id, const QDnsSd::QueryResult &result) { Q_UNUSED(id); Q_UNUSED(result); } virtual void dns_browseResult(int id, const QDnsSd::BrowseResult &result) { Q_UNUSED(id); Q_UNUSED(result); } virtual void dns_resolveResult(int id, const QDnsSd::ResolveResult &result) { Q_UNUSED(id); Q_UNUSED(result); } virtual void dns_regResult(int id, const QDnsSd::RegResult &result) { Q_UNUSED(id); Q_UNUSED(result); } }; class IdManager { private: QSet set; int at; inline void bump_at() { if(at == 0x7fffffff) at = 0; else ++at; } public: IdManager() : at(0) { } int reserveId() { while(1) { if(!set.contains(at)) { int id = at; set.insert(id); bump_at(); return id; } bump_at(); } } void releaseId(int id) { set.remove(id); } }; } //---------------------------------------------------------------------------- // AppleProvider //---------------------------------------------------------------------------- class AppleProvider : public XMPP::IrisNetProvider { Q_OBJECT Q_INTERFACES(XMPP::IrisNetProvider); public: QDnsSd dns; QHash delegateById; AppleProvider() : dns(this) { connect(&dns, SIGNAL(queryResult(int, const QDnsSd::QueryResult &)), SLOT(dns_queryResult(int, const QDnsSd::QueryResult &))); connect(&dns, SIGNAL(browseResult(int, const QDnsSd::BrowseResult &)), SLOT(dns_browseResult(int, const QDnsSd::BrowseResult &))); connect(&dns, SIGNAL(resolveResult(int, const QDnsSd::ResolveResult &)), SLOT(dns_resolveResult(int, const QDnsSd::ResolveResult &))); connect(&dns, SIGNAL(regResult(int, const QDnsSd::RegResult &)), SLOT(dns_regResult(int, const QDnsSd::RegResult &))); } virtual XMPP::NameProvider *createNameProviderInternet(); virtual XMPP::NameProvider *createNameProviderLocal(); virtual XMPP::ServiceProvider *createServiceProvider(); int query(QDnsSdDelegate *p, const QByteArray &name, int qType) { int id = dns.query(name, qType); delegateById[id] = p; return id; } int browse(QDnsSdDelegate *p, const QByteArray &serviceType, const QByteArray &domain) { int id = dns.browse(serviceType, domain); delegateById[id] = p; return id; } int resolve(QDnsSdDelegate *p, const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain) { int id = dns.resolve(serviceName, serviceType, domain); delegateById[id] = p; return id; } int reg(QDnsSdDelegate *p, const QByteArray &serviceName, const QByteArray &serviceType, const QByteArray &domain, int port, const QByteArray &txtRecord) { int id = dns.reg(serviceName, serviceType, domain, port, txtRecord); delegateById[id] = p; return id; } void stop(int id) { delegateById.remove(id); dns.stop(id); } void stop_all(QDnsSdDelegate *p) { QList ids; QHashIterator it(delegateById); while(it.hasNext()) { it.next(); if(it.value() == p) ids += it.key(); } foreach(int id, ids) stop(id); } private slots: void dns_queryResult(int id, const QDnsSd::QueryResult &result) { delegateById[id]->dns_queryResult(id, result); } void dns_browseResult(int id, const QDnsSd::BrowseResult &result) { delegateById[id]->dns_browseResult(id, result); } void dns_resolveResult(int id, const QDnsSd::ResolveResult &result) { delegateById[id]->dns_resolveResult(id, result); } void dns_regResult(int id, const QDnsSd::RegResult &result) { delegateById[id]->dns_regResult(id, result); } }; //---------------------------------------------------------------------------- // AppleBrowseSession //---------------------------------------------------------------------------- // only use this class for a single browse. if you want to browse again, // create a new object. class AppleBrowse : public QObject, public QDnsSdDelegate { Q_OBJECT public: AppleProvider *global; int browse_id; QList instances; QHash pendingByQueryId; // waiting for TXT AppleBrowse(AppleProvider *_global, QObject *parent = 0) : QObject(parent), global(_global), browse_id(-1) { connect(this, SIGNAL(unavailable_p(const XMPP::ServiceInstance &)), SIGNAL(unavailable(const XMPP::ServiceInstance &))); } ~AppleBrowse() { global->stop_all(this); } void browse(const QString &type, const QString &domain) { browse_id = global->browse(this, type.toUtf8(), domain.toUtf8()); } signals: void available(const XMPP::ServiceInstance &instance); void unavailable(const XMPP::ServiceInstance &instance); void error(); // emit delayed void unavailable_p(const XMPP::ServiceInstance &instance); protected: virtual void dns_browseResult(int id, const QDnsSd::BrowseResult &result) { Q_UNUSED(id); if(!result.success) { emit error(); return; } foreach(const QDnsSd::BrowseEntry &e, result.entries) { XMPP::ServiceInstance si(e.serviceName, e.serviceType, e.replyDomain, QMap()); if(e.added) { int query_id = global->query(this, si.name(), 16); // 16 == TXT pendingByQueryId[query_id] = si.name(); } else // removed { // emit these queued for SS. no worry of SR since // the browse operation is not cancellable. for(int n = 0; n < instances.count(); ++n) { const XMPP::ServiceInstance &i = instances[n]; if(i.name() == si.name()) { emit unavailable_p(i); instances.removeAt(n); --n; // adjust position } } } } } virtual void dns_queryResult(int id, const QDnsSd::QueryResult &result) { if(!result.success) { // if we get here, then it means we received a browse // entry, but could not fetch its TXT record. if // that happens, cancel the query and drop the // browse entry. global->stop(id); pendingByQueryId.remove(id); return; } // qdnssd guarantees at least one answer Q_ASSERT(!result.records.isEmpty()); // only the first entry matters, and it must be an added TXT if(!result.records[0].added || result.records[0].rrtype != 16) return; // we only care about one answer QByteArray name = pendingByQueryId[id]; QList parts = nameToInstanceParts(name); if(parts.isEmpty()) { // TODO: error Q_ASSERT(0); } global->stop(id); pendingByQueryId.remove(id); XMPP::NameRecord rec = importQDnsSdRecord(result.records[0]); // bad answer? if(rec.isNull()) return; QMap attribs = textsToAttribs(rec.texts()); // FIXME: conversion/escaping? XMPP::ServiceInstance si(QString::fromUtf8(parts[0]), QString::fromUtf8(parts[1]), QString::fromUtf8(parts[2]), attribs); // does qdnssd guarantee we won't receive dups? bool found = false; foreach(const XMPP::ServiceInstance &i, instances) { if(i.name() == si.name()) { found = true; break; } } Q_ASSERT(!found); instances += si; emit available(si); } }; //---------------------------------------------------------------------------- // AppleBrowseLookup //---------------------------------------------------------------------------- // only use this class for a single lookup. if you want to lookup again, // create a new object. class AppleBrowseLookup : public QObject, public QDnsSdDelegate { Q_OBJECT public: AppleProvider *global; int resolve_id; XMPP::NameResolver nameResolverAaaa; XMPP::NameResolver nameResolverA; bool activeAaaa; bool activeA; QTimer waitTimer; QByteArray host; QHostAddress addr4; QHostAddress addr6; int port; AppleBrowseLookup(AppleProvider *_global, QObject *parent = 0) : QObject(parent), global(_global), resolve_id(-1), nameResolverAaaa(this), nameResolverA(this), activeAaaa(false), activeA(false), waitTimer(this) { connect(&nameResolverAaaa, SIGNAL(resultsReady(const QList &)), SLOT(nameAaaa_resultsReady(const QList &))); connect(&nameResolverAaaa, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(nameAaaa_error(XMPP::NameResolver::Error))); connect(&nameResolverA, SIGNAL(resultsReady(const QList &)), SLOT(nameA_resultsReady(const QList &))); connect(&nameResolverA, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(nameA_error(XMPP::NameResolver::Error))); connect(&waitTimer, SIGNAL(timeout()), SLOT(waitTimer_timeout())); waitTimer.setSingleShot(true); } ~AppleBrowseLookup() { global->stop_all(this); } void resolve(const QByteArray &instance, const QByteArray &type, const QByteArray &domain) { resolve_id = global->resolve(this, instance, type, domain); } signals: // emits at least 1 and at most 2 void finished(const QList &addrs, int port); void error(); protected: void dns_resolveResult(int id, const QDnsSd::ResolveResult &result) { // there is only one response, so deregister global->stop(id); if(!result.success) { emit error(); return; } host = result.hostTarget; port = result.port; activeAaaa = true; activeA = true; nameResolverAaaa.start(host, XMPP::NameRecord::Aaaa); nameResolverA.start(host, XMPP::NameRecord::A); waitTimer.start(500); // 500ms cut-off time, take what we have and run } private slots: void nameAaaa_resultsReady(const QList &results) { // nameresolver guarantees at least one result, and we only // care about the first addr6 = results[0].address(); activeAaaa = false; tryDone(); } void nameAaaa_error(XMPP::NameResolver::Error e) { Q_UNUSED(e); activeAaaa = false; tryDone(); } void nameA_resultsReady(const QList &results) { // nameresolver guarantees at least one result, and we only // care about the first addr4 = results[0].address(); activeA = false; tryDone(); } void nameA_error(XMPP::NameResolver::Error e) { Q_UNUSED(e); activeA = false; tryDone(); } void waitTimer_timeout() { tryDone(); } private: void tryDone() { // we're done if both resolves are inactive and we have no // results, or if the wait timer ends and we have at least // one result if(!activeAaaa && !activeA && addr6.isNull() && addr4.isNull()) { nameResolverAaaa.stop(); nameResolverA.stop(); waitTimer.stop(); emit error(); return; } if(!waitTimer.isActive() && (!addr6.isNull() || !addr4.isNull())) { nameResolverAaaa.stop(); nameResolverA.stop(); QList out; if(!addr4.isNull()) out += addr4; if(!addr6.isNull()) out += addr6; emit finished(out, port); } } }; //---------------------------------------------------------------------------- // AppleNameProvider //---------------------------------------------------------------------------- class AppleNameProvider : public XMPP::NameProvider, public QDnsSdDelegate { Q_OBJECT public: AppleProvider *global; AppleNameProvider(AppleProvider *parent) : NameProvider(parent), global(parent) { } ~AppleNameProvider() { global->stop_all(this); } virtual bool supportsLongLived() const { return true; } virtual bool supportsRecordType(int type) const { // all record types supported Q_UNUSED(type); return true; } virtual int resolve_start(const QByteArray &name, int qType, bool longLived) { Q_UNUSED(longLived); // query is always long lived return global->query(this, name, qType); } virtual void resolve_stop(int id) { global->stop(id); } protected: virtual void dns_queryResult(int id, const QDnsSd::QueryResult &result) { if(!result.success) { emit resolve_error(id, XMPP::NameResolver::ErrorGeneric); return; } QList results; foreach(const QDnsSd::Record &rec, result.records) { XMPP::NameRecord nr = importQDnsSdRecord(rec); // unsupported type if(nr.isNull()) continue; // if removed, ensure ttl is 0 if(!rec.added) nr.setTtl(0); results += nr; } emit resolve_resultsReady(id, results); } }; //---------------------------------------------------------------------------- // AppleServiceProvider //---------------------------------------------------------------------------- class AppleServiceProvider : public XMPP::ServiceProvider, public QDnsSdDelegate { Q_OBJECT public: class Browse { public: AppleServiceProvider *parent; int id; AppleBrowse *browse; Browse(AppleServiceProvider *_parent) : parent(_parent), id(-1), browse(0) { } ~Browse() { delete browse; parent->idManager.releaseId(id); } }; class Resolve { public: AppleServiceProvider *parent; int id; AppleBrowseLookup *resolve; Resolve(AppleServiceProvider *_parent) : parent(_parent), id(-1), resolve(0) { } ~Resolve() { delete resolve; parent->idManager.releaseId(id); } }; AppleProvider *global; QList browseList; QList resolveList; IdManager idManager; AppleServiceProvider(AppleProvider *parent) : ServiceProvider(parent), global(parent) { } ~AppleServiceProvider() { qDeleteAll(resolveList); qDeleteAll(browseList); global->stop_all(this); } int indexOfBrowseByBrowse(AppleBrowse *browse) const { for(int n = 0; n < browseList.count(); ++n) { if(browseList[n]->browse == browse) return n; } return -1; } int indexOfBrowseById(int id) const { for(int n = 0; n < browseList.count(); ++n) { if(browseList[n]->id == id) return n; } return -1; } int indexOfResolveByResolve(AppleBrowseLookup *resolve) const { for(int n = 0; n < resolveList.count(); ++n) { if(resolveList[n]->resolve == resolve) return n; } return -1; } int indexOfResolveById(int id) const { for(int n = 0; n < resolveList.count(); ++n) { if(resolveList[n]->id == id) return n; } return -1; } virtual int browse_start(const QString &type, const QString &domain) { Browse *b = new Browse(this); b->id = idManager.reserveId(); b->browse = new AppleBrowse(global, this); connect(b->browse, SIGNAL(available(const XMPP::ServiceInstance &)), SLOT(browse_available(const XMPP::ServiceInstance &))); connect(b->browse, SIGNAL(unavailable(const XMPP::ServiceInstance &)), SLOT(browse_unavailable(const XMPP::ServiceInstance &))); connect(b->browse, SIGNAL(error()), SLOT(browse_error())); browseList += b; b->browse->browse(type, domain); return b->id; } virtual void browse_stop(int id) { int at = indexOfBrowseById(id); if(at == -1) return; Browse *b = browseList[at]; browseList.removeAt(at); delete b; } virtual int resolve_start(const QByteArray &name) { QList parts = nameToInstanceParts(name); if(parts.isEmpty()) { // TODO: signal error rather than die Q_ASSERT(0); } Resolve *r = new Resolve(this); r->id = idManager.reserveId(); r->resolve = new AppleBrowseLookup(global, this); connect(r->resolve, SIGNAL(finished(const QList &)), SLOT(resolve_finished(const QList &))); connect(r->resolve, SIGNAL(error()), SLOT(resolve_error())); resolveList += r; r->resolve->resolve(parts[0], parts[1], parts[2]); return r->id; } virtual void resolve_stop(int id) { int at = indexOfResolveById(id); if(at == -1) return; Resolve *r = resolveList[at]; resolveList.removeAt(at); delete r; } virtual int publish_start(const QString &instance, const QString &type, int port, const QMap &attributes) { QByteArray txtRecord = attribsToTxtRecord(attributes); if(txtRecord.isEmpty()) { // TODO: signal error rather than die Q_ASSERT(0); } QString domain = "local"; // FIXME: conversion/escaping is probably wrong? return global->reg(this, instance.toUtf8(), type.toUtf8(), domain.toUtf8(), port, txtRecord); } virtual void publish_update(int id, const QMap &attributes) { // TODO: verify 'id' is valid. if not valid, then assert/return (don't do anything or signal error) QByteArray txtRecord = attribsToTxtRecord(attributes); if(txtRecord.isEmpty()) { // TODO: signal error rather than die Q_ASSERT(0); } if(global->dns.recordUpdateTxt(id, txtRecord, 4500)) { // FIXME: SR QMetaObject::invokeMethod(this, "publish_published", Qt::QueuedConnection, Q_ARG(int, id)); } else { // TODO: unpublish // FIXME: register meta type, SR QMetaObject::invokeMethod(this, "publish_error", Qt::QueuedConnection, Q_ARG(int, id), Q_ARG(XMPP::ServiceLocalPublisher::Error, XMPP::ServiceLocalPublisher::ErrorGeneric)); } } virtual void publish_stop(int id) { global->stop(id); } virtual int publish_extra_start(int pub_id, const XMPP::NameRecord &name) { // TODO Q_UNUSED(pub_id); Q_UNUSED(name); return 0; } virtual void publish_extra_update(int id, const XMPP::NameRecord &name) { // TODO Q_UNUSED(id); Q_UNUSED(name); } virtual void publish_extra_stop(int id) { // TODO Q_UNUSED(id); } // called by AppleProvider void dns_regResult(int id, const QDnsSd::RegResult &result) { // TODO Q_UNUSED(id); Q_UNUSED(result); } private slots: void browse_available(const XMPP::ServiceInstance &instance) { int at = indexOfBrowseByBrowse((AppleBrowse *)sender()); Q_ASSERT(at != -1); emit browse_instanceAvailable(browseList[at]->id, instance); } void browse_unavailable(const XMPP::ServiceInstance &instance) { int at = indexOfBrowseByBrowse((AppleBrowse *)sender()); Q_ASSERT(at != -1); emit browse_instanceUnavailable(browseList[at]->id, instance); } void browse_error() { int at = indexOfBrowseByBrowse((AppleBrowse *)sender()); Q_ASSERT(at != -1); Browse *b = browseList[at]; browseList.removeAt(at); int id = b->id; delete b; // FIXME: this looks weird, we should probably rename our // local function emit ServiceProvider::browse_error(id, XMPP::ServiceBrowser::ErrorGeneric); } void resolve_finished(const QList &addrs, int port) { int at = indexOfResolveByResolve((AppleBrowseLookup *)sender()); Q_ASSERT(at != -1); Resolve *r = resolveList[at]; resolveList.removeAt(at); int id = r->id; delete r; QList results; foreach(const QHostAddress &addr, addrs) { ResolveResult r; r.address = addr; r.port = port; results += r; } emit resolve_resultsReady(id, results); } void resolve_error() { int at = indexOfResolveByResolve((AppleBrowseLookup *)sender()); Q_ASSERT(at != -1); Resolve *r = resolveList[at]; resolveList.removeAt(at); int id = r->id; delete r; // FIXME: this looks weird, we should probably rename our // local function emit ServiceProvider::resolve_error(id, XMPP::ServiceResolver::ErrorGeneric); } }; // AppleProvider XMPP::NameProvider *AppleProvider::createNameProviderInternet() { return new AppleNameProvider(this); } XMPP::NameProvider *AppleProvider::createNameProviderLocal() { return new AppleNameProvider(this); } XMPP::ServiceProvider *AppleProvider::createServiceProvider() { return new AppleServiceProvider(this); } #ifdef APPLEDNS_STATIC XMPP::IrisNetProvider *irisnet_createAppleProvider() { return new AppleProvider; } #else Q_EXPORT_PLUGIN2(appledns, AppleProvider) #endif #include "appledns.moc" psi-0.14/iris/src/irisnet/appledns/appledns.pri0000644000175000017500000000015711305557616017711 0ustar janjanQT *= network HEADERS += $$PWD/qdnssd.h SOURCES += $$PWD/qdnssd.cpp $$PWD/appledns.cpp !mac:LIBS += -ldns_sd psi-0.14/iris/src/irisnet/noncore/0000755000175000017500000000000011305557616015221 5ustar janjanpsi-0.14/iris/src/irisnet/noncore/processquit.h0000644000175000017500000001037111305557616017755 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef PROCESSQUIT_H #define PROCESSQUIT_H #ifdef NO_IRISNET # include # define IRISNET_EXPORT #else # include "irisnetglobal.h" #endif #ifndef NO_IRISNET namespace XMPP { #endif /** \brief Listens for termination requests ProcessQuit listens for requests to terminate the application process. On Unix platforms, these are the signals SIGINT, SIGHUP, and SIGTERM. On Windows, these are the console control events for Ctrl+C, console window close, and system shutdown. For Windows GUI programs, ProcessQuit has no effect. For GUI programs, ProcessQuit is not a substitute for QSessionManager. The only safe way to handle termination of a GUI program in the usual way is to use QSessionManager. However, ProcessQuit does give additional benefit to Unix GUI programs that might be terminated unconventionally, so it can't hurt to support both. When a termination request is received, the application should exit gracefully, and generally without user interaction. Otherwise, it is at risk of being terminated outside of its control. For example, if a Windows console application does not exit after just a few seconds of attempting to close the console window, Windows will display a prompt to the user asking if the process should be ended immediately. Using ProcessQuit is easy, and it usually amounts to a single line: \code myapp.connect(ProcessQuit::instance(), SIGNAL(quit()), SLOT(do_quit())); \endcode Calling instance() returns a pointer to the global ProcessQuit instance, which will be created if necessary. The quit() signal is emitted when a request to terminate is received. The quit() signal is only emitted once, future termination requests are ignored. Call reset() to allow the quit() signal to be emitted again. */ class IRISNET_EXPORT ProcessQuit : public QObject { Q_OBJECT public: /** \brief Returns the global ProcessQuit instance If the global instance does not exist yet, it will be created, and the termination handlers will be installed. \sa cleanup */ static ProcessQuit *instance(); /** \brief Allows the quit() signal to be emitted again ProcessQuit only emits the quit() signal once, so that if a user repeatedly presses Ctrl-C or sends SIGTERM, your shutdown slot will not be called multiple times. This is normally the desired behavior, but if you are ignoring the termination request then you may want to allow future notifications. Calling this function will allow the quit() signal to be emitted again, if a new termination request arrives. \sa quit */ static void reset(); /** \brief Frees all resources used by ProcessQuit This function will free any resources used by ProcessQuit, including the global instance, and the termination handlers will be uninstalled (reverted to default). Future termination requests will cause the application to exit abruptly. \note You normally do not need to call this function directly. When IrisNet cleans up, it will be called. \sa instance */ static void cleanup(); signals: /** \brief Notification of termination request This signal is emitted when a termination request is received. It is only emitted once, unless reset() is called. Upon receiving this signal, the application should proceed to exit gracefully, and generally without user interaction. \sa reset */ void quit(); private: class Private; friend class Private; Private *d; ProcessQuit(QObject *parent = 0); ~ProcessQuit(); }; #ifndef NO_IRISNET } #endif #endif psi-0.14/iris/src/irisnet/noncore/ice176.h0000644000175000017500000000676411305557616016405 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef ICE176_H #define ICE176_H #include #include #include namespace QCA { class SecureArray; } namespace XMPP { class Ice176 : public QObject { Q_OBJECT public: enum Mode { Initiator, Responder }; enum StunServiceType { Basic, Relay }; class LocalAddress { public: QHostAddress addr; int network; // -1 = unknown bool isVpn; LocalAddress() : network(-1), isVpn(false) { } bool operator==(const LocalAddress &other) const { if(addr == other.addr && network == other.network) return true; else return false; } inline bool operator!=(const LocalAddress &other) const { return !operator==(other); } }; class ExternalAddress { public: LocalAddress base; QHostAddress addr; int portBase; // -1 = same as base ExternalAddress() : portBase(-1) { } }; class Candidate { public: int component; QString foundation; int generation; QString id; QHostAddress ip; int network; int port; int priority; QString protocol; QHostAddress rel_addr; int rel_port; QHostAddress rem_addr; int rem_port; QString type; Candidate() : component(-1), generation(-1), network(-1), port(-1), priority(-1), rel_port(-1), rem_port(-1) { } }; Ice176(QObject *parent = 0); ~Ice176(); void reset(); // default = -1 (unspecified) // if a base port is specified, it is only considered for the initial // component count. if components are later added, random ports // will be used. void setBasePort(int port); void setLocalAddresses(const QList &addrs); // one per local address. you must set local addresses first. void setExternalAddresses(const QList &addrs); void setStunService(StunServiceType type, const QHostAddress &addr, int port); void setComponentCount(int count); void setLocalCandidateTrickle(bool enabled); // default false void start(Mode mode); QString localUfrag() const; QString localPassword() const; void setPeerUfrag(const QString &ufrag); void setPeerPassword(const QString &pass); void setStunUsername(const QString &user); void setStunPassword(const QCA::SecureArray &pass); void addRemoteCandidates(const QList &list); bool hasPendingDatagrams(int componentIndex) const; QByteArray readDatagram(int componentIndex); void writeDatagram(int componentIndex, const QByteArray &datagram); signals: void started(); void error(); void localCandidatesReady(const QList &list); void componentReady(int index); void readyRead(int componentIndex); void datagramsWritten(int componentIndex, int count); private: class Private; friend class Private; Private *d; }; } #endif psi-0.14/iris/src/irisnet/noncore/noncore.pro0000644000175000017500000000044211305557616017406 0ustar janjanIRIS_BASE = ../../.. TEMPLATE = lib QT -= gui TARGET = irisnet DESTDIR = $$IRIS_BASE/lib CONFIG += staticlib create_prl VERSION = 1.0.0 include(../../libbase.pri) include(noncore.pri) windows:!staticlib:DEFINES += IRISNET_MAKEDLL staticlib:PRL_EXPORT_DEFINES += IRISNET_STATIC psi-0.14/iris/src/irisnet/noncore/processquit.cpp0000644000175000017500000001164411305557616020314 0ustar janjan/* * Copyright (C) 2006 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "processquit.h" #ifndef NO_IRISNET # include "irisnetglobal_p.h" #endif #ifdef QT_GUI_LIB # include #endif #ifdef Q_OS_WIN # include #endif #ifdef Q_OS_UNIX # include # include #endif namespace { // safeobj stuff, from qca void releaseAndDeleteLater(QObject *owner, QObject *obj) { obj->disconnect(owner); obj->setParent(0); obj->deleteLater(); } class SafeSocketNotifier : public QObject { Q_OBJECT public: SafeSocketNotifier(int socket, QSocketNotifier::Type type, QObject *parent = 0) : QObject(parent) { sn = new QSocketNotifier(socket, type, this); connect(sn, SIGNAL(activated(int)), SIGNAL(activated(int))); } ~SafeSocketNotifier() { sn->setEnabled(false); releaseAndDeleteLater(this, sn); } bool isEnabled() const { return sn->isEnabled(); } int socket() const { return sn->socket(); } QSocketNotifier::Type type() const { return sn->type(); } public slots: void setEnabled(bool enable) { sn->setEnabled(enable); } signals: void activated(int socket); private: QSocketNotifier *sn; }; } #ifndef NO_IRISNET namespace XMPP { #endif Q_GLOBAL_STATIC(QMutex, pq_mutex) static ProcessQuit *g_pq = 0; inline bool is_gui_app() { #ifdef QT_GUI_LIB return (QApplication::type() != QApplication::Tty); #else return false; #endif } class ProcessQuit::Private : public QObject { Q_OBJECT public: ProcessQuit *q; bool done; #ifdef Q_OS_WIN bool use_handler; #endif #ifdef Q_OS_UNIX int sig_pipe[2]; SafeSocketNotifier *sig_notifier; #endif Private(ProcessQuit *_q) : QObject(_q), q(_q) { done = false; #ifdef Q_OS_WIN use_handler = !is_gui_app(); if(use_handler) SetConsoleCtrlHandler((PHANDLER_ROUTINE)winHandler, TRUE); #endif #ifdef Q_OS_UNIX pipe(sig_pipe); sig_notifier = new SafeSocketNotifier(sig_pipe[0], QSocketNotifier::Read, this); connect(sig_notifier, SIGNAL(activated(int)), SLOT(sig_activated(int))); unixWatchAdd(SIGINT); unixWatchAdd(SIGHUP); unixWatchAdd(SIGTERM); #endif } ~Private() { #ifdef Q_OS_WIN if(use_handler) SetConsoleCtrlHandler((PHANDLER_ROUTINE)winHandler, FALSE); #endif #ifdef Q_OS_UNIX unixWatchRemove(SIGINT); unixWatchRemove(SIGHUP); unixWatchRemove(SIGTERM); delete sig_notifier; close(sig_pipe[0]); close(sig_pipe[1]); #endif } #ifdef Q_OS_WIN static BOOL winHandler(DWORD ctrlType) { Q_UNUSED(ctrlType); QMetaObject::invokeMethod(g_pq->d, "ctrl_ready", Qt::QueuedConnection); return TRUE; } #endif #ifdef Q_OS_UNIX static void unixHandler(int sig) { Q_UNUSED(sig); unsigned char c = 0; ::write(g_pq->d->sig_pipe[1], &c, 1); } void unixWatchAdd(int sig) { struct sigaction sa; sigaction(sig, NULL, &sa); // if the signal is ignored, don't take it over. this is // recommended by the glibc manual if(sa.sa_handler == SIG_IGN) return; sigemptyset(&(sa.sa_mask)); sa.sa_flags = 0; sa.sa_handler = unixHandler; sigaction(sig, &sa, 0); } void unixWatchRemove(int sig) { struct sigaction sa; sigaction(sig, NULL, &sa); // ignored means we skipped it earlier, so we should // skip it again if(sa.sa_handler == SIG_IGN) return; sigemptyset(&(sa.sa_mask)); sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigaction(sig, &sa, 0); } #endif public slots: void ctrl_ready() { #ifdef Q_OS_WIN do_emit(); #endif } void sig_activated(int) { #ifdef Q_OS_UNIX unsigned char c; ::read(sig_pipe[0], &c, 1); do_emit(); #endif } private: void do_emit() { // only signal once if(!done) { done = true; emit q->quit(); } } }; ProcessQuit::ProcessQuit(QObject *parent) :QObject(parent) { d = new Private(this); } ProcessQuit::~ProcessQuit() { delete d; } ProcessQuit *ProcessQuit::instance() { QMutexLocker locker(pq_mutex()); if(!g_pq) { g_pq = new ProcessQuit; g_pq->moveToThread(QCoreApplication::instance()->thread()); #ifndef NO_IRISNET irisNetAddPostRoutine(cleanup); #endif } return g_pq; } void ProcessQuit::reset() { QMutexLocker locker(pq_mutex()); if(g_pq) g_pq->d->done = false; } void ProcessQuit::cleanup() { delete g_pq; g_pq = 0; } #ifndef NO_IRISNET } #endif #include "processquit.moc" psi-0.14/iris/src/irisnet/noncore/legacy/0000755000175000017500000000000011305557616016465 5ustar janjanpsi-0.14/iris/src/irisnet/noncore/legacy/ndns.cpp0000644000175000017500000000704111305557616020135 0ustar janjan/* * ndns.cpp - native DNS resolution * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ //! \class NDns ndns.h //! \brief Simple DNS resolution using native system calls //! //! This class is to be used when Qt's QDns is not good enough. Because QDns //! does not use threads, it cannot make a system call asyncronously. Thus, //! QDns tries to imitate the behavior of each platform's native behavior, and //! generally falls short. //! //! NDns uses a thread to make the system call happen in the background. This //! gives your program native DNS behavior, at the cost of requiring threads //! to build. //! //! \code //! #include "ndns.h" //! //! ... //! //! NDns dns; //! dns.resolve("psi.affinix.com"); //! //! // The class will emit the resultsReady() signal when the resolution //! // is finished. You may then retrieve the results: //! //! uint ip_address = dns.result(); //! //! // or if you want to get the IP address as a string: //! //! QString ip_address = dns.resultString(); //! \endcode #include "ndns.h" #include "netnames.h" // CS_NAMESPACE_BEGIN //---------------------------------------------------------------------------- // NDns //---------------------------------------------------------------------------- //! \fn void NDns::resultsReady() //! This signal is emitted when the DNS resolution succeeds or fails. //! //! Constructs an NDns object with parent \a parent. NDns::NDns(QObject *parent) :QObject(parent) { busy = false; connect(&dns, SIGNAL(resultsReady(const QList &)), SLOT(dns_resultsReady(const QList &))); connect(&dns, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error))); } //! //! Destroys the object and frees allocated resources. NDns::~NDns() { stop(); } //! //! Resolves hostname \a host (eg. psi.affinix.com) void NDns::resolve(const QString &host) { stop(); busy = true; dns.start(host.toLatin1()); } //! //! Cancels the lookup action. //! \note This will not stop the underlying system call, which must finish before the next lookup will proceed. void NDns::stop() { dns.stop(); busy = false; } //! //! Returns the IP address as a 32-bit integer in host-byte-order. This will be 0 if the lookup failed. //! \sa resultsReady() QHostAddress NDns::result() const { return addr; } //! //! Returns the IP address as a string. This will be an empty string if the lookup failed. //! \sa resultsReady() QString NDns::resultString() const { return addr.toString(); } //! //! Returns TRUE if busy resolving a hostname. bool NDns::isBusy() const { return busy; } void NDns::dns_resultsReady(const QList &results) { addr = results[0].address(); busy = false; emit resultsReady(); } void NDns::dns_error(XMPP::NameResolver::Error) { addr = QHostAddress(); busy = false; emit resultsReady(); } // CS_NAMESPACE_END psi-0.14/iris/src/irisnet/noncore/legacy/safedelete.h0000644000175000017500000000151011305557616020734 0ustar janjan#ifndef SAFEDELETE_H #define SAFEDELETE_H #include class SafeDelete; class SafeDeleteLock { public: SafeDeleteLock(SafeDelete *sd); ~SafeDeleteLock(); private: SafeDelete *_sd; bool own; friend class SafeDelete; void dying(); }; class SafeDelete { public: SafeDelete(); ~SafeDelete(); void deleteLater(QObject *o); // same as QObject::deleteLater() static void deleteSingle(QObject *o); private: QObjectList list; void deleteAll(); friend class SafeDeleteLock; SafeDeleteLock *lock; void unlock(); }; class SafeDeleteLater : public QObject { Q_OBJECT public: static SafeDeleteLater *ensureExists(); void deleteItLater(QObject *o); private slots: void explode(); private: SafeDeleteLater(); ~SafeDeleteLater(); QObjectList list; friend class SafeDelete; static SafeDeleteLater *self; }; #endif psi-0.14/iris/src/irisnet/noncore/legacy/ndns.h0000644000175000017500000000260611305557616017604 0ustar janjan/* * ndns.h - native DNS resolution * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_NDNS_H #define CS_NDNS_H #include #include #include "netnames.h" // CS_NAMESPACE_BEGIN class NDns : public QObject { Q_OBJECT public: NDns(QObject *parent=0); ~NDns(); void resolve(const QString &); void stop(); bool isBusy() const; QHostAddress result() const; QString resultString() const; signals: void resultsReady(); private slots: void dns_resultsReady(const QList &); void dns_error(XMPP::NameResolver::Error); private: XMPP::NameResolver dns; bool busy; QHostAddress addr; }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/irisnet/noncore/legacy/safedelete.cpp0000644000175000017500000000361711305557616021301 0ustar janjan#include"safedelete.h" //---------------------------------------------------------------------------- // SafeDelete //---------------------------------------------------------------------------- SafeDelete::SafeDelete() { lock = 0; } SafeDelete::~SafeDelete() { if(lock) lock->dying(); } void SafeDelete::deleteLater(QObject *o) { if(!lock) deleteSingle(o); else list.append(o); } void SafeDelete::unlock() { lock = 0; deleteAll(); } void SafeDelete::deleteAll() { if(list.isEmpty()) return; for(int n = 0; n < list.size(); ++n) deleteSingle(list[n]); list.clear(); } void SafeDelete::deleteSingle(QObject *o) { #if QT_VERSION < 0x030000 // roll our own QObject::deleteLater() SafeDeleteLater *sdl = SafeDeleteLater::ensureExists(); sdl->deleteItLater(o); #else o->deleteLater(); #endif } //---------------------------------------------------------------------------- // SafeDeleteLock //---------------------------------------------------------------------------- SafeDeleteLock::SafeDeleteLock(SafeDelete *sd) { own = false; if(!sd->lock) { _sd = sd; _sd->lock = this; } else _sd = 0; } SafeDeleteLock::~SafeDeleteLock() { if(_sd) { _sd->unlock(); if(own) delete _sd; } } void SafeDeleteLock::dying() { _sd = new SafeDelete(*_sd); own = true; } //---------------------------------------------------------------------------- // SafeDeleteLater //---------------------------------------------------------------------------- SafeDeleteLater *SafeDeleteLater::self = 0; SafeDeleteLater *SafeDeleteLater::ensureExists() { if(!self) new SafeDeleteLater(); return self; } SafeDeleteLater::SafeDeleteLater() { self = this; QTimer::singleShot(0, this, SLOT(explode())); } SafeDeleteLater::~SafeDeleteLater() { qDeleteAll(list); list.clear(); self = 0; } void SafeDeleteLater::deleteItLater(QObject *o) { list.append(o); } void SafeDeleteLater::explode() { delete this; } psi-0.14/iris/src/irisnet/noncore/legacy/srvresolver.h0000644000175000017500000000366011305557616021237 0ustar janjan/* * srvresolver.h - class to simplify SRV lookups * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_SRVRESOLVER_H #define CS_SRVRESOLVER_H #include #include #include "netnames.h" // CS_NAMESPACE_BEGIN class Q3Dns { public: class Server { public: Server(const QString &n = QString(), quint16 p = 0, quint16 w = 0, quint16 po = 0) :name(n), priority(p), weight(w), port(po) {} QString name; quint16 priority; quint16 weight; quint16 port; }; }; class SrvResolver : public QObject { Q_OBJECT public: SrvResolver(QObject *parent=0); ~SrvResolver(); void resolve(const QString &server, const QString &type, const QString &proto); void resolveSrvOnly(const QString &server, const QString &type, const QString &proto); void next(); void stop(); bool isBusy() const; QList servers() const; bool failed() const; QHostAddress resultAddress() const; quint16 resultPort() const; signals: void resultsReady(); private slots: void nndns_resultsReady(const QList &); void nndns_error(XMPP::NameResolver::Error); void ndns_done(); void t_timeout(); private: class Private; Private *d; void tryNext(); }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/irisnet/noncore/legacy/servsock.h0000644000175000017500000000277611305557616020511 0ustar janjan/* * servsock.h - simple wrapper to QServerSocket * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_SERVSOCK_H #define CS_SERVSOCK_H #include #include // CS_NAMESPACE_BEGIN class ServSock : public QObject { Q_OBJECT public: ServSock(QObject *parent=0); ~ServSock(); bool isActive() const; bool listen(quint16 port); void stop(); int port() const; QHostAddress address() const; signals: void connectionReady(int); private slots: void sss_connectionReady(int); private: class Private; Private *d; }; class ServSockSignal : public QTcpServer { Q_OBJECT public: ServSockSignal(QObject *parent = 0); signals: void connectionReady(int); protected: // reimplemented void incomingConnection(int socketDescriptor); }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/irisnet/noncore/legacy/srvresolver.cpp0000644000175000017500000001404411305557616021570 0ustar janjan/* * srvresolver.cpp - class to simplify SRV lookups * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "srvresolver.h" #ifndef NO_NDNS # include "ndns.h" #endif // CS_NAMESPACE_BEGIN static void sortSRVList(QList &list) { QList tmp = list; list.clear(); while(!tmp.isEmpty()) { QList::Iterator p = tmp.end(); for(QList::Iterator it = tmp.begin(); it != tmp.end(); ++it) { if(p == tmp.end()) p = it; else { int a = (*it).priority; int b = (*p).priority; int j = (*it).weight; int k = (*p).weight; if(a < b || (a == b && j < k)) p = it; } } list.append(*p); tmp.erase(p); } } class SrvResolver::Private { public: Private() {} XMPP::NameResolver nndns; XMPP::NameRecord::Type nntype; bool nndns_busy; #ifndef NO_NDNS NDns ndns; #endif bool failed; QHostAddress resultAddress; quint16 resultPort; bool srvonly; QString srv; QList servers; bool aaaa; QTimer t; }; SrvResolver::SrvResolver(QObject *parent) :QObject(parent) { d = new Private; d->nndns_busy = false; connect(&d->nndns, SIGNAL(resultsReady(const QList &)), SLOT(nndns_resultsReady(const QList &))); connect(&d->nndns, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(nndns_error(XMPP::NameResolver::Error))); #ifndef NO_NDNS connect(&d->ndns, SIGNAL(resultsReady()), SLOT(ndns_done())); #endif connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout())); stop(); } SrvResolver::~SrvResolver() { stop(); delete d; } void SrvResolver::resolve(const QString &server, const QString &type, const QString &proto) { stop(); d->failed = false; d->srvonly = false; d->srv = QString("_") + type + "._" + proto + '.' + server; d->t.setSingleShot(true); d->t.start(15000); d->nndns_busy = true; d->nntype = XMPP::NameRecord::Srv; d->nndns.start(d->srv.toLatin1(), d->nntype); } void SrvResolver::resolveSrvOnly(const QString &server, const QString &type, const QString &proto) { stop(); d->failed = false; d->srvonly = true; d->srv = QString("_") + type + "._" + proto + '.' + server; d->t.setSingleShot(true); d->t.start(15000); d->nndns_busy = true; d->nntype = XMPP::NameRecord::Srv; d->nndns.start(d->srv.toLatin1(), d->nntype); } void SrvResolver::next() { if(d->servers.isEmpty()) return; tryNext(); } void SrvResolver::stop() { if(d->t.isActive()) d->t.stop(); if(d->nndns_busy) { d->nndns.stop(); d->nndns_busy = false; } #ifndef NO_NDNS if(d->ndns.isBusy()) d->ndns.stop(); #endif d->resultAddress = QHostAddress(); d->resultPort = 0; d->servers.clear(); d->srv = ""; d->failed = true; } bool SrvResolver::isBusy() const { #ifndef NO_NDNS if(d->nndns_busy || d->ndns.isBusy()) #else if(d->nndns_busy) #endif return true; else return false; } QList SrvResolver::servers() const { return d->servers; } bool SrvResolver::failed() const { return d->failed; } QHostAddress SrvResolver::resultAddress() const { return d->resultAddress; } quint16 SrvResolver::resultPort() const { return d->resultPort; } void SrvResolver::tryNext() { #ifndef NO_NDNS d->ndns.resolve(d->servers.first().name); #else d->nndns_busy = true; d->nntype = d->aaaa ? XMPP::NameRecord::Aaaa : XMPP::NameRecord::A; d->nndns.start(d->servers.first().name.toLatin1(), d->nntype); #endif } void SrvResolver::nndns_resultsReady(const QList &results) { if(!d->nndns_busy) return; d->t.stop(); if(d->nntype == XMPP::NameRecord::Srv) { // grab the server list and destroy the qdns object QList list; for(int n = 0; n < results.count(); ++n) { list += Q3Dns::Server(QString::fromLatin1(results[n].name()), results[n].priority(), results[n].weight(), results[n].port()); } d->nndns_busy = false; d->nndns.stop(); if(list.isEmpty()) { stop(); resultsReady(); return; } sortSRVList(list); d->servers = list; if(d->srvonly) resultsReady(); else { // kick it off d->aaaa = true; tryNext(); } } else { // grab the address list and destroy the qdns object QList list; if(d->nntype == XMPP::NameRecord::A || d->nntype == XMPP::NameRecord::Aaaa) { for(int n = 0; n < results.count(); ++n) { list += results[n].address(); } } d->nndns_busy = false; d->nndns.stop(); if(!list.isEmpty()) { int port = d->servers.first().port; d->servers.removeFirst(); d->aaaa = true; d->resultAddress = list.first(); d->resultPort = port; resultsReady(); } else { if(!d->aaaa) d->servers.removeFirst(); d->aaaa = !d->aaaa; // failed? bail if last one if(d->servers.isEmpty()) { stop(); resultsReady(); return; } // otherwise try the next tryNext(); } } } void SrvResolver::nndns_error(XMPP::NameResolver::Error) { nndns_resultsReady(QList()); } void SrvResolver::ndns_done() { #ifndef NO_NDNS QHostAddress r = d->ndns.result(); int port = d->servers.first().port; d->servers.removeFirst(); if(!r.isNull()) { d->resultAddress = d->ndns.result(); d->resultPort = port; resultsReady(); } else { // failed? bail if last one if(d->servers.isEmpty()) { stop(); resultsReady(); return; } // otherwise try the next tryNext(); } #endif } void SrvResolver::t_timeout() { stop(); resultsReady(); } // CS_NAMESPACE_END psi-0.14/iris/src/irisnet/noncore/legacy/legacy.pri0000644000175000017500000000030111305557616020437 0ustar janjanHEADERS += \ $$PWD/safedelete.h \ $$PWD/ndns.h \ $$PWD/srvresolver.h \ $$PWD/servsock.h SOURCES += \ $$PWD/safedelete.cpp \ $$PWD/ndns.cpp \ $$PWD/srvresolver.cpp \ $$PWD/servsock.cpp psi-0.14/iris/src/irisnet/noncore/legacy/servsock.cpp0000644000175000017500000000450411305557616021033 0ustar janjan/* * servsock.cpp - simple wrapper to QServerSocket * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "servsock.h" // CS_NAMESPACE_BEGIN //---------------------------------------------------------------------------- // ServSock //---------------------------------------------------------------------------- class ServSock::Private { public: Private() {} ServSockSignal *serv; }; ServSock::ServSock(QObject *parent) :QObject(parent) { d = new Private; d->serv = 0; } ServSock::~ServSock() { stop(); delete d; } bool ServSock::isActive() const { return (d->serv ? true: false); } bool ServSock::listen(quint16 port) { stop(); d->serv = new ServSockSignal(this); if(!d->serv->listen(QHostAddress::Any, port)) { delete d->serv; d->serv = 0; return false; } connect(d->serv, SIGNAL(connectionReady(int)), SLOT(sss_connectionReady(int))); return true; } void ServSock::stop() { delete d->serv; d->serv = 0; } int ServSock::port() const { if(d->serv) return d->serv->serverPort(); else return -1; } QHostAddress ServSock::address() const { if(d->serv) return d->serv->serverAddress(); else return QHostAddress(); } void ServSock::sss_connectionReady(int s) { connectionReady(s); } //---------------------------------------------------------------------------- // ServSockSignal //---------------------------------------------------------------------------- ServSockSignal::ServSockSignal(QObject *parent) :QTcpServer(parent) { setMaxPendingConnections(16); } void ServSockSignal::incomingConnection(int socketDescriptor) { connectionReady(socketDescriptor); } // CS_NAMESPACE_END psi-0.14/iris/src/irisnet/noncore/ice176.cpp0000644000175000017500000006347611305557616016743 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "ice176.h" #include #include #include "stuntransaction.h" #include "stunbinding.h" #include "stunallocate.h" #include "stunmessage.h" #include "icelocaltransport.h" namespace XMPP { static QChar randomPrintableChar() { // 0-25 = a-z // 26-51 = A-Z // 52-61 = 0-9 uchar c = QCA::Random::randomChar() % 62; if(c <= 25) return 'a' + c; else if(c <= 51) return 'A' + (c - 26); else return '0' + (c - 52); } static QString randomCredential(int len) { QString out; for(int n = 0; n < len; ++n) out += randomPrintableChar(); return out; } static int calc_priority(int typePref, int localPref, int componentId) { Q_ASSERT(typePref >= 0 && typePref <= 126); Q_ASSERT(localPref >= 0 && localPref <= 65535); Q_ASSERT(componentId >= 1 && componentId <= 256); int priority = (1 << 24) * typePref; priority += (1 << 8) * localPref; priority += (256 - componentId); return priority; } static qint64 calc_pair_priority(int a, int b) { qint64 priority = ((qint64)1 << 32) * qMin(a, b); priority += (qint64)2 * qMax(a, b); if(a > b) ++priority; return priority; } class Ice176::Private : public QObject { Q_OBJECT public: enum CandidatePairState { PWaiting, PInProgress, PSucceeded, PFailed, PFrozen }; enum CandidateType { HostType, PeerReflexiveType, ServerReflexiveType, RelayedType }; enum CheckListState { LRunning, LCompleted, LFailed }; class TransportAddress { public: QHostAddress addr; int port; TransportAddress() : port(-1) { } bool operator==(const TransportAddress &other) const { if(addr == other.addr && port == other.port) return true; else return false; } inline bool operator!=(const TransportAddress &other) const { return !operator==(other); } }; class CandidateInfo { public: TransportAddress addr; CandidateType type; int priority; QString foundation; int componentId; TransportAddress base; TransportAddress related; QString id; int network; bool operator==(const CandidateInfo &other) const { if(addr == other.addr && type == other.type && priority == other.priority && foundation == other.foundation && componentId == other.componentId && base == other.base && related == other.related && network == other.network) { return true; } else return false; } inline bool operator!=(const CandidateInfo &other) const { return !operator==(other); } }; class CandidatePair { public: CandidateInfo local, remote; bool isDefault; bool isValid; bool isNominated; CandidatePairState state; qint64 priority; QString foundation; StunBinding *binding; // FIXME: this is wrong i think, it should be in LocalTransport // or such, to multiplex ids StunTransactionPool *pool; CandidatePair() : binding(0), pool(0) { } }; class CheckList { public: QList pairs; CheckListState state; }; class LocalTransport { public: IceLocalTransport *sock; QTimer *t; // for cutting stun request short int addrAt; // for calculating foundation, not great int network; bool isVpn; int componentId; bool started; bool use_stun; bool stun_finished; LocalTransport() : sock(0), t(0), addrAt(-1), network(-1), isVpn(false), componentId(-1), started(false), use_stun(false), stun_finished(false) { } }; Ice176 *q; Ice176::Mode mode; int basePort; int componentCount; QList localAddrs; QList extAddrs; Ice176::StunServiceType stunType; QHostAddress stunAddr; int stunPort; QString stunUser; QCA::SecureArray stunPass; QString localUser, localPass; QString peerUser, peerPass; QList localTransports; QList localCandidates; CheckList checkList; QList< QList > in; Private(Ice176 *_q) : QObject(_q), q(_q), basePort(-1), componentCount(0) { } ~Private() { for(int n = 0; n < localTransports.count(); ++n) { delete localTransports[n]->sock; QTimer *t = localTransports[n]->t; if(t) { t->disconnect(this); t->setParent(0); t->deleteLater(); } } qDeleteAll(localTransports); for(int n = 0; n < checkList.pairs.count(); ++n) { StunBinding *binding = checkList.pairs[n].binding; StunTransactionPool *pool = checkList.pairs[n].pool; delete binding; if(pool) { pool->disconnect(this); pool->setParent(0); pool->deleteLater(); } } } // localPref is the priority of the network interface being used for // this candidate. the value must be between 0-65535 and different // interfaces must have different values. if there is only one // interface, the value should be 65535. static int choose_default_priority(CandidateType type, int localPref, bool isVpn, int componentId) { int typePref; if(type == HostType) { if(isVpn) typePref = 0; else typePref = 126; } else if(type == PeerReflexiveType) typePref = 110; else if(type == ServerReflexiveType) typePref = 100; else // RelayedType typePref = 0; return calc_priority(typePref, localPref, componentId); } static QString candidateType_to_string(CandidateType type) { QString out; switch(type) { case HostType: out = "host"; break; case PeerReflexiveType: out = "prflx"; break; case ServerReflexiveType: out = "srflx"; break; case RelayedType: out = "relay"; break; default: Q_ASSERT(0); } return out; } static int string_to_candidateType(const QString &in) { if(in == "host") return HostType; else if(in == "prflx") return PeerReflexiveType; else if(in == "srflx") return ServerReflexiveType; else if(in == "relay") return RelayedType; else return -1; } void start() { localUser = randomCredential(4); localPass = randomCredential(22); bool atLeastOneTransport = false; for(int n = 0; n < componentCount; ++n) { in += QList(); for(int i = 0; i < localAddrs.count(); ++i) { if(localAddrs[i].addr.protocol() != QAbstractSocket::IPv4Protocol) { printf("warning: skipping non-ipv4 address: %s\n", qPrintable(localAddrs[i].addr.toString())); continue; } LocalTransport *lt = new LocalTransport; lt->sock = new IceLocalTransport(this); connect(lt->sock, SIGNAL(started()), SLOT(lt_started())); connect(lt->sock, SIGNAL(stopped()), SLOT(lt_stopped())); connect(lt->sock, SIGNAL(stunFinished()), SLOT(lt_stunFinished())); connect(lt->sock, SIGNAL(error(XMPP::IceLocalTransport::Error)), SLOT(lt_error(XMPP::IceLocalTransport::Error))); connect(lt->sock, SIGNAL(readyRead(XMPP::IceLocalTransport::TransmitPath)), SLOT(lt_readyRead(XMPP::IceLocalTransport::TransmitPath))); connect(lt->sock, SIGNAL(datagramsWritten(XMPP::IceLocalTransport::TransmitPath, int)), SLOT(lt_datagramsWritten(XMPP::IceLocalTransport::TransmitPath, int))); lt->addrAt = i; lt->network = localAddrs[i].network; lt->isVpn = localAddrs[i].isVpn; lt->componentId = n + 1; localTransports += lt; int port = (basePort != -1) ? basePort + n : -1; lt->sock->start(localAddrs[i].addr, port); atLeastOneTransport = true; printf("starting transport %s:%d for component %d\n", qPrintable(localAddrs[i].addr.toString()), port, lt->componentId); } } if(!atLeastOneTransport) QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection); } void tryFinishGather() { bool allReady = true; foreach(const LocalTransport *lt, localTransports) { if(!lt->started || (lt->use_stun && !lt->stun_finished)) { allReady = false; break; } } if(allReady) { emit q->started(); // FIXME: DOR-SS QList list; foreach(const CandidateInfo &ci, localCandidates) { Ice176::Candidate c; c.component = ci.componentId; c.foundation = ci.foundation; c.generation = 0; c.id = ci.id; c.ip = ci.addr.addr; c.network = ci.network; c.port = ci.addr.port; c.priority = ci.priority; c.protocol = "udp"; if(ci.type != HostType) { c.rel_addr = ci.base.addr; c.rel_port = ci.base.port; } else { c.rel_addr = QHostAddress(); c.rel_port = -1; } c.rem_addr = QHostAddress(); c.rem_port = -1; c.type = candidateType_to_string(ci.type); list += c; } if(!list.isEmpty()) emit q->localCandidatesReady(list); } } void addRemoteCandidates(const QList &list) { QList remoteCandidates; foreach(const Candidate &c, list) { CandidateInfo ci; ci.addr.addr = c.ip; ci.addr.port = c.port; ci.type = (CandidateType)string_to_candidateType(c.type); // TODO: handle error ci.componentId = c.component; ci.priority = c.priority; ci.foundation = c.foundation; if(!c.rel_addr.isNull()) { ci.base.addr = c.rel_addr; ci.base.port = c.rel_port; } ci.network = c.network; ci.id = c.id; remoteCandidates += ci; } printf("adding %d remote candidates\n", remoteCandidates.count()); QList pairs; foreach(const CandidateInfo &lc, localCandidates) { foreach(const CandidateInfo &rc, remoteCandidates) { if(lc.componentId != rc.componentId) continue; CandidatePair pair; pair.state = PFrozen; // FIXME: setting state here may be wrong pair.local = lc; pair.remote = rc; pair.isDefault = false; pair.isValid = false; pair.isNominated = false; if(mode == Ice176::Initiator) pair.priority = calc_pair_priority(lc.priority, rc.priority); else pair.priority = calc_pair_priority(rc.priority, lc.priority); pairs += pair; } } printf("%d pairs\n", pairs.count()); // combine pairs with existing, and sort pairs = checkList.pairs + pairs; checkList.pairs.clear(); while(!pairs.isEmpty()) { int at = -1; qint64 highest_priority = -1; for(int n = 0; n < pairs.count(); ++n) { if(n == 0 || pairs[n].priority > highest_priority) { at = n; highest_priority = pairs[n].priority; } } CandidatePair pair = pairs[at]; pairs.removeAt(at); checkList.pairs += pair; } // pruning for(int n = 0; n < checkList.pairs.count(); ++n) { CandidatePair &pair = checkList.pairs[n]; if(pair.local.type == ServerReflexiveType) pair.local.addr = pair.local.base; } for(int n = 0; n < checkList.pairs.count(); ++n) { CandidatePair &pair = checkList.pairs[n]; printf("%d, %s:%d -> %s:%d\n", pair.local.componentId, qPrintable(pair.local.addr.addr.toString()), pair.local.addr.port, qPrintable(pair.remote.addr.addr.toString()), pair.remote.addr.port); bool found = false; for(int i = n - 1; i >= 0; --i) { if(pair.local == checkList.pairs[i].local && pair.remote == checkList.pairs[i].remote) { found = true; break; } } if(found) { checkList.pairs.removeAt(n); --n; // adjust position } } printf("%d after pruning\n", checkList.pairs.count()); // set state for(int n = 0; n < checkList.pairs.count(); ++n) { CandidatePair &pair = checkList.pairs[n]; // only initialize the new pairs if(pair.state != PFrozen) continue; pair.foundation = pair.local.foundation + pair.remote.foundation; // FIXME: for now we just do checks to everything immediately pair.state = PInProgress; int at = -1; for(int i = 0; i < localTransports.count(); ++i) { if(localTransports[i]->sock->localAddress() == pair.local.addr.addr && localTransports[i]->sock->localPort() == pair.local.addr.port) { at = i; break; } } Q_ASSERT(at != -1); LocalTransport *lt = localTransports[at]; pair.pool = new StunTransactionPool(StunTransaction::Udp, this); connect(pair.pool, SIGNAL(retransmit(XMPP::StunTransaction *)), SLOT(pool_retransmit(XMPP::StunTransaction *))); pair.pool->setUsername(peerUser + ':' + localUser); pair.pool->setPassword(peerPass.toUtf8()); pair.binding = new StunBinding(pair.pool); connect(pair.binding, SIGNAL(success()), SLOT(binding_success())); int prflx_priority = choose_default_priority(PeerReflexiveType, 65535 - lt->addrAt, lt->isVpn, pair.local.componentId); pair.binding->setPriority(prflx_priority); if(mode == Ice176::Initiator) { pair.binding->setIceControlling(0); pair.binding->setUseCandidate(true); } else pair.binding->setIceControlled(0); pair.binding->start(); } } public slots: void lt_started() { printf("lt_started\n"); IceLocalTransport *sock = (IceLocalTransport *)sender(); int at = -1; for(int n = 0; n < localTransports.count(); ++n) { if(localTransports[n]->sock == sock) { at = n; break; } } if(at == -1) return; LocalTransport *lt = localTransports[at]; lt->started = true; CandidateInfo ci; ci.addr.addr = lt->sock->localAddress(); ci.addr.port = lt->sock->localPort(); ci.type = HostType; ci.componentId = lt->componentId; ci.priority = choose_default_priority(ci.type, 65535 - lt->addrAt, lt->isVpn, ci.componentId); ci.foundation = QString::number(lt->addrAt); ci.base = ci.addr; ci.network = lt->network; ci.id = randomCredential(10); // FIXME: ensure unique localCandidates += ci; int extAt = -1; for(int n = 0; n < extAddrs.count(); ++n) { if(extAddrs[n].base.addr == lt->sock->localAddress() && (extAddrs[n].portBase == -1 || extAddrs[n].portBase == lt->sock->localPort())) { extAt = n; break; } } if(extAt != -1) { CandidateInfo ci; ci.addr.addr = extAddrs[extAt].addr; ci.addr.port = (extAddrs[extAt].portBase != -1) ? extAddrs[extAt].portBase : lt->sock->localPort(); ci.type = ServerReflexiveType; ci.componentId = lt->componentId; ci.priority = choose_default_priority(ci.type, 65535 - lt->addrAt, lt->isVpn, ci.componentId); ci.foundation = QString::number(lt->addrAt) + 'e'; ci.base.addr = lt->sock->localAddress(); ci.base.port = lt->sock->localPort(); ci.network = lt->network; ci.id = randomCredential(10); // FIXME: ensure unique localCandidates += ci; } if(!stunAddr.isNull()) { lt->use_stun = true; if(stunType == Ice176::Relay) lt->sock->setStunService(IceLocalTransport::Relay, stunAddr, stunPort); else lt->sock->setStunService(IceLocalTransport::Basic, stunAddr, stunPort); // reduce gathering of STUN candidates to 4 seconds // when trickle mode is disabled lt->t = new QTimer(this); connect(lt->t, SIGNAL(timeout()), SLOT(lt_timeout())); lt->t->setSingleShot(true); lt->t->start(4000); printf("starting stun\n"); lt->sock->stunStart(); return; } tryFinishGather(); } void lt_stopped() { // TODO printf("lt_stopped\n"); } void lt_stunFinished() { printf("lt_stunFinished\n"); IceLocalTransport *sock = (IceLocalTransport *)sender(); int at = -1; for(int n = 0; n < localTransports.count(); ++n) { if(localTransports[n]->sock == sock) { at = n; break; } } if(at == -1) return; LocalTransport *lt = localTransports[at]; // already marked as finished? this can happen if we timed // out the operation from earlier. in that case just // ignore the event if(lt->stun_finished) { printf("ignoring\n"); return; } lt->t->stop(); lt->stun_finished = true; if(!lt->sock->serverReflexiveAddress().isNull()) { CandidateInfo ci; ci.addr.addr = lt->sock->serverReflexiveAddress(); ci.addr.port = lt->sock->serverReflexivePort(); ci.type = ServerReflexiveType; ci.componentId = lt->componentId; ci.priority = choose_default_priority(ci.type, 65535 - lt->addrAt, lt->isVpn, ci.componentId); ci.foundation = QString::number(lt->addrAt) + 's'; ci.base.addr = lt->sock->localAddress(); ci.base.port = lt->sock->localPort(); ci.network = lt->network; ci.id = randomCredential(10); // FIXME: ensure unique localCandidates += ci; } // TODO: relayed candidate tryFinishGather(); } void lt_error(XMPP::IceLocalTransport::Error e) { // TODO Q_UNUSED(e); printf("lt_error\n"); for(int n = 0; n < localTransports.count(); ++n) localTransports[n]->sock->disconnect(this); emit q->error(); } void lt_readyRead(XMPP::IceLocalTransport::TransmitPath path) { IceLocalTransport *sock = (IceLocalTransport *)sender(); int at = -1; for(int n = 0; n < localTransports.count(); ++n) { if(localTransports[n]->sock == sock) { at = n; break; } } if(at == -1) return; LocalTransport *lt = localTransports[at]; if(path == IceLocalTransport::Direct) { while(lt->sock->hasPendingDatagrams(path)) { QHostAddress fromAddr; int fromPort; QByteArray buf = lt->sock->readDatagram(path, &fromAddr, &fromPort); //printf("port %d: received packet (%d bytes)\n", lt->sock->localPort(), buf.size()); QString requser = localUser + ':' + peerUser; QByteArray reqkey = localPass.toUtf8(); StunMessage::ConvertResult result; StunMessage msg = StunMessage::fromBinary(buf, &result, StunMessage::MessageIntegrity | StunMessage::Fingerprint, reqkey); if(!msg.isNull() && (msg.mclass() == StunMessage::Request || msg.mclass() == StunMessage::Indication)) { printf("received validated request or indication\n"); QString user = QString::fromUtf8(msg.attribute(0x0006)); // USERNAME if(requser != user) { printf("user [%s] is wrong. it should be [%s]. skipping\n", qPrintable(user), qPrintable(requser)); continue; } if(msg.method() != 0x001) { printf("not a binding request. skipping\n"); continue; } StunMessage response; response.setClass(StunMessage::SuccessResponse); response.setMethod(0x001); response.setId(msg.id()); quint16 port16 = fromPort; quint32 addr4 = fromAddr.toIPv4Address(); QByteArray val(8, 0); quint8 *p = (quint8 *)val.data(); const quint8 *magic = response.magic(); p[0] = 0; p[1] = 0x01; p[2] = (port16 >> 8) & 0xff; p[2] ^= magic[0]; p[3] = port16 & 0xff; p[3] ^= magic[1]; p[4] = (addr4 >> 24) & 0xff; p[4] ^= magic[0]; p[5] = (addr4 >> 16) & 0xff; p[5] ^= magic[1]; p[6] = (addr4 >> 8) & 0xff; p[6] ^= magic[2]; p[7] = addr4 & 0xff; p[7] ^= magic[3]; QList list; StunMessage::Attribute attr; attr.type = 0x0020; attr.value = val; list += attr; response.setAttributes(list); QByteArray packet = response.toBinary(StunMessage::MessageIntegrity | StunMessage::Fingerprint, reqkey); lt->sock->writeDatagram(path, packet, fromAddr, fromPort); } else { QByteArray reskey = peerPass.toUtf8(); StunMessage msg = StunMessage::fromBinary(buf, &result, StunMessage::MessageIntegrity | StunMessage::Fingerprint, reskey); if(!msg.isNull() && (msg.mclass() == StunMessage::SuccessResponse || msg.mclass() == StunMessage::ErrorResponse)) { printf("received validated response\n"); // FIXME: this is so gross and completely defeats the point of having pools for(int n = 0; n < checkList.pairs.count(); ++n) { CandidatePair &pair = checkList.pairs[n]; if(pair.local.addr.addr == lt->sock->localAddress() && pair.local.addr.port == lt->sock->localPort()) pair.pool->writeIncomingMessage(msg); } } else { //printf("received some non-stun or invalid stun packet\n"); // FIXME: i don't know if this is good enough if(StunMessage::isProbablyStun(buf)) { printf("unexpected stun packet (loopback?), skipping.\n"); continue; } int at = -1; for(int n = 0; n < checkList.pairs.count(); ++n) { CandidatePair &pair = checkList.pairs[n]; if(pair.local.addr.addr == lt->sock->localAddress() && pair.local.addr.port == lt->sock->localPort()) { at = n; break; } } if(at == -1) { printf("the local transport does not seem to be associated with a candidate?!\n"); continue; } int componentIndex = checkList.pairs[at].local.componentId - 1; //printf("packet is considered to be application data for component index %d\n", componentIndex); in[componentIndex] += buf; emit q->readyRead(componentIndex); } } } } else // Relayed { // TODO } } void lt_datagramsWritten(XMPP::IceLocalTransport::TransmitPath path, int count) { // TODO Q_UNUSED(path); Q_UNUSED(count); } void lt_timeout() { QTimer *t = (QTimer *)sender(); int at = -1; for(int n = 0; n < localTransports.count(); ++n) { if(localTransports[n]->t == t) { at = n; break; } } if(at == -1) return; LocalTransport *lt = localTransports[at]; lt->stun_finished = true; // TODO: delete lt->t ? tryFinishGather(); } void pool_retransmit(XMPP::StunTransaction *trans) { StunTransactionPool *pool = (StunTransactionPool *)sender(); int at = -1; for(int n = 0; n < checkList.pairs.count(); ++n) { if(checkList.pairs[n].pool == pool) { at = n; break; } } if(at == -1) return; CandidatePair &pair = checkList.pairs[at]; at = -1; for(int n = 0; n < localTransports.count(); ++n) { if(pair.local.addr.addr == localTransports[n]->sock->localAddress() && pair.local.addr.port == localTransports[n]->sock->localPort()) { at = n; break; } } if(at == -1) return; LocalTransport *lt = localTransports[at]; printf("connectivity check from %s:%d to %s:%d\n", qPrintable(pair.local.addr.addr.toString()), pair.local.addr.port, qPrintable(pair.remote.addr.addr.toString()), pair.remote.addr.port); lt->sock->writeDatagram(IceLocalTransport::Direct, trans->packet(), pair.remote.addr.addr, pair.remote.addr.port); } void binding_success() { StunBinding *binding = (StunBinding *)sender(); int at = -1; for(int n = 0; n < checkList.pairs.count(); ++n) { if(checkList.pairs[n].binding == binding) { at = n; break; } } if(at == -1) return; printf("check success\n"); CandidatePair &pair = checkList.pairs[at]; // TODO: if we were cool, we'd do something with the peer // reflexive address received // TODO: we're also supposed to do triggered checks. except // that currently we check everything anyway so this is not // relevant // check if there's a candidate already valid at = -1; for(int n = 0; n < checkList.pairs.count(); ++n) { if(checkList.pairs[n].local.componentId == pair.local.componentId && checkList.pairs[n].isValid) { at = n; break; } } pair.isValid = true; if(at == -1) { emit q->componentReady(pair.local.componentId - 1); } else { printf("component %d already active, not signalling\n", pair.local.componentId); } } }; Ice176::Ice176(QObject *parent) : QObject(parent) { d = new Private(this); } Ice176::~Ice176() { delete d; } void Ice176::reset() { // TODO } void Ice176::setBasePort(int port) { d->basePort = port; } void Ice176::setLocalAddresses(const QList &addrs) { // TODO: dedup d->localAddrs = addrs; } void Ice176::setExternalAddresses(const QList &addrs) { // TODO: dedup d->extAddrs.clear(); foreach(const ExternalAddress &addr, addrs) { if(d->localAddrs.contains(addr.base)) d->extAddrs += addrs; } } void Ice176::setStunService(StunServiceType type, const QHostAddress &addr, int port) { d->stunType = type; d->stunAddr = addr; d->stunPort = port; } void Ice176::setComponentCount(int count) { d->componentCount = count; } void Ice176::start(Mode mode) { d->mode = mode; d->start(); } QString Ice176::localUfrag() const { return d->localUser; } QString Ice176::localPassword() const { return d->localPass; } void Ice176::setPeerUfrag(const QString &ufrag) { d->peerUser = ufrag; } void Ice176::setPeerPassword(const QString &pass) { d->peerPass = pass; } void Ice176::setStunUsername(const QString &user) { d->stunUser = user; } void Ice176::setStunPassword(const QCA::SecureArray &pass) { d->stunPass = pass; } void Ice176::addRemoteCandidates(const QList &list) { d->addRemoteCandidates(list); } bool Ice176::hasPendingDatagrams(int componentIndex) const { return !d->in[componentIndex].isEmpty(); } QByteArray Ice176::readDatagram(int componentIndex) { return d->in[componentIndex].takeFirst(); } void Ice176::writeDatagram(int componentIndex, const QByteArray &datagram) { int at = -1; for(int n = 0; n < d->checkList.pairs.count(); ++n) { if(d->checkList.pairs[n].local.componentId - 1 == componentIndex && d->checkList.pairs[n].isValid) { at = n; break; } } if(at == -1) return; Private::CandidatePair &pair = d->checkList.pairs[at]; at = -1; for(int n = 0; n < d->localTransports.count(); ++n) { if(d->localTransports[n]->sock->localAddress() == pair.local.addr.addr && d->localTransports[n]->sock->localPort() == pair.local.addr.port) { at = n; break; } } if(at == -1) return; Private::LocalTransport *lt = d->localTransports[at]; lt->sock->writeDatagram(IceLocalTransport::Direct, datagram, pair.remote.addr.addr, pair.remote.addr.port); // DOR-SR? QMetaObject::invokeMethod(this, "datagramsWritten", Qt::QueuedConnection, Q_ARG(int, componentIndex), Q_ARG(int, 1)); } } #include "ice176.moc" psi-0.14/iris/src/irisnet/noncore/stunbinding.cpp0000644000175000017500000001560711305557616020262 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "stunbinding.h" #include #include "stuntransaction.h" #include "stunmessage.h" namespace XMPP { // from stunmessage.cpp static void write32(quint8 *out, quint32 i) { out[0] = (i >> 24) & 0xff; out[1] = (i >> 16) & 0xff; out[2] = (i >> 8) & 0xff; out[3] = i & 0xff; } static void write64(quint8 *out, quint64 i) { out[0] = (i >> 56) & 0xff; out[1] = (i >> 48) & 0xff; out[2] = (i >> 40) & 0xff; out[3] = (i >> 32) & 0xff; out[4] = (i >> 24) & 0xff; out[5] = (i >> 16) & 0xff; out[6] = (i >> 8) & 0xff; out[7] = i & 0xff; } // pass valid magic and id pointers to do XOR-MAPPED-ADDRESS processing // pass 0 for magic and id to do MAPPED-ADDRESS processing static bool parse_mapped_address(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port) { // val is at least 4 bytes if(val.size() < 4) return false; const quint8 *p = (const quint8 *)val.data(); if(p[0] != 0) return false; quint16 _port; if(magic) { _port = p[2] ^ magic[0]; _port <<= 8; _port += p[3] ^ magic[1]; } else { _port = p[2]; _port <<= 8; _port += p[3]; } QHostAddress _addr; if(p[1] == 0x01) { // ipv4 // val is 8 bytes in this case if(val.size() != 8) return false; quint32 addr4; if(magic) { addr4 = p[4] ^ magic[0]; addr4 <<= 8; addr4 += p[5] ^ magic[1]; addr4 <<= 8; addr4 += p[6] ^ magic[2]; addr4 <<= 8; addr4 += p[7] ^ magic[3]; } else { addr4 = p[4]; addr4 <<= 8; addr4 += p[5]; addr4 <<= 8; addr4 += p[6]; addr4 <<= 8; addr4 += p[7]; } _addr = QHostAddress(addr4); } else if(p[1] == 0x02) { // ipv6 // val is 20 bytes in this case if(val.size() != 20) return false; quint8 tmp[16]; for(int n = 0; n < 16; ++n) { quint8 x; if(n < 4) x = magic[n]; else x = id[n - 4]; tmp[n] = p[n + 4] ^ x; } _addr = QHostAddress(tmp); } else return false; *addr = _addr; *port = _port; return true; } class StunBinding::Private : public QObject { Q_OBJECT public: StunBinding *q; StunTransactionPool *pool; StunTransaction *trans; QHostAddress addr; int port; QString errorString; bool use_extPriority, use_extIceControlling, use_extIceControlled; quint32 extPriority; bool extUseCandidate; quint64 extIceControlling, extIceControlled; Private(StunBinding *_q) : QObject(_q), q(_q), pool(0), trans(0), use_extPriority(false), use_extIceControlling(false), use_extIceControlled(false), extUseCandidate(false) { } ~Private() { if(trans) pool->remove(trans); } void start() { Q_ASSERT(!trans); trans = new StunTransaction(this); connect(trans, SIGNAL(finished(const XMPP::StunMessage &)), SLOT(trans_finished(const XMPP::StunMessage &))); connect(trans, SIGNAL(error(XMPP::StunTransaction::Error)), SLOT(trans_error(XMPP::StunTransaction::Error))); StunMessage message; message.setClass(StunMessage::Request); message.setMethod(0x001); QByteArray id = pool->generateId(); message.setId((const quint8 *)id.data()); QList list; if(use_extPriority) { StunMessage::Attribute a; a.type = 0x0024; // PRIORITY QByteArray val(4, 0); write32((quint8 *)val.data(), extPriority); a.value = val; list += a; } if(extUseCandidate) { StunMessage::Attribute a; a.type = 0x0025; // USE-CANDIDATE list += a; } if(use_extIceControlling) { StunMessage::Attribute a; a.type = 0x802a; QByteArray val(8, 0); write64((quint8 *)val.data(), extIceControlling); a.value = val; list += a; } if(use_extIceControlled) { StunMessage::Attribute a; a.type = 0x0029; QByteArray val(8, 0); write64((quint8 *)val.data(), extIceControlled); a.value = val; list += a; } message.setAttributes(list); trans->start(pool->mode(), message, pool->username(), pool->password()); pool->insert(trans); } private slots: void trans_finished(const XMPP::StunMessage &response) { pool->remove(trans); trans = 0; if(response.mclass() == StunMessage::ErrorResponse) { errorString = "Server responded with an error."; emit q->error(StunBinding::ErrorRejected); return; } QHostAddress saddr; quint16 sport = 0; QByteArray val; val = response.attribute(0x0020); if(!val.isNull()) { if(!parse_mapped_address(val, response.magic(), response.id(), &saddr, &sport)) { errorString = "Unable to parse XOR-MAPPED-ADDRESS response."; emit q->error(StunBinding::ErrorProtocol); return; } } else { val = response.attribute(0x0001); if(!val.isNull()) { if(!parse_mapped_address(val, 0, 0, &saddr, &sport)) { errorString = "Unable to parse MAPPED-ADDRESS response."; emit q->error(StunBinding::ErrorProtocol); return; } } else { errorString = "Response does not contain XOR-MAPPED-ADDRESS or MAPPED-ADDRESS."; emit q->error(StunBinding::ErrorProtocol); return; } } addr = saddr; port = sport; emit q->success(); } void trans_error(XMPP::StunTransaction::Error e) { pool->remove(trans); trans = 0; if(e == StunTransaction::ErrorTimeout) { errorString = "Request timed out."; emit q->error(StunBinding::ErrorTimeout); } else { errorString = "Generic transaction error."; emit q->error(StunBinding::ErrorGeneric); } } }; StunBinding::StunBinding(StunTransactionPool *pool) : QObject(pool) { d = new Private(this); d->pool = pool; } StunBinding::~StunBinding() { delete d; } void StunBinding::setPriority(quint32 i) { d->use_extPriority = true; d->extPriority = i; } void StunBinding::setUseCandidate(bool enabled) { d->extUseCandidate = enabled; } void StunBinding::setIceControlling(quint64 i) { d->use_extIceControlling = true; d->extIceControlling = i; } void StunBinding::setIceControlled(quint64 i) { d->use_extIceControlled = true; d->extIceControlled = i; } void StunBinding::start() { d->start(); } QHostAddress StunBinding::reflexiveAddress() const { return d->addr; } int StunBinding::reflexivePort() const { return d->port; } QString StunBinding::errorString() const { return d->errorString; } } #include "stunbinding.moc" psi-0.14/iris/src/irisnet/noncore/icelocaltransport.h0000644000175000017500000000477511305557616021137 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef ICELOCALTRANSPORT_H #define ICELOCALTRANSPORT_H #include #include class QHostAddress; namespace QCA { class SecureArray; } namespace XMPP { // this class manages a single port on a single interface, including the // relationship with an associated STUN/TURN server. if TURN is used, this // class offers two UDP channels (direct or relayed), otherwise it offers // just one UDP channel (direct). class IceLocalTransport : public QObject { Q_OBJECT public: enum Error { ErrorGeneric }; enum StunServiceType { Basic, Relay }; enum TransmitPath { Direct, Relayed }; IceLocalTransport(QObject *parent = 0); ~IceLocalTransport(); void start(const QHostAddress &addr, int port = -1); void stop(); void setStunService(StunServiceType type, const QHostAddress &addr, int port); void setStunUsername(const QString &user); void setStunPassword(const QCA::SecureArray &pass); // obtain relay / reflexive void stunStart(); QHostAddress localAddress() const; int localPort() const; QHostAddress serverReflexiveAddress() const; int serverReflexivePort() const; QHostAddress relayedAddress() const; int relayedPort() const; bool hasPendingDatagrams(TransmitPath path) const; QByteArray readDatagram(TransmitPath path, QHostAddress *addr, int *port); void writeDatagram(TransmitPath path, const QByteArray &buf, const QHostAddress &addr, int port); signals: void started(); void stopped(); void stunFinished(); void error(XMPP::IceLocalTransport::Error e); void readyRead(XMPP::IceLocalTransport::TransmitPath path); void datagramsWritten(XMPP::IceLocalTransport::TransmitPath path, int count); private: class Private; friend class Private; Private *d; }; } #endif psi-0.14/iris/src/irisnet/noncore/stunmessage.h0000644000175000017500000000450411305557616017733 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef STUNMESSAGE_H #define STUNMESSAGE_H #include #include #include namespace XMPP { class StunMessage { public: enum Class { Request, SuccessResponse, ErrorResponse, Indication }; enum ValidationFlags { Fingerprint = 0x01, // you must have the hmac(sha1) algorithm in QCA to use MessageIntegrity = 0x02 }; enum ConvertResult { ConvertGood, ErrorFormat, ErrorFingerprint, ErrorMessageIntegrity, ErrorConvertUnknown = 64 }; class Attribute { public: quint16 type; QByteArray value; }; StunMessage(); StunMessage(const StunMessage &from); ~StunMessage(); StunMessage & operator=(const StunMessage &from); bool isNull() const; Class mclass() const; quint16 method() const; const quint8 *magic() const; // 4 bytes const quint8 *id() const; // 12 bytes QList attributes() const; // returns the first instance or null QByteArray attribute(quint16 type) const; void setClass(Class mclass); void setMethod(quint16 method); void setMagic(const quint8 *magic); // 4 bytes void setId(const quint8 *id); // 12 bytes void setAttributes(const QList &attribs); QByteArray toBinary(int validationFlags = 0, const QByteArray &key = QByteArray()) const; static StunMessage fromBinary(const QByteArray &a, ConvertResult *result = 0, int validationFlags = 0, const QByteArray &key = QByteArray()); // minimal 3-field check static bool isProbablyStun(const QByteArray &a); private: class Private; QSharedDataPointer d; }; } #endif psi-0.14/iris/src/irisnet/noncore/icelocaltransport.cpp0000644000175000017500000003425011305557616021461 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "icelocaltransport.h" #include #include #include #include "objectsession.h" #include "stunmessage.h" #include "stuntransaction.h" #include "stunbinding.h" #include "stunallocate.h" // don't queue more incoming packets than this per transmit path #define MAX_PACKET_QUEUE 64 namespace XMPP { //---------------------------------------------------------------------------- // SafeUdpSocket //---------------------------------------------------------------------------- // DOR-safe wrapper for QUdpSocket class SafeUdpSocket : public QObject { Q_OBJECT private: ObjectSession sess; QUdpSocket *sock; int writtenCount; public: SafeUdpSocket(QObject *parent = 0) : QObject(parent), sess(this) { sock = new QUdpSocket(this); connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64))); writtenCount = 0; } ~SafeUdpSocket() { sock->disconnect(this); sock->setParent(0); sock->deleteLater(); } bool bind(const QHostAddress &addr, quint16 port = 0) { return sock->bind(addr, port); } quint16 localPort() const { return sock->localPort(); } bool hasPendingDatagrams() const { return sock->hasPendingDatagrams(); } QByteArray readDatagram(QHostAddress *address = 0, quint16 *port = 0) { if(!sock->hasPendingDatagrams()) return QByteArray(); QByteArray buf; buf.resize(sock->pendingDatagramSize()); sock->readDatagram(buf.data(), buf.size(), address, port); return buf; } void writeDatagram(const QByteArray &buf, const QHostAddress &address, quint16 port) { sock->writeDatagram(buf, address, port); } signals: void readyRead(); void datagramsWritten(int count); private slots: void sock_readyRead() { emit readyRead(); } void sock_bytesWritten(qint64 bytes) { Q_UNUSED(bytes); ++writtenCount; sess.deferExclusive(this, "processWritten"); } void processWritten() { int count = writtenCount; writtenCount = 0; emit datagramsWritten(count); } }; //---------------------------------------------------------------------------- // IceLocalTransport //---------------------------------------------------------------------------- class IceLocalTransport::Private : public QObject { Q_OBJECT public: enum WriteType { InternalWrite, DirectWrite, RelayedWrite }; class Datagram { public: QHostAddress addr; int port; QByteArray buf; }; IceLocalTransport *q; ObjectSession sess; SafeUdpSocket *sock; StunTransactionPool *pool; StunBinding *stunBinding; StunAllocate *stunAllocate; bool alloc_started; bool changing_perms; QHostAddress addr; int port; QHostAddress refAddr; int refPort; QHostAddress relAddr; int relPort; QHostAddress stunAddr; int stunPort; IceLocalTransport::StunServiceType stunType; QString stunUser; QCA::SecureArray stunPass; QList in; QList inRelayed; QList outRelayed; QList pendingWrites; QList pendingPerms; Private(IceLocalTransport *_q) : QObject(_q), q(_q), sess(this), sock(0), stunBinding(0), stunAllocate(0), alloc_started(false), changing_perms(false), port(-1), refPort(-1), relPort(-1) { pool = new StunTransactionPool(StunTransaction::Udp, this); connect(pool, SIGNAL(retransmit(XMPP::StunTransaction *)), SLOT(pool_retransmit(XMPP::StunTransaction *))); } ~Private() { reset(); } void reset() { sess.reset(); delete stunBinding; stunBinding = 0; delete stunAllocate; stunAllocate = 0; alloc_started = false; changing_perms = false; delete sock; sock = 0; addr = QHostAddress(); port = -1; refAddr = QHostAddress(); refPort = -1; relAddr = QHostAddress(); relPort = -1; in.clear(); inRelayed.clear(); outRelayed.clear(); pendingWrites.clear(); } void start() { Q_ASSERT(!sock); sock = new SafeUdpSocket(this); connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(sock, SIGNAL(datagramsWritten(int)), SLOT(sock_datagramsWritten(int))); sess.defer(this, "postStart"); } void stop() { Q_ASSERT(sock); if(stunAllocate) stunAllocate->stop(); else sess.defer(this, "postStop"); } void stunStart() { Q_ASSERT(!stunBinding && !stunAllocate); if(stunType == IceLocalTransport::Relay) { stunAllocate = new StunAllocate(pool); connect(stunAllocate, SIGNAL(started()), SLOT(allocate_started())); connect(stunAllocate, SIGNAL(stopped()), SLOT(allocate_stopped())); connect(stunAllocate, SIGNAL(error(XMPP::StunAllocate::Error)), SLOT(allocate_error(XMPP::StunAllocate::Error))); connect(stunAllocate, SIGNAL(permissionsChanged()), SLOT(allocate_permissionsChanged())); connect(stunAllocate, SIGNAL(readyRead()), SLOT(allocate_readyRead())); connect(stunAllocate, SIGNAL(datagramsWritten(int)), SLOT(allocate_datagramsWritten(int))); stunAllocate->start(); } else // Basic { stunBinding = new StunBinding(pool); connect(stunBinding, SIGNAL(success()), SLOT(binding_success())); connect(stunBinding, SIGNAL(error(XMPP::StunBinding::Error)), SLOT(binding_error(XMPP::StunBinding::Error))); stunBinding->start(); } } void tryWriteRelayed(const QByteArray &buf, const QHostAddress &addr, int port) { QList perms = stunAllocate->permissions(); // do we have permission to relay to this address yet? if(perms.contains(addr)) { writeRelayed(buf, addr, port); } else { // no? then queue while we ask the server to grant Datagram dg; dg.addr = addr; dg.port = port; dg.buf = buf; outRelayed += dg; if(!changing_perms) { perms += addr; stunAllocate->setPermissions(perms); } else pendingPerms += addr; } } void writeRelayed(const QByteArray &buf, const QHostAddress &addr, int port) { QByteArray enc = stunAllocate->encode(buf, addr, port); if(enc.isEmpty()) { printf("Warning: could not encode packet for sending.\n"); return; } pendingWrites += RelayedWrite; sock->writeDatagram(enc, stunAddr, stunPort); } // return true if we received a relayed packet bool processIncomingStun(const QByteArray &buf, Datagram *dg) { // this might be a ChannelData message. check the first // two bits: if(stunAllocate && alloc_started && buf.size() >= 1 && buf[0] & 0xC0 == 0x40) { QHostAddress fromAddr; int fromPort; QByteArray buf = stunAllocate->decode(buf, &fromAddr, &fromPort); if(fromAddr.isNull()) { printf("Warning: server responded with what appears to be an invalid packet, skipping.\n"); return false; } dg->addr = fromAddr; dg->port = fromPort; dg->buf = buf; return true; } // else, interpret it as a stun message StunMessage message = StunMessage::fromBinary(buf); if(message.isNull()) { printf("Warning: server responded with what doesn't seem to be a STUN packet, skipping.\n"); return false; } // indication? maybe it's a relayed packet if(message.mclass() == StunMessage::Indication) { QHostAddress fromAddr; int fromPort; QByteArray buf = stunAllocate->decode(message, &fromAddr, &fromPort); if(fromAddr.isNull()) { printf("Warning: server responded with an unknown Indication packet, skipping.\n"); return false; } dg->addr = fromAddr; dg->port = fromPort; dg->buf = buf; return true; } if(!pool->writeIncomingMessage(message)) { printf("Warning: received unexpected message, skipping.\n"); } return false; } public slots: void postStart() { bool ok; if(port != -1) ok = sock->bind(addr, port); else ok = sock->bind(addr, 0); if(ok) { port = sock->localPort(); emit q->started(); } else { reset(); emit q->error(IceLocalTransport::ErrorGeneric); } } void postStop() { reset(); emit q->stopped(); } void sock_readyRead() { ObjectSessionWatcher watcher(&sess); QList dreads; QList rreads; while(sock->hasPendingDatagrams()) { QHostAddress from; quint16 fromPort; QByteArray buf = sock->readDatagram(&from, &fromPort); Datagram dg; if(from == stunAddr && fromPort == stunPort) { // came from stun server if(processIncomingStun(buf, &dg)) rreads += dg; if(!watcher.isValid()) return; } else { dg.addr = from; dg.port = fromPort; dg.buf = buf; dreads += dg; } } if(dreads.count() > 0) { in += dreads; emit q->readyRead(IceLocalTransport::Direct); if(!watcher.isValid()) return; } if(rreads.count() > 0) { inRelayed += rreads; emit q->readyRead(IceLocalTransport::Relayed); } } void sock_datagramsWritten(int count) { Q_ASSERT(count <= pendingWrites.count()); int dwrites = 0; int rwrites = 0; for(int n = 0; n < count; ++n) { WriteType type = pendingWrites.takeFirst(); if(type == DirectWrite) ++dwrites; else if(type == RelayedWrite) ++rwrites; } ObjectSessionWatcher watch(&sess); if(dwrites > 0) { emit q->datagramsWritten(IceLocalTransport::Direct, dwrites); if(!watch.isValid()) return; } if(rwrites > 0) emit q->datagramsWritten(IceLocalTransport::Relayed, rwrites); } void pool_retransmit(XMPP::StunTransaction *trans) { // warning: read StunTransactionPool docs before modifying // this function pendingWrites += InternalWrite; sock->writeDatagram(trans->packet(), stunAddr, stunPort); } void binding_success() { refAddr = stunBinding->reflexiveAddress(); refPort = stunBinding->reflexivePort(); delete stunBinding; stunBinding = 0; emit q->stunFinished(); } void binding_error(XMPP::StunBinding::Error e) { Q_UNUSED(e); delete stunBinding; stunBinding = 0; emit q->stunFinished(); } void allocate_started() { refAddr = stunAllocate->reflexiveAddress(); refPort = stunAllocate->reflexivePort(); relAddr = stunAllocate->relayedAddress(); relPort = stunAllocate->relayedPort(); alloc_started = true; emit q->stunFinished(); } void allocate_stopped() { // allocation deleted delete stunAllocate; stunAllocate = 0; alloc_started = false; postStop(); } void allocate_error(XMPP::StunAllocate::Error e) { delete stunAllocate; stunAllocate = 0; bool wasStarted = alloc_started; alloc_started = false; // this means our relay died on us. in the future we might // consider reporting this if(wasStarted) return; // if we get an error during initialization, fall back to // binding if(e != StunAllocate::ErrorTimeout) { stunType = IceLocalTransport::Basic; stunStart(); } else { emit q->stunFinished(); } } void allocate_permissionsChanged() { // get updated list QList perms = stunAllocate->permissions(); // extract any sendable packets from the out queue QList sendable; for(int n = 0; n < outRelayed.count(); ++n) { if(perms.contains(outRelayed[n].addr)) { sendable += outRelayed[n]; outRelayed.removeAt(n); --n; // adjust position } } // and send them foreach(const Datagram &dg, sendable) writeRelayed(dg.buf, dg.addr, dg.port); changing_perms = false; if(!pendingPerms.isEmpty()) { perms += pendingPerms; pendingPerms.clear(); changing_perms = true; stunAllocate->setPermissions(perms); } } }; IceLocalTransport::IceLocalTransport(QObject *parent) : QObject(parent) { d = new Private(this); } IceLocalTransport::~IceLocalTransport() { delete d; } void IceLocalTransport::start(const QHostAddress &addr, int port) { d->addr = addr; d->port = port; d->start(); } void IceLocalTransport::stop() { d->stop(); } void IceLocalTransport::setStunService(StunServiceType type, const QHostAddress &addr, int port) { d->stunType = type; d->stunAddr = addr; d->stunPort = port; } void IceLocalTransport::setStunUsername(const QString &user) { d->stunUser = user; } void IceLocalTransport::setStunPassword(const QCA::SecureArray &pass) { d->stunPass = pass; } void IceLocalTransport::stunStart() { d->stunStart(); } QHostAddress IceLocalTransport::localAddress() const { return d->addr; } int IceLocalTransport::localPort() const { return d->port; } QHostAddress IceLocalTransport::serverReflexiveAddress() const { return d->refAddr; } int IceLocalTransport::serverReflexivePort() const { return d->refPort; } QHostAddress IceLocalTransport::relayedAddress() const { return d->relAddr; } int IceLocalTransport::relayedPort() const { return d->relPort; } bool IceLocalTransport::hasPendingDatagrams(TransmitPath path) const { if(path == Direct) return !d->in.isEmpty(); else if(path == Relayed) return !d->inRelayed.isEmpty(); else { Q_ASSERT(0); return false; } } QByteArray IceLocalTransport::readDatagram(TransmitPath path, QHostAddress *addr, int *port) { QList *in = 0; if(path == Direct) in = &d->in; else if(path == Relayed) in = &d->inRelayed; else Q_ASSERT(0); if(!in->isEmpty()) { Private::Datagram datagram = in->takeFirst(); *addr = datagram.addr; *port = datagram.port; return datagram.buf; } else { *addr = QHostAddress(); *port = -1; return QByteArray(); } } void IceLocalTransport::writeDatagram(TransmitPath path, const QByteArray &buf, const QHostAddress &addr, int port) { if(path == Direct) { d->pendingWrites += Private::DirectWrite; d->sock->writeDatagram(buf, addr, port); } else if(path == Relayed) { if(d->stunAllocate && d->alloc_started) d->tryWriteRelayed(buf, addr, port); } else Q_ASSERT(0); } } #include "icelocaltransport.moc" psi-0.14/iris/src/irisnet/noncore/stunbinding.h0000644000175000017500000000314511305557616017721 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef STUNBINDING_H #define STUNBINDING_H #include class QHostAddress; namespace XMPP { class StunTransactionPool; class StunBinding : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, ErrorTimeout, ErrorRejected, ErrorProtocol }; StunBinding(StunTransactionPool *pool); ~StunBinding(); // for ICE-use only void setPriority(quint32 i); void setUseCandidate(bool enabled); void setIceControlling(quint64 i); void setIceControlled(quint64 i); void start(); QHostAddress reflexiveAddress() const; int reflexivePort() const; // non-translatable diagnostic string for convenience QString errorString() const; signals: void success(); void error(XMPP::StunBinding::Error e); private: Q_DISABLE_COPY(StunBinding) class Private; friend class Private; Private *d; }; } #endif psi-0.14/iris/src/irisnet/noncore/stunmessage.cpp0000644000175000017500000004255311305557616020274 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "stunmessage.h" #include #include #define ENSURE_D { if(!d) d = new Private; } namespace XMPP { // some attribute types we need to explicitly support enum { AttribMessageIntegrity = 0x0008, AttribFingerprint = 0x8028 }; // adapted from public domain source by Ross Williams and Eric Durbin unsigned long crctable[256] = { 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL }; class Crc32 { private: quint32 result; public: Crc32() { clear(); } void clear() { result = 0xffffffff; } void update(const QByteArray &in) { for(int n = 0; n < in.size(); ++n) result = (result >> 8) ^ (crctable[(result & 0xff) ^ (quint8)in[n]]); } quint32 final() { return result ^= 0xffffffff; } static quint32 process(const QByteArray &in) { Crc32 c; c.update(in); return c.final(); } }; static quint8 magic_cookie[4] = { 0x21, 0x12, 0xA4, 0x42 }; static quint16 read16(const quint8 *in) { quint16 out = in[0]; out <<= 8; out += in[1]; return out; } static quint32 read32(const quint8 *in) { quint32 out = in[0]; out <<= 8; out += in[1]; out <<= 8; out += in[2]; out <<= 8; out += in[3]; return out; } static void write16(quint8 *out, quint16 i) { out[0] = (i >> 8) & 0xff; out[1] = i & 0xff; } static void write32(quint8 *out, quint32 i) { out[0] = (i >> 24) & 0xff; out[1] = (i >> 16) & 0xff; out[2] = (i >> 8) & 0xff; out[3] = i & 0xff; } // do 3-field check of stun packet // returns length of packet not counting the header, or -1 on error static int check_and_get_length(const QByteArray &buf) { // stun packets are at least 20 bytes if(buf.size() < 20) return -1; // minimal 3-field check // top 2 bits of packet must be 0 if(buf[0] & 0xC0) return -1; const quint8 *p = (const quint8 *)buf.data(); quint16 mlen = read16(p + 2); // bottom 2 bits of message length field must be 0 if(mlen & 0x03) return -1; // (also, the message length should be a reasonable size) if(mlen + 20 > buf.size()) return -1; // magic cookie must be set if(memcmp(p + 4, magic_cookie, 4) != 0) return -1; return mlen; } #define ATTRIBUTE_AREA_START 20 #define ATTRIBUTE_AREA_MAX 65535 #define ATTRIBUTE_VALUE_MAX 65531 // note: because the attribute area of the packet has a maximum size of // 2^16-1, and each attribute itself has a 4 byte header, it follows that // the maximum size of an attribute's value is 2^16-5. this means that, // even if padded with up to 3 bytes, the physical size of an attribute's // value will not overflow a 16-bit unsigned integer. static quint16 round_up_length(quint16 in) { Q_ASSERT(in <= ATTRIBUTE_VALUE_MAX); quint16 out = in; quint16 remainder = out % 4; if(remainder != 0) out += (4 - remainder); return out; } // buf = entire stun packet // offset = byte index of current attribute (first is offset=20) // type = take attribute type // len = take attribute value length (value is at offset + 4) // returns offset of next attribute, -1 if no more static int get_attribute_props(const QByteArray &buf, int offset, quint16 *type, int *len) { Q_ASSERT(offset >= ATTRIBUTE_AREA_START); const quint8 *p = (const quint8 *)buf.data(); // need at least 4 bytes for an attribute if(offset + 4 > buf.size()) return -1; quint16 _type = read16(p + offset); offset += 2; quint16 _alen = read16(p + offset); offset += 2; // get physical length. stun attributes are 4-byte aligned, and may // contain 0-3 bytes of padding. quint16 plen = round_up_length(_alen); if(offset + plen > buf.size()) return -1; *type = _type; *len = _alen; return offset + plen; } // buf = entire stun packet // type = attribute type to find // len = take attribute value length (value is at offset + 4) // next = take offset of next attribute // returns offset of found attribute, -1 if not found static int find_attribute(const QByteArray &buf, quint16 type, int *len, int *next = 0) { int at = ATTRIBUTE_AREA_START; quint16 _type; int _len; int _next; while(1) { _next = get_attribute_props(buf, at, &_type, &_len); if(_next == -1) break; if(_type == type) { *len = _len; if(next) *next = _next; return at; } at = _next; } return -1; } // buf = stun packet to append attribute to // type = type of attribute // len = length of value // returns offset of new attribute, or -1 if it can't fit // note: attribute value is located at offset + 4 and is uninitialized // note: padding following attribute is zeroed out static int append_attribute_uninitialized(QByteArray *buf, quint16 type, int len) { if(len > ATTRIBUTE_VALUE_MAX) return -1; quint16 alen = (quint16)len; quint16 plen = round_up_length(alen); if((buf->size() - ATTRIBUTE_AREA_START) + 4 + plen > ATTRIBUTE_AREA_MAX) return -1; int at = buf->size(); buf->resize(buf->size() + 4 + plen); quint8 *p = (quint8 *)buf->data(); write16(p + at, type); write16(p + at + 2, alen); // padding for(int n = 0; n < plen - alen; ++n) p[at + alen + n] = 0; return at; } static quint32 fingerprint_calc(const quint8 *buf, int size) { QByteArray region = QByteArray::fromRawData((const char *)buf, size); return Crc32::process(region) ^ 0x5354554e; } static QByteArray message_integrity_calc(const quint8 *buf, int size, const QByteArray &key) { QCA::MessageAuthenticationCode hmac("hmac(sha1)", key); QByteArray region = QByteArray::fromRawData((const char *)buf, size); QByteArray result = hmac.process(region).toByteArray(); Q_ASSERT(result.size() == 20); return result; } // look for fingerprint attribute and confirm it // buf = entire stun packet // returns true if fingerprint attribute exists and is correct static bool fingerprint_check(const QByteArray &buf) { int at, len; at = find_attribute(buf, AttribFingerprint, &len); if(at == -1 || len != 4) // value must be 4 bytes return false; const quint8 *p = (const quint8 *)buf.data(); quint32 fpval = read32(p + at + 4); quint32 fpcalc = fingerprint_calc(p, at); if(fpval == fpcalc) return true; else return false; } // copy the input buffer and prepare for message integrity checking. the // packet is truncated after the message-integrity attribute (since nothing // after it is protected), and the packet length is adjusted in the header // accordingly. // buf = input stun packet // out = take output stun packet // offset = take offset of message-integrity attribute // returns true if message-integrity attribute exists and packet is prepared // note: message-integrity value is at offset + 4 and is exactly 20 bytes static bool message_integrity_prep(const QByteArray &buf, QByteArray *out, int *offset) { int at, len, next; at = find_attribute(buf, AttribMessageIntegrity, &len, &next); if(at == -1 || len != 20) // value must be 20 bytes return false; // prepare new attribute area size int i = next - ATTRIBUTE_AREA_START; // new value must be divisible by 4 if(i % 4 != 0) return false; // copy truncated packet *out = buf.mid(0, next); // set new length in header quint16 newlen = (quint16)i; write16((quint8 *)out->data() + 2, newlen); *offset = at; return true; } // confirm message integrity // buf = prepared stun packet (from message_integrity_prep()) // offset = offset of message-integrity attribute // key = the HMAC key // returns true if correct static bool message_integrity_check(const QByteArray &buf, int offset, const QByteArray &key) { QByteArray mival = QByteArray::fromRawData(buf.data() + offset + 4, 20); QByteArray micalc = message_integrity_calc((const quint8 *)buf.data(), offset, key); if(mival == micalc) return true; else return false; } class StunMessage::Private : public QSharedData { public: StunMessage::Class mclass; quint16 method; quint8 magic[4]; quint8 id[12]; QList attribs; Private() { mclass = (StunMessage::Class)-1; method = 0; memcpy(magic, magic_cookie, 4); memset(id, 0, 12); } }; StunMessage::StunMessage() : d(0) { } StunMessage::StunMessage(const StunMessage &from) : d(from.d) { } StunMessage::~StunMessage() { } StunMessage & StunMessage::operator=(const StunMessage &from) { d = from.d; return *this; } bool StunMessage::isNull() const { return (d ? false: true); } StunMessage::Class StunMessage::mclass() const { Q_ASSERT(d); return d->mclass; } quint16 StunMessage::method() const { Q_ASSERT(d); return d->method; } const quint8 *StunMessage::magic() const { Q_ASSERT(d); return d->magic; } const quint8 *StunMessage::id() const { Q_ASSERT(d); return d->id; } QList StunMessage::attributes() const { Q_ASSERT(d); return d->attribs; } QByteArray StunMessage::attribute(quint16 type) const { Q_ASSERT(d); foreach(const Attribute &i, d->attribs) { if(i.type == type) return i.value; } return QByteArray(); } void StunMessage::setClass(Class mclass) { ENSURE_D d->mclass = mclass; } void StunMessage::setMethod(quint16 method) { ENSURE_D d->method = method; } void StunMessage::setMagic(const quint8 *magic) { ENSURE_D memcpy(d->magic, magic, 4); } void StunMessage::setId(const quint8 *id) { ENSURE_D memcpy(d->id, id, 12); } void StunMessage::setAttributes(const QList &attribs) { ENSURE_D d->attribs = attribs; } QByteArray StunMessage::toBinary(int validationFlags, const QByteArray &key) const { Q_ASSERT(d); // header QByteArray buf(20, 0); quint8 *p = (quint8 *)buf.data(); quint8 classbits = 0; if(d->mclass == Request) classbits = 0; // 00 else if(d->mclass == Indication) classbits = 1; // 01 else if(d->mclass == SuccessResponse) classbits = 2; // 10 else if(d->mclass == ErrorResponse) classbits = 3; // 11 else Q_ASSERT(0); // method bits are split into 3 sections quint16 m1, m2, m3; m1 = d->method & 0x0f80; // M7-11 m1 <<= 2; m2 = d->method & 0x0070; // M4-6 m2 <<= 1; m3 = d->method & 0x000f; // M0-3 // class bits are split into 2 sections quint16 c1, c2; c1 = classbits & 0x02; // C1 c1 <<= 7; c2 = classbits & 0x01; // C0 c2 <<= 4; quint16 type = m1 | m2 | m3 | c1 | c2; write16(p, type); write16(p + 2, 0); memcpy(p + 4, d->magic, 4); memcpy(p + 8, d->id, 12); foreach(const Attribute &i, d->attribs) { int at = append_attribute_uninitialized(&buf, i.type, i.value.size()); if(at == -1) return QByteArray(); memcpy(buf.data() + at + 4, i.value.data(), i.value.size()); } // set attribute area size write16(p + 2, buf.size() - ATTRIBUTE_AREA_START); if(validationFlags & MessageIntegrity) { quint16 alen = 20; // size of hmac(sha1) int at = append_attribute_uninitialized(&buf, AttribMessageIntegrity, alen); if(at == -1) return QByteArray(); p = (quint8 *)buf.data(); // follow the resize // set attribute area size to include the new attribute write16(p + 2, buf.size() - ATTRIBUTE_AREA_START); // now calculate the hash and fill in the value QByteArray result = message_integrity_calc(p, at, key); Q_ASSERT(result.size() == alen); memcpy(p + at + 4, result.data(), alen); } if(validationFlags & Fingerprint) { quint16 alen = 4; // size of crc32 int at = append_attribute_uninitialized(&buf, AttribFingerprint, alen); if(at == -1) return QByteArray(); p = (quint8 *)buf.data(); // follow the resize // set attribute area size to include the new attribute write16(p + 2, buf.size() - ATTRIBUTE_AREA_START); // now calculate the fingerprint and fill in the value quint32 fpcalc = fingerprint_calc(p, at); write32(p + at + 4, fpcalc); } return buf; } StunMessage StunMessage::fromBinary(const QByteArray &a, ConvertResult *result, int validationFlags, const QByteArray &key) { int mlen = check_and_get_length(a); if(mlen == -1) { if(result) *result = ErrorFormat; return StunMessage(); } if(validationFlags & Fingerprint) { if(!fingerprint_check(a)) { if(result) *result = ErrorFingerprint; return StunMessage(); } } QByteArray in; if(validationFlags & MessageIntegrity) { int offset; if(!message_integrity_prep(a, &in, &offset)) { if(result) *result = ErrorMessageIntegrity; return StunMessage(); } if(!message_integrity_check(in, offset, key)) { if(result) *result = ErrorMessageIntegrity; return StunMessage(); } } else in = a; // all validating complete, now just parse the packet const quint8 *p = (const quint8 *)in.data(); // method bits are split into 3 sections quint16 m1, m2, m3; m1 = p[0] & 0x3e; // M7-11 m1 <<= 6; m2 = p[1] & 0xe0; // M4-6 m2 >>= 1; m3 = p[1] & 0x0f; // M0-3 // class bits are split into 2 sections quint8 c1, c2; c1 = p[0] & 0x01; // C1 c1 <<= 1; c2 = p[1] & 0x10; // C0 c2 >>= 4; quint16 method = m1 | m2 | m3; quint8 classbits = c1 | c2; Class mclass; if(classbits == 0) // 00 mclass = Request; else if(classbits == 1) // 01 mclass = Indication; else if(classbits == 2) // 10 mclass = SuccessResponse; else // 11 mclass = ErrorResponse; StunMessage out; out.setClass(mclass); out.setMethod(method); out.setMagic(p + 4); out.setId(p + 8); QList list; int at = ATTRIBUTE_AREA_START; while(1) { quint16 type; int len; int next; next = get_attribute_props(in, at, &type, &len); if(next == -1) break; Attribute attrib; attrib.type = type; attrib.value = in.mid(at + 4, len); list += attrib; at = next; } out.setAttributes(list); if(result) *result = ConvertGood; return out; } bool StunMessage::isProbablyStun(const QByteArray &a) { return (check_and_get_length(a) != -1 ? true: false); } } psi-0.14/iris/src/irisnet/noncore/stuntransaction.cpp0000644000175000017500000001677311305557616021202 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "stuntransaction.h" #include #include #include #include #include #include "stunmessage.h" Q_DECLARE_METATYPE(XMPP::StunTransaction::Error) namespace XMPP { //---------------------------------------------------------------------------- // StunTransaction //---------------------------------------------------------------------------- class StunTransaction::Private : public QObject { Q_OBJECT public: StunTransaction *q; bool active; StunTransaction::Mode mode; QByteArray id; QByteArray packet; int rto, rc, rm, ti; int tries; int last_interval; QTimer *t; //QTime time; QString stuser; QByteArray key; Private(StunTransaction *_q) : QObject(_q), q(_q) { qRegisterMetaType(); active = false; t = new QTimer(this); connect(t, SIGNAL(timeout()), SLOT(t_timeout())); t->setSingleShot(true); // defaults from RFC 5389 rto = 500; rc = 7; rm = 16; ti = 39500; } ~Private() { t->disconnect(this); t->setParent(0); t->deleteLater(); } void start(StunTransaction::Mode _mode, const StunMessage &msg, const QString &_stuser, const QString &stpass) { mode = _mode; stuser = _stuser; StunMessage out = msg; id = QByteArray((const char *)msg.id(), 12); // HACK HACK HACK if(!stuser.isEmpty()) { QList list = out.attributes(); StunMessage::Attribute attr; attr.type = 0x0006; // USERNAME attr.value = stuser.toUtf8(); list += attr; out.setAttributes(list); key = stpass.toUtf8(); // FIXME: why also fingerprint? this is such a mess packet = out.toBinary(StunMessage::MessageIntegrity | StunMessage::Fingerprint, key); } else packet = out.toBinary(); if(packet.isEmpty()) { // since a transaction is not cancelable nor reusable, // there's no DOR-SR issue here QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection, Q_ARG(XMPP::StunTransaction::Error, ErrorGeneric)); return; } active = true; tries = 1; // assume the user does its job if(mode == StunTransaction::Udp) { last_interval = rm * rto; t->start(rto); rto *= 2; } else if(mode == StunTransaction::Tcp) { t->start(ti); } else Q_ASSERT(0); //time.start(); //printf("send: %d\n", time.elapsed()); } private slots: void t_timeout() { if(mode == StunTransaction::Tcp || tries == rc) { emit q->error(StunTransaction::ErrorTimeout); return; } ++tries; if(tries == rc) { t->start(last_interval); } else { t->start(rto); rto *= 2; } //printf("send: %d\n", time.elapsed()); emit q->retransmit(); } public: bool processIncoming(const StunMessage &msg) { if(!active) return false; if(msg.mclass() != StunMessage::SuccessResponse && msg.mclass() != StunMessage::ErrorResponse) return false; if(memcmp(msg.id(), id.data(), 12) != 0) return false; active = false; t->stop(); emit q->finished(msg); return true; } }; StunTransaction::StunTransaction(QObject *parent) : QObject(parent) { d = new Private(this); } StunTransaction::~StunTransaction() { delete d; } void StunTransaction::start(Mode mode, const StunMessage &msg, const QString &stuser, const QString &stpass) { Q_ASSERT(!d->active); d->start(mode, msg, stuser, stpass); } QByteArray StunTransaction::transactionId() const { return d->id; } QByteArray StunTransaction::packet() const { return d->packet; } void StunTransaction::setRTO(int i) { Q_ASSERT(!d->active); d->rto = i; } void StunTransaction::setRc(int i) { Q_ASSERT(!d->active); d->rc = i; } void StunTransaction::setRm(int i) { Q_ASSERT(!d->active); d->rm = i; } void StunTransaction::setTi(int i) { Q_ASSERT(!d->active); d->ti = i; } bool StunTransaction::writeIncomingMessage(const StunMessage &msg) { return d->processIncoming(msg); } //---------------------------------------------------------------------------- // StunTransactionPool //---------------------------------------------------------------------------- class StunTransactionPool::Private : public QObject { Q_OBJECT public: StunTransactionPool *q; StunTransaction::Mode mode; QHash transToId; QHash idToTrans; bool shortTermCredentials; QString username, password; Private(StunTransactionPool *_q) : QObject(_q), q(_q), shortTermCredentials(false) { } void insert(StunTransaction *trans) { connect(trans, SIGNAL(retransmit()), this, SLOT(trans_retransmit())); QByteArray id = trans->transactionId(); transToId.insert(trans, id); idToTrans.insert(id, trans); // send the first transmit attempt emit q->retransmit(trans); } void remove(StunTransaction *trans) { disconnect(trans, SIGNAL(retransmit()), this, SLOT(trans_retransmit())); QByteArray id = transToId.value(trans); transToId.remove(trans); idToTrans.remove(id); } private slots: void trans_retransmit() { StunTransaction *trans = (StunTransaction *)sender(); emit q->retransmit(trans); } }; StunTransactionPool::StunTransactionPool(StunTransaction::Mode mode, QObject *parent) : QObject(parent) { d = new Private(this); d->mode = mode; } StunTransactionPool::~StunTransactionPool() { delete d; } StunTransaction::Mode StunTransactionPool::mode() const { return d->mode; } QByteArray StunTransactionPool::generateId() const { QByteArray id; do { id = QCA::Random::randomArray(12).toByteArray(); } while(d->idToTrans.contains(id)); return id; } void StunTransactionPool::insert(StunTransaction *trans) { Q_ASSERT(!trans->transactionId().isEmpty()); d->insert(trans); } void StunTransactionPool::remove(StunTransaction *trans) { d->remove(trans); } bool StunTransactionPool::writeIncomingMessage(const StunMessage &msg) { if(msg.mclass() != StunMessage::SuccessResponse && msg.mclass() != StunMessage::ErrorResponse) return false; StunTransaction *trans = d->idToTrans.value(QByteArray::fromRawData((const char *)msg.id(), 12)); if(!trans) return false; return trans->writeIncomingMessage(msg); } QString StunTransactionPool::realm() const { // TODO return QString(); } void StunTransactionPool::setUsername(const QString &username) { d->username = username; } void StunTransactionPool::setPassword(const QCA::SecureArray &password) { // HACK HACK HACK d->password = QString::fromUtf8(password.toByteArray()); } void StunTransactionPool::setRealm(const QString &realm) { // TODO Q_UNUSED(realm); } void StunTransactionPool::setShortTermCredentialsEnabled(bool enabled) { d->shortTermCredentials = enabled; } void StunTransactionPool::continueAfterParams() { // TODO } QString StunTransactionPool::username() const { return d->username; } QString StunTransactionPool::password() const { return d->password; } } #include "stuntransaction.moc" psi-0.14/iris/src/irisnet/noncore/noncore.pri0000644000175000017500000000110611305557616017376 0ustar janjanIRIS_BASE = $$PWD/../../.. QT *= network irisnetcore_bundle:{ include(../corelib/corelib.pri) } else { LIBS += -L$$IRIS_BASE/lib -lirisnetcore } INCLUDEPATH += $$PWD/../corelib HEADERS += \ $$PWD/processquit.h \ $$PWD/stunmessage.h \ $$PWD/stuntransaction.h \ $$PWD/stunbinding.h \ $$PWD/stunallocate.h \ $$PWD/icelocaltransport.h \ $$PWD/ice176.h SOURCES += \ $$PWD/processquit.cpp \ $$PWD/stunmessage.cpp \ $$PWD/stuntransaction.cpp \ $$PWD/stunbinding.cpp \ $$PWD/stunallocate.cpp \ $$PWD/icelocaltransport.cpp \ $$PWD/ice176.cpp include(legacy/legacy.pri) psi-0.14/iris/src/irisnet/noncore/stunallocate.h0000644000175000017500000000367111305557616020077 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef STUNALLOCATE_H #define STUNALLOCATE_H #include #include class QByteArray; class QHostAddress; namespace XMPP { class StunMessage; class StunTransactionPool; class StunAllocate : public QObject { Q_OBJECT public: enum Error { ErrorGeneric, ErrorTimeout, ErrorRejected, ErrorProtocol }; StunAllocate(StunTransactionPool *pool); ~StunAllocate(); void start(); void stop(); QHostAddress reflexiveAddress() const; int reflexivePort() const; QHostAddress relayedAddress() const; int relayedPort() const; QList permissions() const; void setPermissions(const QList &perms); QByteArray encode(const QByteArray &datagram, const QHostAddress &addr, int port); QByteArray decode(const QByteArray &encoded, QHostAddress *addr = 0, int *port = 0); QByteArray decode(const StunMessage &encoded, QHostAddress *addr = 0, int *port = 0); signals: void started(); void stopped(); void error(XMPP::StunAllocate::Error e); // emitted after calling setPermissions() void permissionsChanged(); private: Q_DISABLE_COPY(StunAllocate) class Private; friend class Private; Private *d; }; } #endif psi-0.14/iris/src/irisnet/noncore/stunallocate.cpp0000644000175000017500000000515011305557616020424 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include "stunallocate.h" #include #include #include "stunmessage.h" #include "stuntransaction.h" Q_DECLARE_METATYPE(XMPP::StunAllocate::Error) namespace XMPP { class StunAllocate::Private : public QObject { Q_OBJECT public: StunAllocate *q; StunTransactionPool *pool; Private(StunAllocate *_q) : QObject(_q), q(_q), pool(0) { qRegisterMetaType(); } }; StunAllocate::StunAllocate(StunTransactionPool *pool) : QObject(pool) { d = new Private(this); d->pool = pool; } StunAllocate::~StunAllocate() { delete d; } void StunAllocate::start() { // TODO QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(XMPP::StunAllocate::Error, ErrorGeneric)); } void StunAllocate::stop() { // TODO } QHostAddress StunAllocate::reflexiveAddress() const { // TODO return QHostAddress(); } int StunAllocate::reflexivePort() const { // TODO return 0; } QHostAddress StunAllocate::relayedAddress() const { // TODO return QHostAddress(); } int StunAllocate::relayedPort() const { // TODO return 0; } QList StunAllocate::permissions() const { // TODO return QList(); } void StunAllocate::setPermissions(const QList &perms) { // TODO Q_UNUSED(perms); } QByteArray StunAllocate::encode(const QByteArray &datagram, const QHostAddress &addr, int port) { // TODO Q_UNUSED(datagram); Q_UNUSED(addr); Q_UNUSED(port); return QByteArray(); } QByteArray StunAllocate::decode(const QByteArray &encoded, QHostAddress *addr, int *port) { // TODO Q_UNUSED(encoded); Q_UNUSED(addr); Q_UNUSED(port); return QByteArray(); } QByteArray StunAllocate::decode(const StunMessage &encoded, QHostAddress *addr, int *port) { // TODO Q_UNUSED(encoded); Q_UNUSED(addr); Q_UNUSED(port); return QByteArray(); } } #include "stunallocate.moc" psi-0.14/iris/src/irisnet/noncore/stuntransaction.h0000644000175000017500000000757311305557616020645 0ustar janjan/* * Copyright (C) 2009 Barracuda Networks, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef STUNTRANSACTION_H #define STUNTRANSACTION_H #include #include namespace QCA { class SecureArray; } namespace XMPP { class StunMessage; class StunTransaction : public QObject { Q_OBJECT public: enum Mode { Udp, // handle retransmissions Tcp // send once }; enum Error { ErrorGeneric, ErrorTimeout }; StunTransaction(QObject *parent = 0); ~StunTransaction(); // pass a message with transaction id unset. it will be filled in. // after calling this function, immediately obtain the result by // calling packet(), and send it. the start() function will not // perform the first send attempt. it leaves that to you. // FIXME: stuser/stpass are a hack void start(Mode mode, const StunMessage &request, const QString &stuser = QString(), const QString &stpass = QString()); QByteArray transactionId() const; QByteArray packet() const; // transmission/timeout parameters, from RFC 5389. by default, // they are set to the recommended values from the RFC. void setRTO(int i); void setRc(int i); void setRm(int i); void setTi(int i); // note: not DOR-DS safe. this will either emit signals and return // true, or not emit signals and return false. bool writeIncomingMessage(const StunMessage &msg); signals: // indicates you should retransmit the value of packet() void retransmit(); void finished(const XMPP::StunMessage &response); void error(XMPP::StunTransaction::Error error); private: Q_DISABLE_COPY(StunTransaction) class Private; friend class Private; Private *d; }; // keep track of many open transactions. note that retransmit() may be // emitted as a direct result of calling certain member functions of this // class as well as any other class that might use it (such as StunBinding). // so, be careful with what you do in your retransmit slot. class StunTransactionPool : public QObject { Q_OBJECT public: StunTransactionPool(StunTransaction::Mode mode, QObject *parent = 0); ~StunTransactionPool(); StunTransaction::Mode mode() const; // generate a random id not used by any transaction in the pool QByteArray generateId() const; // you must start the transaction before inserting it. // note: not DOR-DS safe. this function will cause retransmit() to be // emitted. void insert(StunTransaction *trans); void remove(StunTransaction *trans); // note: not DOR-DS safe. this will either cause transactions to emit // signals and return true, or not cause signals and return false. bool writeIncomingMessage(const StunMessage &msg); QString realm() const; void setUsername(const QString &username); void setPassword(const QCA::SecureArray &password); void setRealm(const QString &realm); void setShortTermCredentialsEnabled(bool enabled); void continueAfterParams(); QString username() const; QString password() const; signals: // note: not DOR-SS safe. writeIncomingMessage() must not be called // during this signal. void retransmit(XMPP::StunTransaction *trans); void needAuthParams(); private: Q_DISABLE_COPY(StunTransactionPool) class Private; friend class Private; Private *d; }; } #endif psi-0.14/iris/src/libidn/0000755000175000017500000000000011305557616013342 5ustar janjanpsi-0.14/iris/src/libidn/idn-int.h0000644000175000017500000002007011305557616015054 0ustar janjan#ifndef _LIBIDN_LIB_IDN_INT_H #define _LIBIDN_LIB_IDN_INT_H 1 #ifndef _GENERATED_STDINT_H #define _GENERATED_STDINT_H "libidn 0.3.1" /* generated using gnu compiler gcc (GCC) 3.2.3 20030422 (Gentoo Linux 1.4 3.2.3-r1, propolice) */ #define _STDINT_HAVE_STDINT_H 1 /* ................... shortcircuit part ........................... */ #if defined HAVE_STDINT_H || defined _STDINT_HAVE_STDINT_H //#include //#ifdef Q_OS_WIN32 #include "qint.h" //#else //#include //#endif #else #include /* .................... configured part ............................ */ /* whether we have a C99 compatible stdint header file */ /* #undef _STDINT_HEADER_INTPTR */ /* whether we have a C96 compatible inttypes header file */ /* #undef _STDINT_HEADER_UINT32 */ /* whether we have a BSD compatible inet types header */ /* #undef _STDINT_HEADER_U_INT32 */ /* which 64bit typedef has been found */ /* #undef _STDINT_HAVE_UINT64_T */ /* #undef _STDINT_HAVE_U_INT64_T */ /* which type model has been detected */ /* #undef _STDINT_CHAR_MODEL // skipped */ /* #undef _STDINT_LONG_MODEL // skipped */ /* whether int_least types were detected */ /* #undef _STDINT_HAVE_INT_LEAST32_T */ /* whether int_fast types were detected */ /* #undef _STDINT_HAVE_INT_FAST32_T */ /* whether intmax_t type was detected */ /* #undef _STDINT_HAVE_INTMAX_T */ /* .................... detections part ............................ */ /* whether we need to define bitspecific types from compiler base types */ #ifndef _STDINT_HEADER_INTPTR #ifndef _STDINT_HEADER_UINT32 #ifndef _STDINT_HEADER_U_INT32 #define _STDINT_NEED_INT_MODEL_T #else #define _STDINT_HAVE_U_INT_TYPES #endif #endif #endif #ifdef _STDINT_HAVE_U_INT_TYPES #undef _STDINT_NEED_INT_MODEL_T #endif #ifdef _STDINT_CHAR_MODEL #if _STDINT_CHAR_MODEL+0 == 122 || _STDINT_CHAR_MODEL+0 == 124 #ifndef _STDINT_BYTE_MODEL #define _STDINT_BYTE_MODEL 12 #endif #endif #endif #ifndef _STDINT_HAVE_INT_LEAST32_T #define _STDINT_NEED_INT_LEAST_T #endif #ifndef _STDINT_HAVE_INT_FAST32_T #define _STDINT_NEED_INT_FAST_T #endif #ifndef _STDINT_HEADER_INTPTR #define _STDINT_NEED_INTPTR_T #ifndef _STDINT_HAVE_INTMAX_T #define _STDINT_NEED_INTMAX_T #endif #endif /* .................... definition part ............................ */ /* some system headers have good uint64_t */ #ifndef _HAVE_UINT64_T #if defined _STDINT_HAVE_UINT64_T || defined HAVE_UINT64_T #define _HAVE_UINT64_T #elif defined _STDINT_HAVE_U_INT64_T || defined HAVE_U_INT64_T #define _HAVE_UINT64_T typedef u_int64_t uint64_t; #endif #endif #ifndef _HAVE_UINT64_T /* .. here are some common heuristics using compiler runtime specifics */ #if defined __STDC_VERSION__ && defined __STDC_VERSION__ >= 199901L #define _HAVE_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #elif !defined __STRICT_ANSI__ #if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ #define _HAVE_UINT64_T typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ /* note: all ELF-systems seem to have loff-support which needs 64-bit */ #if !defined _NO_LONGLONG #define _HAVE_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #endif #elif defined __alpha || (defined __mips && defined _ABIN32) #if !defined _NO_LONGLONG typedef long int64_t; typedef unsigned long uint64_t; #endif /* compiler/cpu type to define int64_t */ #endif #endif #endif #if defined _STDINT_HAVE_U_INT_TYPES /* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ typedef u_int8_t uint8_t; typedef u_int16_t uint16_t; typedef u_int32_t uint32_t; /* glibc compatibility */ #ifndef __int8_t_defined #define __int8_t_defined #endif #endif #ifdef _STDINT_NEED_INT_MODEL_T /* we must guess all the basic types. Apart from byte-adressable system, */ /* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ /* (btw, those nibble-addressable systems are way off, or so we assume) */ #if defined _STDINT_BYTE_MODEL #if _STDINT_LONG_MODEL+0 == 242 /* 2:4:2 = IP16 = a normal 16-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef long int32_t; #endif #elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 /* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ /* 4:4:4 = ILP32 = a normal 32-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef int int32_t; #endif #elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 /* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ /* 4:8:8 = LP64 = a normal 64-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef int int32_t; #endif /* this system has a "long" of 64bit */ #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef unsigned long uint64_t; typedef long int64_t; #endif #elif _STDINT_LONG_MODEL+0 == 448 /* LLP64 a 64-bit system derived from a 32-bit system */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #ifndef __int8_t_defined #define __int8_t_defined typedef char int8_t; typedef short int16_t; typedef int int32_t; #endif /* assuming the system has a "long long" */ #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef unsigned long long uint64_t; typedef long long int64_t; #endif #else #define _STDINT_NO_INT32_T #endif #else #define _STDINT_NO_INT8_T #define _STDINT_NO_INT32_T #endif #endif /* * quote from SunOS-5.8 sys/inttypes.h: * Use at your own risk. As of February 1996, the committee is squarely * behind the fixed sized types; the "least" and "fast" types are still being * discussed. The probability that the "fast" types may be removed before * the standard is finalized is high enough that they are not currently * implemented. */ #if defined _STDINT_NEED_INT_LEAST_T typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; #ifdef _HAVE_UINT64_T typedef int64_t int_least64_t; #endif typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; #ifdef _HAVE_UINT64_T typedef uint64_t uint_least64_t; #endif /* least types */ #endif #if defined _STDINT_NEED_INT_FAST_T typedef int8_t int_fast8_t; typedef int int_fast16_t; typedef int32_t int_fast32_t; #ifdef _HAVE_UINT64_T typedef int64_t int_fast64_t; #endif typedef uint8_t uint_fast8_t; typedef unsigned uint_fast16_t; typedef uint32_t uint_fast32_t; #ifdef _HAVE_UINT64_T typedef uint64_t uint_fast64_t; #endif /* fast types */ #endif #ifdef _STDINT_NEED_INTMAX_T #ifdef _HAVE_UINT64_T typedef int64_t intmax_t; typedef uint64_t uintmax_t; #else typedef long intmax_t; typedef unsigned long uintmax_t; #endif #endif #ifdef _STDINT_NEED_INTPTR_T #ifndef __intptr_t_defined #define __intptr_t_defined /* we encourage using "long" to store pointer values, never use "int" ! */ #if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 typedef unsinged int uintptr_t; typedef int intptr_t; #elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 typedef unsigned long uintptr_t; typedef long intptr_t; #elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T typedef uint64_t uintptr_t; typedef int64_t intptr_t; #else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ typedef unsigned long uintptr_t; typedef long intptr_t; #endif #endif #endif /* shortcircuit*/ #endif /* once */ #endif #endif psi-0.14/iris/src/libidn/punycode.h0000644000175000017500000001610311305557616015342 0ustar janjan/* punycode.h Declarations for punycode functions. * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * This file is derived from RFC 3492 written by Adam M. Costello. * * Disclaimer and license: Regarding this entire document or any * portion of it (including the pseudocode and C code), the author * makes no guarantees and is not responsible for any damage resulting * from its use. The author grants irrevocable permission to anyone * to use, modify, and distribute it in any way that does not diminish * the rights of anyone else to use, modify, and distribute it, * provided that redistributed derivative works do not contain * misleading author or version information. Derivative works need * not be licensed under similar terms. * * Copyright (C) The Internet Society (2003). All Rights Reserved. * * This document and translations of it may be copied and furnished to * others, and derivative works that comment on or otherwise explain it * or assist in its implementation may be prepared, copied, published * and distributed, in whole or in part, without restriction of any * kind, provided that the above copyright notice and this paragraph are * included on all such copies and derivative works. However, this * document itself may not be modified in any way, such as by removing * the copyright notice or references to the Internet Society or other * Internet organizations, except as needed for the purpose of * developing Internet standards in which case the procedures for * copyrights defined in the Internet Standards process must be * followed, or as required to translate it into languages other than * English. * * The limited permissions granted above are perpetual and will not be * revoked by the Internet Society or its successors or assigns. * * This document and the information contained herein is provided on an * "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING * TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef _PUNYCODE_H #define _PUNYCODE_H #ifdef __cplusplus extern "C" { #endif #include /* size_t */ #include /* my_uint32_t */ typedef enum { PUNYCODE_SUCCESS = 0, PUNYCODE_BAD_INPUT, /* Input is invalid. */ PUNYCODE_BIG_OUTPUT, /* Output would exceed the space provided. */ PUNYCODE_OVERFLOW /* Input needs wider integers to process. */ } Punycode_status; /* For RFC compatibility. */ enum punycode_status { punycode_success = PUNYCODE_SUCCESS, punycode_bad_input = PUNYCODE_BAD_INPUT, punycode_big_output = PUNYCODE_BIG_OUTPUT, punycode_overflow = PUNYCODE_OVERFLOW }; typedef my_uint32_t punycode_uint; int punycode_encode (size_t input_length, const punycode_uint input[], const unsigned char case_flags[], size_t * output_length, char output[]); /* punycode_encode() converts Unicode to Punycode. The input */ /* is represented as an array of Unicode code points (not code */ /* units; surrogate pairs are not allowed), and the output */ /* will be represented as an array of ASCII code points. The */ /* output string is *not* null-terminated; it will contain */ /* zeros if and only if the input contains zeros. (Of course */ /* the caller can leave room for a terminator and add one if */ /* needed.) The input_length is the number of code points in */ /* the input. The output_length is an in/out argument: the */ /* caller passes in the maximum number of code points that it */ /* can receive, and on successful return it will contain the */ /* number of code points actually output. The case_flags array */ /* holds input_length boolean values, where nonzero suggests that */ /* the corresponding Unicode character be forced to uppercase */ /* after being decoded (if possible), and zero suggests that */ /* it be forced to lowercase (if possible). ASCII code points */ /* are encoded literally, except that ASCII letters are forced */ /* to uppercase or lowercase according to the corresponding */ /* uppercase flags. If case_flags is a null pointer then ASCII */ /* letters are left as they are, and other code points are */ /* treated as if their uppercase flags were zero. The return */ /* value can be any of the punycode_status values defined above */ /* except punycode_bad_input; if not punycode_success, then */ /* output_size and output might contain garbage. */ int punycode_decode (size_t input_length, const char input[], size_t * output_length, punycode_uint output[], unsigned char case_flags[]); /* punycode_decode() converts Punycode to Unicode. The input is */ /* represented as an array of ASCII code points, and the output */ /* will be represented as an array of Unicode code points. The */ /* input_length is the number of code points in the input. The */ /* output_length is an in/out argument: the caller passes in */ /* the maximum number of code points that it can receive, and */ /* on successful return it will contain the actual number of */ /* code points output. The case_flags array needs room for at */ /* least output_length values, or it can be a null pointer if the */ /* case information is not needed. A nonzero flag suggests that */ /* the corresponding Unicode character be forced to uppercase */ /* by the caller (if possible), while zero suggests that it be */ /* forced to lowercase (if possible). ASCII code points are */ /* output already in the proper case, but their flags will be set */ /* appropriately so that applying the flags would be harmless. */ /* The return value can be any of the punycode_status values */ /* defined above; if not punycode_success, then output_length, */ /* output, and case_flags might contain garbage. On success, the */ /* decoder will never need to write an output_length greater than */ /* input_length, because of how the encoding is defined. */ #ifdef __cplusplus } #endif #endif /* _PUNYCODE_H */ psi-0.14/iris/src/libidn/libidn.pri0000644000175000017500000000035311305557616015320 0ustar janjanINCLUDEPATH += $$PWD/.. DEPENDPATH += $$PWD/.. unix:{ QMAKE_CFLAGS_WARN_ON -= -W } win32:{ QMAKE_CFLAGS += -Zm400 } SOURCES += \ $$PWD/profiles.c \ #$$PWD/toutf8.c \ $$PWD/rfc3454.c \ $$PWD/nfkc.c \ $$PWD/stringprep.c psi-0.14/iris/src/libidn/gunicomp.h0000644000175000017500000016113711305557616015345 0ustar janjan#define COMPOSE_FIRST_START 1 #define COMPOSE_FIRST_SINGLE_START 147 #define COMPOSE_SECOND_START 357 #define COMPOSE_SECOND_SINGLE_START 388 #define COMPOSE_TABLE_LAST 48 static const guint16 compose_data[][256] = { { /* page 0, index 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 148, 149, 0, 0, 1, 2, 3, 4, 5, 150, 6, 7, 8, 151, 9, 10, 11, 12, 13, 14, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 0, 0, 0, 0, 0, 24, 25, 26, 27, 28, 152, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 0, 39, 40, 41, 42, 43, 44, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 153, 154, 50, 155, 0, 0, 51, 0, 0, 0, 0, 156, 0, 0, 0, 0, 52, 53, 157, 0, 158, 0, 0, 0, 54, 0, 0, 0, 0, 0, 55, 0, 159, 160, 56, 161, 0, 0, 57, 0, 0, 0, 0, 162, 0, 0, 0, 0, 58, 59, 163, 0, 164, 0, 0, 0, 60, 0, 0, 0 }, { /* page 1, index 1 */ 0, 0, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165, 166, 0, 0, 0, 0, 167, 168, 0, 0, 0, 0, 0, 0, 169, 170, 171, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 2, index 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 178, 179, 180, 0, 0, 0, 0, 181, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 3, index 3 */ 357, 358, 359, 360, 361, 0, 362, 363, 364, 365, 366, 367, 368, 0, 0, 369, 0, 370, 0, 371, 372, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 0, 374, 375, 376, 377, 378, 379, 0, 0, 0, 0, 380, 381, 0, 382, 383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 72, 0, 73, 0, 74, 0, 0, 0, 0, 0, 75, 0, 184, 0, 0, 0, 76, 0, 0, 0, 77, 0, 0, 185, 0, 186, 0, 0, 78, 0, 0, 0, 79, 0, 80, 0, 81, 0, 0, 0, 0, 0, 82, 0, 83, 0, 0, 0, 84, 0, 0, 0, 85, 86, 87, 0, 0, 187, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 4, index 4 */ 0, 0, 0, 0, 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 189, 0, 90, 91, 190, 92, 0, 191, 0, 0, 0, 192, 0, 0, 0, 0, 93, 0, 0, 0, 193, 0, 0, 0, 194, 0, 195, 0, 0, 94, 0, 0, 196, 0, 95, 96, 197, 97, 0, 198, 0, 0, 0, 199, 0, 0, 0, 0, 98, 0, 0, 0, 200, 0, 0, 0, 201, 0, 202, 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 6, index 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 0, 211, 0, 0, 0, 0, 0, 0, 0, 0, 388, 389, 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 9, index 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, 216, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 11, index 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 394, 395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 396, 0, 0, 0, 0, 0, 0, 0, 102, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 12, index 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 398, 0, 0, 0, 103, 0, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 399, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 13, index 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, 0, 0, 0, 0, 0, 104, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 0, 0, 224, 0, 0, 405, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 16, index 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 30, index 11 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 229, 0, 0, 0, 0, 0, 0, 230, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 31, index 12 */ 108, 109, 236, 237, 238, 239, 240, 241, 110, 111, 242, 243, 244, 245, 246, 247, 112, 113, 0, 0, 0, 0, 0, 0, 114, 115, 0, 0, 0, 0, 0, 0, 116, 117, 248, 249, 250, 251, 252, 253, 118, 119, 254, 255, 256, 257, 258, 259, 120, 121, 0, 0, 0, 0, 0, 0, 122, 123, 0, 0, 0, 0, 0, 0, 124, 125, 0, 0, 0, 0, 0, 0, 126, 127, 0, 0, 0, 0, 0, 0, 128, 129, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 131, 132, 260, 261, 262, 263, 264, 265, 133, 134, 266, 267, 268, 269, 270, 271, 272, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 277, 0, 0, 0, 0, 0, 0, 0, 136, 0 }, { /* page 33, index 13 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 0, 279, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 0, 282, 0, 283, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 34, index 14 */ 0, 0, 0, 284, 0, 0, 0, 0, 285, 0, 0, 286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 287, 0, 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289, 0, 0, 0, 0, 0, 0, 290, 0, 291, 0, 0, 292, 0, 0, 0, 0, 293, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 294, 0, 0, 295, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 297, 298, 0, 0, 299, 300, 0, 0, 301, 302, 303, 304, 0, 0, 0, 0, 305, 306, 0, 0, 307, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, 0, 0, 0, 0, 0, 312, 313, 0, 314, 0, 0, 0, 0, 0, 0, 315, 316, 317, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 48, index 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 320, 0, 321, 0, 322, 0, 323, 0, 324, 0, 325, 0, 326, 0, 327, 0, 328, 0, 329, 0, 330, 0, 331, 0, 0, 332, 0, 333, 0, 334, 0, 0, 0, 0, 0, 0, 137, 0, 0, 138, 0, 0, 139, 0, 0, 140, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386, 387, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 0, 336, 0, 0, 0, 0, 337, 0, 338, 0, 339, 0, 340, 0, 341, 0, 342, 0, 343, 0, 344, 0, 345, 0, 346, 0, 347, 0, 348, 0, 0, 349, 0, 350, 0, 351, 0, 0, 0, 0, 0, 0, 142, 0, 0, 143, 0, 0, 144, 0, 0, 145, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 353, 354, 355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 356, 0, 0 } }; static const gint16 compose_table[COMPOSE_TABLE_LAST + 1] = { 0 /* page 0 */, 1 /* page 1 */, 2 /* page 2 */, 3 /* page 3 */, 4 /* page 4 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 5 /* page 6 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 6 /* page 9 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 7 /* page 11 */, 8 /* page 12 */, 9 /* page 13 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 10 /* page 16 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 11 /* page 30 */, 12 /* page 31 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 13 /* page 33 */, 14 /* page 34 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 15 /* page 48 */ }; static const guint16 compose_first_single[][2] = { { 0x0338, 0x226e }, { 0x0338, 0x2260 }, { 0x0338, 0x226f }, { 0x0307, 0x1e1e }, { 0x0302, 0x0134 }, { 0x0307, 0x1e1f }, { 0x0304, 0x01de }, { 0x0301, 0x01fa }, { 0x0301, 0x1e08 }, { 0x0301, 0x1e2e }, { 0x0304, 0x022a }, { 0x0301, 0x01fe }, { 0x0304, 0x01df }, { 0x0301, 0x01fb }, { 0x0301, 0x1e09 }, { 0x0301, 0x1e2f }, { 0x0304, 0x022b }, { 0x0301, 0x01ff }, { 0x0307, 0x1e64 }, { 0x0307, 0x1e65 }, { 0x0307, 0x1e66 }, { 0x0307, 0x1e67 }, { 0x0301, 0x1e78 }, { 0x0301, 0x1e79 }, { 0x0308, 0x1e7a }, { 0x0308, 0x1e7b }, { 0x0307, 0x1e9b }, { 0x030c, 0x01ee }, { 0x0304, 0x01ec }, { 0x0304, 0x01ed }, { 0x0304, 0x01e0 }, { 0x0304, 0x01e1 }, { 0x0306, 0x1e1c }, { 0x0306, 0x1e1d }, { 0x0304, 0x0230 }, { 0x0304, 0x0231 }, { 0x030c, 0x01ef }, { 0x0314, 0x1fec }, { 0x0345, 0x1fb4 }, { 0x0345, 0x1fc4 }, { 0x0345, 0x1ff4 }, { 0x0308, 0x0407 }, { 0x0301, 0x0403 }, { 0x0308, 0x04de }, { 0x0301, 0x040c }, { 0x0308, 0x04e6 }, { 0x0308, 0x04f4 }, { 0x0308, 0x04f8 }, { 0x0308, 0x04ec }, { 0x0301, 0x0453 }, { 0x0308, 0x04df }, { 0x0301, 0x045c }, { 0x0308, 0x04e7 }, { 0x0308, 0x04f5 }, { 0x0308, 0x04f9 }, { 0x0308, 0x04ed }, { 0x0308, 0x0457 }, { 0x030f, 0x0476 }, { 0x030f, 0x0477 }, { 0x0308, 0x04da }, { 0x0308, 0x04db }, { 0x0308, 0x04ea }, { 0x0308, 0x04eb }, { 0x0654, 0x0624 }, { 0x0654, 0x0626 }, { 0x0654, 0x06c2 }, { 0x0654, 0x06d3 }, { 0x0654, 0x06c0 }, { 0x093c, 0x0929 }, { 0x093c, 0x0931 }, { 0x093c, 0x0934 }, { 0x0bd7, 0x0b94 }, { 0x0bbe, 0x0bcb }, { 0x0c56, 0x0c48 }, { 0x0cd5, 0x0cc0 }, { 0x0cd5, 0x0ccb }, { 0x0d3e, 0x0d4b }, { 0x0dca, 0x0ddd }, { 0x102e, 0x1026 }, { 0x0304, 0x1e38 }, { 0x0304, 0x1e39 }, { 0x0304, 0x1e5c }, { 0x0304, 0x1e5d }, { 0x0307, 0x1e68 }, { 0x0307, 0x1e69 }, { 0x0302, 0x1ec6 }, { 0x0302, 0x1ec7 }, { 0x0302, 0x1ed8 }, { 0x0302, 0x1ed9 }, { 0x0345, 0x1f82 }, { 0x0345, 0x1f83 }, { 0x0345, 0x1f84 }, { 0x0345, 0x1f85 }, { 0x0345, 0x1f86 }, { 0x0345, 0x1f87 }, { 0x0345, 0x1f8a }, { 0x0345, 0x1f8b }, { 0x0345, 0x1f8c }, { 0x0345, 0x1f8d }, { 0x0345, 0x1f8e }, { 0x0345, 0x1f8f }, { 0x0345, 0x1f92 }, { 0x0345, 0x1f93 }, { 0x0345, 0x1f94 }, { 0x0345, 0x1f95 }, { 0x0345, 0x1f96 }, { 0x0345, 0x1f97 }, { 0x0345, 0x1f9a }, { 0x0345, 0x1f9b }, { 0x0345, 0x1f9c }, { 0x0345, 0x1f9d }, { 0x0345, 0x1f9e }, { 0x0345, 0x1f9f }, { 0x0345, 0x1fa2 }, { 0x0345, 0x1fa3 }, { 0x0345, 0x1fa4 }, { 0x0345, 0x1fa5 }, { 0x0345, 0x1fa6 }, { 0x0345, 0x1fa7 }, { 0x0345, 0x1faa }, { 0x0345, 0x1fab }, { 0x0345, 0x1fac }, { 0x0345, 0x1fad }, { 0x0345, 0x1fae }, { 0x0345, 0x1faf }, { 0x0345, 0x1fb2 }, { 0x0345, 0x1fc2 }, { 0x0345, 0x1ff2 }, { 0x0345, 0x1fb7 }, { 0x0345, 0x1fc7 }, { 0x0345, 0x1ff7 }, { 0x0338, 0x219a }, { 0x0338, 0x219b }, { 0x0338, 0x21ae }, { 0x0338, 0x21cd }, { 0x0338, 0x21cf }, { 0x0338, 0x21ce }, { 0x0338, 0x2204 }, { 0x0338, 0x2209 }, { 0x0338, 0x220c }, { 0x0338, 0x2224 }, { 0x0338, 0x2226 }, { 0x0338, 0x2241 }, { 0x0338, 0x2244 }, { 0x0338, 0x2247 }, { 0x0338, 0x2249 }, { 0x0338, 0x226d }, { 0x0338, 0x2262 }, { 0x0338, 0x2270 }, { 0x0338, 0x2271 }, { 0x0338, 0x2274 }, { 0x0338, 0x2275 }, { 0x0338, 0x2278 }, { 0x0338, 0x2279 }, { 0x0338, 0x2280 }, { 0x0338, 0x2281 }, { 0x0338, 0x22e0 }, { 0x0338, 0x22e1 }, { 0x0338, 0x2284 }, { 0x0338, 0x2285 }, { 0x0338, 0x2288 }, { 0x0338, 0x2289 }, { 0x0338, 0x22e2 }, { 0x0338, 0x22e3 }, { 0x0338, 0x22ac }, { 0x0338, 0x22ad }, { 0x0338, 0x22ae }, { 0x0338, 0x22af }, { 0x0338, 0x22ea }, { 0x0338, 0x22eb }, { 0x0338, 0x22ec }, { 0x0338, 0x22ed }, { 0x3099, 0x3094 }, { 0x3099, 0x304c }, { 0x3099, 0x304e }, { 0x3099, 0x3050 }, { 0x3099, 0x3052 }, { 0x3099, 0x3054 }, { 0x3099, 0x3056 }, { 0x3099, 0x3058 }, { 0x3099, 0x305a }, { 0x3099, 0x305c }, { 0x3099, 0x305e }, { 0x3099, 0x3060 }, { 0x3099, 0x3062 }, { 0x3099, 0x3065 }, { 0x3099, 0x3067 }, { 0x3099, 0x3069 }, { 0x3099, 0x309e }, { 0x3099, 0x30f4 }, { 0x3099, 0x30ac }, { 0x3099, 0x30ae }, { 0x3099, 0x30b0 }, { 0x3099, 0x30b2 }, { 0x3099, 0x30b4 }, { 0x3099, 0x30b6 }, { 0x3099, 0x30b8 }, { 0x3099, 0x30ba }, { 0x3099, 0x30bc }, { 0x3099, 0x30be }, { 0x3099, 0x30c0 }, { 0x3099, 0x30c2 }, { 0x3099, 0x30c5 }, { 0x3099, 0x30c7 }, { 0x3099, 0x30c9 }, { 0x3099, 0x30f7 }, { 0x3099, 0x30f8 }, { 0x3099, 0x30f9 }, { 0x3099, 0x30fa }, { 0x3099, 0x30fe } }; static const guint16 compose_second_single[][2] = { { 0x0627, 0x0622 }, { 0x0627, 0x0623 }, { 0x0627, 0x0625 }, { 0x09c7, 0x09cb }, { 0x09c7, 0x09cc }, { 0x0b47, 0x0b4b }, { 0x0b47, 0x0b48 }, { 0x0b47, 0x0b4c }, { 0x0bc6, 0x0bca }, { 0x0bc6, 0x0bcc }, { 0x0cc6, 0x0cca }, { 0x0cc6, 0x0cc7 }, { 0x0cc6, 0x0cc8 }, { 0x0d46, 0x0d4a }, { 0x0d46, 0x0d4c }, { 0x0dd9, 0x0dda }, { 0x0dd9, 0x0ddc }, { 0x0dd9, 0x0dde } }; static const guint16 compose_array[146][31] = { { 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x0100, 0x0102, 0x0226, 0x00c4, 0x1ea2, 0x00c5, 0, 0x01cd, 0x0200, 0x0202, 0, 0, 0, 0x1ea0, 0, 0x1e00, 0, 0, 0x0104, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e04, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e06, 0, 0, 0, 0 }, { 0, 0x0106, 0x0108, 0, 0, 0, 0x010a, 0, 0, 0, 0, 0x010c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00c7, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e0a, 0, 0, 0, 0, 0x010e, 0, 0, 0, 0, 0, 0x1e0c, 0, 0, 0, 0x1e10, 0, 0x1e12, 0, 0, 0x1e0e, 0, 0, 0, 0 }, { 0x00c8, 0x00c9, 0x00ca, 0x1ebc, 0x0112, 0x0114, 0x0116, 0x00cb, 0x1eba, 0, 0, 0x011a, 0x0204, 0x0206, 0, 0, 0, 0x1eb8, 0, 0, 0, 0x0228, 0x0118, 0x1e18, 0, 0x1e1a, 0, 0, 0, 0, 0 }, { 0, 0x01f4, 0x011c, 0, 0x1e20, 0x011e, 0x0120, 0, 0, 0, 0, 0x01e6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0122, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0x0124, 0, 0, 0, 0x1e22, 0x1e26, 0, 0, 0, 0x021e, 0, 0, 0, 0, 0, 0x1e24, 0, 0, 0, 0x1e28, 0, 0, 0x1e2a, 0, 0, 0, 0, 0, 0 }, { 0x00cc, 0x00cd, 0x00ce, 0x0128, 0x012a, 0x012c, 0x0130, 0x00cf, 0x1ec8, 0, 0, 0x01cf, 0x0208, 0x020a, 0, 0, 0, 0x1eca, 0, 0, 0, 0, 0x012e, 0, 0, 0x1e2c, 0, 0, 0, 0, 0 }, { 0, 0x1e30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01e8, 0, 0, 0, 0, 0, 0x1e32, 0, 0, 0, 0x0136, 0, 0, 0, 0, 0x1e34, 0, 0, 0, 0 }, { 0, 0x0139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x013d, 0, 0, 0, 0, 0, 0x1e36, 0, 0, 0, 0x013b, 0, 0x1e3c, 0, 0, 0x1e3a, 0, 0, 0, 0 }, { 0, 0x1e3e, 0, 0, 0, 0, 0x1e40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x01f8, 0x0143, 0, 0x00d1, 0, 0, 0x1e44, 0, 0, 0, 0, 0x0147, 0, 0, 0, 0, 0, 0x1e46, 0, 0, 0, 0x0145, 0, 0x1e4a, 0, 0, 0x1e48, 0, 0, 0, 0 }, { 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x014c, 0x014e, 0x022e, 0x00d6, 0x1ece, 0, 0x0150, 0x01d1, 0x020c, 0x020e, 0, 0, 0x01a0, 0x1ecc, 0, 0, 0, 0, 0x01ea, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x1e54, 0, 0, 0, 0, 0x1e56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x0154, 0, 0, 0, 0, 0x1e58, 0, 0, 0, 0, 0x0158, 0x0210, 0x0212, 0, 0, 0, 0x1e5a, 0, 0, 0, 0x0156, 0, 0, 0, 0, 0x1e5e, 0, 0, 0, 0 }, { 0, 0x015a, 0x015c, 0, 0, 0, 0x1e60, 0, 0, 0, 0, 0x0160, 0, 0, 0, 0, 0, 0x1e62, 0, 0, 0x0218, 0x015e, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e6a, 0, 0, 0, 0, 0x0164, 0, 0, 0, 0, 0, 0x1e6c, 0, 0, 0x021a, 0x0162, 0, 0x1e70, 0, 0, 0x1e6e, 0, 0, 0, 0 }, { 0x00d9, 0x00da, 0x00db, 0x0168, 0x016a, 0x016c, 0, 0x00dc, 0x1ee6, 0x016e, 0x0170, 0x01d3, 0x0214, 0x0216, 0, 0, 0x01af, 0x1ee4, 0x1e72, 0, 0, 0, 0x0172, 0x1e76, 0, 0x1e74, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0x1e7c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e7e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1e80, 0x1e82, 0x0174, 0, 0, 0, 0x1e86, 0x1e84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e8a, 0x1e8c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ef2, 0x00dd, 0x0176, 0x1ef8, 0x0232, 0, 0x1e8e, 0x0178, 0x1ef6, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ef4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x0179, 0x1e90, 0, 0, 0, 0x017b, 0, 0, 0, 0, 0x017d, 0, 0, 0, 0, 0, 0x1e92, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e94, 0, 0, 0, 0 }, { 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x0101, 0x0103, 0x0227, 0x00e4, 0x1ea3, 0x00e5, 0, 0x01ce, 0x0201, 0x0203, 0, 0, 0, 0x1ea1, 0, 0x1e01, 0, 0, 0x0105, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e05, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e07, 0, 0, 0, 0 }, { 0, 0x0107, 0x0109, 0, 0, 0, 0x010b, 0, 0, 0, 0, 0x010d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00e7, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e0b, 0, 0, 0, 0, 0x010f, 0, 0, 0, 0, 0, 0x1e0d, 0, 0, 0, 0x1e11, 0, 0x1e13, 0, 0, 0x1e0f, 0, 0, 0, 0 }, { 0x00e8, 0x00e9, 0x00ea, 0x1ebd, 0x0113, 0x0115, 0x0117, 0x00eb, 0x1ebb, 0, 0, 0x011b, 0x0205, 0x0207, 0, 0, 0, 0x1eb9, 0, 0, 0, 0x0229, 0x0119, 0x1e19, 0, 0x1e1b, 0, 0, 0, 0, 0 }, { 0, 0x01f5, 0x011d, 0, 0x1e21, 0x011f, 0x0121, 0, 0, 0, 0, 0x01e7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0123, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0x0125, 0, 0, 0, 0x1e23, 0x1e27, 0, 0, 0, 0x021f, 0, 0, 0, 0, 0, 0x1e25, 0, 0, 0, 0x1e29, 0, 0, 0x1e2b, 0, 0x1e96, 0, 0, 0, 0 }, { 0x00ec, 0x00ed, 0x00ee, 0x0129, 0x012b, 0x012d, 0, 0x00ef, 0x1ec9, 0, 0, 0x01d0, 0x0209, 0x020b, 0, 0, 0, 0x1ecb, 0, 0, 0, 0, 0x012f, 0, 0, 0x1e2d, 0, 0, 0, 0, 0 }, { 0, 0, 0x0135, 0, 0, 0, 0, 0, 0, 0, 0, 0x01f0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x1e31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01e9, 0, 0, 0, 0, 0, 0x1e33, 0, 0, 0, 0x0137, 0, 0, 0, 0, 0x1e35, 0, 0, 0, 0 }, { 0, 0x013a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x013e, 0, 0, 0, 0, 0, 0x1e37, 0, 0, 0, 0x013c, 0, 0x1e3d, 0, 0, 0x1e3b, 0, 0, 0, 0 }, { 0, 0x1e3f, 0, 0, 0, 0, 0x1e41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x01f9, 0x0144, 0, 0x00f1, 0, 0, 0x1e45, 0, 0, 0, 0, 0x0148, 0, 0, 0, 0, 0, 0x1e47, 0, 0, 0, 0x0146, 0, 0x1e4b, 0, 0, 0x1e49, 0, 0, 0, 0 }, { 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x014d, 0x014f, 0x022f, 0x00f6, 0x1ecf, 0, 0x0151, 0x01d2, 0x020d, 0x020f, 0, 0, 0x01a1, 0x1ecd, 0, 0, 0, 0, 0x01eb, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x1e55, 0, 0, 0, 0, 0x1e57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x0155, 0, 0, 0, 0, 0x1e59, 0, 0, 0, 0, 0x0159, 0x0211, 0x0213, 0, 0, 0, 0x1e5b, 0, 0, 0, 0x0157, 0, 0, 0, 0, 0x1e5f, 0, 0, 0, 0 }, { 0, 0x015b, 0x015d, 0, 0, 0, 0x1e61, 0, 0, 0, 0, 0x0161, 0, 0, 0, 0, 0, 0x1e63, 0, 0, 0x0219, 0x015f, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e6b, 0x1e97, 0, 0, 0, 0x0165, 0, 0, 0, 0, 0, 0x1e6d, 0, 0, 0x021b, 0x0163, 0, 0x1e71, 0, 0, 0x1e6f, 0, 0, 0, 0 }, { 0x00f9, 0x00fa, 0x00fb, 0x0169, 0x016b, 0x016d, 0, 0x00fc, 0x1ee7, 0x016f, 0x0171, 0x01d4, 0x0215, 0x0217, 0, 0, 0x01b0, 0x1ee5, 0x1e73, 0, 0, 0, 0x0173, 0x1e77, 0, 0x1e75, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0x1e7d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e7f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1e81, 0x1e83, 0x0175, 0, 0, 0, 0x1e87, 0x1e85, 0, 0x1e98, 0, 0, 0, 0, 0, 0, 0, 0x1e89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0x1e8b, 0x1e8d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ef3, 0x00fd, 0x0177, 0x1ef9, 0x0233, 0, 0x1e8f, 0x00ff, 0x1ef7, 0x1e99, 0, 0, 0, 0, 0, 0, 0, 0x1ef5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x017a, 0x1e91, 0, 0, 0, 0x017c, 0, 0, 0, 0, 0x017e, 0, 0, 0, 0, 0, 0x1e93, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e95, 0, 0, 0, 0 }, { 0x1fed, 0x0385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fc1, 0, 0, 0 }, { 0x1ea6, 0x1ea4, 0, 0x1eaa, 0, 0, 0, 0, 0x1ea8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x01fc, 0, 0, 0x01e2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ec0, 0x1ebe, 0, 0x1ec4, 0, 0, 0, 0, 0x1ec2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ed2, 0x1ed0, 0, 0x1ed6, 0, 0, 0, 0, 0x1ed4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x1e4c, 0, 0, 0x022c, 0, 0, 0x1e4e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x01db, 0x01d7, 0, 0, 0x01d5, 0, 0, 0, 0, 0, 0, 0x01d9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ea7, 0x1ea5, 0, 0x1eab, 0, 0, 0, 0, 0x1ea9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x01fd, 0, 0, 0x01e3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ec1, 0x1ebf, 0, 0x1ec5, 0, 0, 0, 0, 0x1ec3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ed3, 0x1ed1, 0, 0x1ed7, 0, 0, 0, 0, 0x1ed5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0x1e4d, 0, 0, 0x022d, 0, 0, 0x1e4f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x01dc, 0x01d8, 0, 0, 0x01d6, 0, 0, 0, 0, 0, 0, 0x01da, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1eb0, 0x1eae, 0, 0x1eb4, 0, 0, 0, 0, 0x1eb2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1eb1, 0x1eaf, 0, 0x1eb5, 0, 0, 0, 0, 0x1eb3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1e14, 0x1e16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1e15, 0x1e17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1e50, 0x1e52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1e51, 0x1e53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1edc, 0x1eda, 0, 0x1ee0, 0, 0, 0, 0, 0x1ede, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ee2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1edd, 0x1edb, 0, 0x1ee1, 0, 0, 0, 0, 0x1edf, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ee3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1eea, 0x1ee8, 0, 0x1eee, 0, 0, 0, 0, 0x1eec, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ef0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1eeb, 0x1ee9, 0, 0x1eef, 0, 0, 0, 0, 0x1eed, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ef1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1fba, 0x0386, 0, 0, 0x1fb9, 0x1fb8, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f08, 0x1f09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fbc, 0, 0 }, { 0x1fc8, 0x0388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f18, 0x1f19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1fca, 0x0389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f28, 0x1f29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fcc, 0, 0 }, { 0x1fda, 0x038a, 0, 0, 0x1fd9, 0x1fd8, 0, 0x03aa, 0, 0, 0, 0, 0, 0, 0x1f38, 0x1f39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ff8, 0x038c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f48, 0x1f49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1fea, 0x038e, 0, 0, 0x1fe9, 0x1fe8, 0, 0x03ab, 0, 0, 0, 0, 0, 0, 0, 0x1f59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1ffa, 0x038f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f68, 0x1f69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ffc, 0, 0 }, { 0x1f70, 0x03ac, 0, 0, 0x1fb1, 0x1fb0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f00, 0x1f01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fb6, 0x1fb3, 0, 0 }, { 0x1f72, 0x03ad, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f10, 0x1f11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f74, 0x03ae, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f20, 0x1f21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fc6, 0x1fc3, 0, 0 }, { 0x1f76, 0x03af, 0, 0, 0x1fd1, 0x1fd0, 0, 0x03ca, 0, 0, 0, 0, 0, 0, 0x1f30, 0x1f31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fd6, 0, 0, 0 }, { 0x1f78, 0x03cc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f40, 0x1f41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fe4, 0x1fe5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f7a, 0x03cd, 0, 0, 0x1fe1, 0x1fe0, 0, 0x03cb, 0, 0, 0, 0, 0, 0, 0x1f50, 0x1f51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fe6, 0, 0, 0 }, { 0x1f7c, 0x03ce, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f60, 0x1f61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ff6, 0x1ff3, 0, 0 }, { 0x1fd2, 0x0390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fd7, 0, 0, 0 }, { 0x1fe2, 0x03b0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fe7, 0, 0, 0 }, { 0, 0x03d3, 0, 0, 0, 0, 0, 0x03d4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0x04d0, 0, 0x04d2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x0400, 0, 0, 0, 0, 0x04d6, 0, 0x0401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0x04c1, 0, 0x04dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x040d, 0, 0, 0, 0x04e2, 0x0419, 0, 0x04e4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0x04ee, 0x040e, 0, 0x04f0, 0, 0, 0x04f2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0x04d1, 0, 0x04d3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x0450, 0, 0, 0, 0, 0x04d7, 0, 0x0451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0x04c2, 0, 0x04dd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x045d, 0, 0, 0, 0x04e3, 0x0439, 0, 0x04e5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0x04ef, 0x045e, 0, 0x04f1, 0, 0, 0x04f3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0x1eac, 0, 0, 0x1eb6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0x1ead, 0, 0, 0x1eb7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f02, 0x1f04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f06, 0x1f80, 0, 0 }, { 0x1f03, 0x1f05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f07, 0x1f81, 0, 0 }, { 0x1f0a, 0x1f0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f0e, 0x1f88, 0, 0 }, { 0x1f0b, 0x1f0d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f0f, 0x1f89, 0, 0 }, { 0x1f12, 0x1f14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f13, 0x1f15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f1a, 0x1f1c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f1b, 0x1f1d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f22, 0x1f24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f26, 0x1f90, 0, 0 }, { 0x1f23, 0x1f25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f27, 0x1f91, 0, 0 }, { 0x1f2a, 0x1f2c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f2e, 0x1f98, 0, 0 }, { 0x1f2b, 0x1f2d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f2f, 0x1f99, 0, 0 }, { 0x1f32, 0x1f34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f36, 0, 0, 0 }, { 0x1f33, 0x1f35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f37, 0, 0, 0 }, { 0x1f3a, 0x1f3c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f3e, 0, 0, 0 }, { 0x1f3b, 0x1f3d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f3f, 0, 0, 0 }, { 0x1f42, 0x1f44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f43, 0x1f45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f4a, 0x1f4c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f4b, 0x1f4d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0x1f52, 0x1f54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f56, 0, 0, 0 }, { 0x1f53, 0x1f55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f57, 0, 0, 0 }, { 0x1f5b, 0x1f5d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f5f, 0, 0, 0 }, { 0x1f62, 0x1f64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f66, 0x1fa0, 0, 0 }, { 0x1f63, 0x1f65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f67, 0x1fa1, 0, 0 }, { 0x1f6a, 0x1f6c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f6e, 0x1fa8, 0, 0 }, { 0x1f6b, 0x1f6d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f6f, 0x1fa9, 0, 0 }, { 0x1fcd, 0x1fce, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fcf, 0, 0, 0 }, { 0x1fdd, 0x1fde, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fdf, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3070, 0x3071 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3073, 0x3074 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3076, 0x3077 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3079, 0x307a }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x307c, 0x307d }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d0, 0x30d1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d3, 0x30d4 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d6, 0x30d7 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d9, 0x30da }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30dc, 0x30dd } }; psi-0.14/iris/src/libidn/gunidecomp.h0000644000175000017500000161754211305557616015665 0ustar janjan/* This file is automatically generated. DO NOT EDIT! */ #ifndef DECOMP_H #define DECOMP_H #define G_UNICODE_LAST_CHAR 0x10ffff #define G_UNICODE_MAX_TABLE_INDEX (0x110000 / 256) #define G_UNICODE_LAST_CHAR_PART1 0x2FAFF #define G_UNICODE_LAST_PAGE_PART1 762 #define G_UNICODE_NOT_PRESENT_OFFSET 65535 static const guchar cclass_data[][256] = { { /* page 3, index 0 */ 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230, 230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230, 230, 230, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 4, index 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 5, index 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 230, 230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230, 230, 230, 230, 0, 220, 220, 220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 20, 21, 22, 0, 23, 0, 24, 25, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 6, index 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 230, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230, 230, 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 7, index 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230, 230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 9, index 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 10, index 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 11, index 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 12, index 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 13, index 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 14, index 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 15, index 11 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, 0, 132, 0, 0, 0, 0, 0, 130, 130, 130, 130, 0, 0, 130, 0, 230, 230, 9, 0, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 16, index 12 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 23, index 13 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 24, index 14 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 32, index 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0, 0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 48, index 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 251, index 17 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 254, index 18 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 465, index 19 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216, 216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220, 220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; static const gint16 combining_class_table_part1[763] = { 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 /* page 3 */, 1 /* page 4 */, 2 /* page 5 */, 3 /* page 6 */, 4 /* page 7 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 5 /* page 9 */, 6 /* page 10 */, 7 /* page 11 */, 8 /* page 12 */, 9 /* page 13 */, 10 /* page 14 */, 11 /* page 15 */, 12 /* page 16 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 13 /* page 23 */, 14 /* page 24 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 15 /* page 32 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 16 /* page 48 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 17 /* page 251 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 18 /* page 254 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 19 /* page 465 */, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX }; static const gint16 combining_class_table_part2[768] = { 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX, 0 + G_UNICODE_MAX_TABLE_INDEX }; typedef struct { gunichar ch; guint16 canon_offset; guint16 compat_offset; } decomposition; static const decomposition decomp_table[] = { { 0x00a0, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x00a8, G_UNICODE_NOT_PRESENT_OFFSET, 2 }, { 0x00aa, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x00af, G_UNICODE_NOT_PRESENT_OFFSET, 8 }, { 0x00b2, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x00b3, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x00b4, G_UNICODE_NOT_PRESENT_OFFSET, 16 }, { 0x00b5, G_UNICODE_NOT_PRESENT_OFFSET, 20 }, { 0x00b8, G_UNICODE_NOT_PRESENT_OFFSET, 23 }, { 0x00b9, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x00ba, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x00bc, G_UNICODE_NOT_PRESENT_OFFSET, 31 }, { 0x00bd, G_UNICODE_NOT_PRESENT_OFFSET, 37 }, { 0x00be, G_UNICODE_NOT_PRESENT_OFFSET, 43 }, { 0x00c0, 49, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c1, 53, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c2, 57, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c3, 61, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c4, 65, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c5, 69, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c7, 73, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c8, 77, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00c9, 81, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ca, 85, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00cb, 89, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00cc, 93, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00cd, 97, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ce, 101, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00cf, 105, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d1, 109, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d2, 113, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d3, 117, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d4, 121, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d5, 125, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d6, 129, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00d9, 133, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00da, 137, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00db, 141, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00dc, 145, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00dd, 149, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e0, 153, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e1, 157, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e2, 161, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e3, 165, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e4, 169, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e5, 173, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e7, 177, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e8, 181, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00e9, 185, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ea, 189, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00eb, 193, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ec, 197, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ed, 201, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ee, 205, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ef, 209, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f1, 213, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f2, 217, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f3, 221, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f4, 225, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f5, 229, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f6, 233, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00f9, 237, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00fa, 241, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00fb, 245, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00fc, 249, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00fd, 253, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x00ff, 257, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0100, 261, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0101, 265, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0102, 269, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0103, 273, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0104, 277, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0105, 281, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0106, 285, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0107, 289, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0108, 293, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0109, 297, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x010a, 301, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x010b, 305, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x010c, 309, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x010d, 313, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x010e, 317, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x010f, 321, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0112, 325, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0113, 329, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0114, 333, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0115, 337, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0116, 341, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0117, 345, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0118, 349, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0119, 353, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x011a, 357, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x011b, 361, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x011c, 365, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x011d, 369, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x011e, 373, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x011f, 377, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0120, 381, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0121, 385, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0122, 389, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0123, 393, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0124, 397, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0125, 401, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0128, 405, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0129, 409, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x012a, 413, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x012b, 417, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x012c, 421, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x012d, 425, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x012e, 429, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x012f, 433, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0130, 437, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0132, G_UNICODE_NOT_PRESENT_OFFSET, 441 }, { 0x0133, G_UNICODE_NOT_PRESENT_OFFSET, 444 }, { 0x0134, 447, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0135, 451, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0136, 455, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0137, 459, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0139, 463, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x013a, 467, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x013b, 471, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x013c, 475, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x013d, 479, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x013e, 483, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x013f, G_UNICODE_NOT_PRESENT_OFFSET, 487 }, { 0x0140, G_UNICODE_NOT_PRESENT_OFFSET, 491 }, { 0x0143, 495, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0144, 499, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0145, 503, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0146, 507, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0147, 511, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0148, 515, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0149, G_UNICODE_NOT_PRESENT_OFFSET, 519 }, { 0x014c, 523, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x014d, 527, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x014e, 531, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x014f, 535, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0150, 539, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0151, 543, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0154, 547, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0155, 551, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0156, 555, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0157, 559, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0158, 563, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0159, 567, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x015a, 571, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x015b, 575, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x015c, 579, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x015d, 583, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x015e, 587, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x015f, 591, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0160, 595, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0161, 599, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0162, 603, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0163, 607, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0164, 611, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0165, 615, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0168, 619, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0169, 623, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x016a, 627, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x016b, 631, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x016c, 635, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x016d, 639, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x016e, 643, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x016f, 647, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0170, 651, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0171, 655, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0172, 659, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0173, 663, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0174, 667, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0175, 671, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0176, 675, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0177, 679, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0178, 683, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0179, 687, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x017a, 691, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x017b, 695, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x017c, 699, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x017d, 703, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x017e, 707, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x017f, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x01a0, 713, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01a1, 717, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01af, 721, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01b0, 725, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01c4, G_UNICODE_NOT_PRESENT_OFFSET, 729 }, { 0x01c5, G_UNICODE_NOT_PRESENT_OFFSET, 734 }, { 0x01c6, G_UNICODE_NOT_PRESENT_OFFSET, 739 }, { 0x01c7, G_UNICODE_NOT_PRESENT_OFFSET, 744 }, { 0x01c8, G_UNICODE_NOT_PRESENT_OFFSET, 747 }, { 0x01c9, G_UNICODE_NOT_PRESENT_OFFSET, 750 }, { 0x01ca, G_UNICODE_NOT_PRESENT_OFFSET, 753 }, { 0x01cb, G_UNICODE_NOT_PRESENT_OFFSET, 756 }, { 0x01cc, G_UNICODE_NOT_PRESENT_OFFSET, 759 }, { 0x01cd, 762, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ce, 766, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01cf, 770, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d0, 774, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d1, 778, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d2, 782, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d3, 786, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d4, 790, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d5, 794, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d6, 800, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d7, 806, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d8, 812, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01d9, 818, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01da, 824, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01db, 830, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01dc, 836, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01de, 842, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01df, 848, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e0, 854, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e1, 860, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e2, 866, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e3, 871, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e6, 876, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e7, 880, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e8, 884, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01e9, 888, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ea, 892, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01eb, 896, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ec, 900, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ed, 906, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ee, 912, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ef, 917, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01f0, 922, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01f1, G_UNICODE_NOT_PRESENT_OFFSET, 926 }, { 0x01f2, G_UNICODE_NOT_PRESENT_OFFSET, 929 }, { 0x01f3, G_UNICODE_NOT_PRESENT_OFFSET, 932 }, { 0x01f4, 935, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01f5, 939, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01f8, 943, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01f9, 947, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01fa, 951, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01fb, 957, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01fc, 963, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01fd, 968, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01fe, 973, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x01ff, 978, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0200, 983, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0201, 987, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0202, 991, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0203, 995, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0204, 999, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0205, 1003, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0206, 1007, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0207, 1011, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0208, 1015, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0209, 1019, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x020a, 1023, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x020b, 1027, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x020c, 1031, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x020d, 1035, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x020e, 1039, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x020f, 1043, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0210, 1047, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0211, 1051, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0212, 1055, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0213, 1059, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0214, 1063, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0215, 1067, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0216, 1071, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0217, 1075, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0218, 1079, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0219, 1083, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x021a, 1087, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x021b, 1091, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x021e, 1095, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x021f, 1099, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0226, 1103, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0227, 1107, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0228, 1111, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0229, 1115, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x022a, 1119, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x022b, 1125, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x022c, 1131, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x022d, 1137, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x022e, 1143, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x022f, 1147, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0230, 1151, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0231, 1157, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0232, 1163, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0233, 1167, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x02b0, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x02b1, G_UNICODE_NOT_PRESENT_OFFSET, 1173 }, { 0x02b2, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x02b3, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x02b4, G_UNICODE_NOT_PRESENT_OFFSET, 1180 }, { 0x02b5, G_UNICODE_NOT_PRESENT_OFFSET, 1183 }, { 0x02b6, G_UNICODE_NOT_PRESENT_OFFSET, 1186 }, { 0x02b7, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x02b8, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x02d8, G_UNICODE_NOT_PRESENT_OFFSET, 1193 }, { 0x02d9, G_UNICODE_NOT_PRESENT_OFFSET, 1197 }, { 0x02da, G_UNICODE_NOT_PRESENT_OFFSET, 1201 }, { 0x02db, G_UNICODE_NOT_PRESENT_OFFSET, 1205 }, { 0x02dc, G_UNICODE_NOT_PRESENT_OFFSET, 1209 }, { 0x02dd, G_UNICODE_NOT_PRESENT_OFFSET, 1213 }, { 0x02e0, G_UNICODE_NOT_PRESENT_OFFSET, 1217 }, { 0x02e1, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x02e2, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x02e3, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x02e4, G_UNICODE_NOT_PRESENT_OFFSET, 1224 }, { 0x0340, 1227, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0341, 1230, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0343, 1233, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0344, 1236, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0374, 1241, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x037a, G_UNICODE_NOT_PRESENT_OFFSET, 1244 }, { 0x037e, 1248, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0384, G_UNICODE_NOT_PRESENT_OFFSET, 16 }, { 0x0385, 1250, 1255 }, { 0x0386, 1261, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0387, 1266, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0388, 1269, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0389, 1274, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x038a, 1279, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x038c, 1284, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x038e, 1289, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x038f, 1294, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0390, 1299, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03aa, 1306, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03ab, 1311, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03ac, 1316, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03ad, 1321, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03ae, 1326, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03af, 1331, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03b0, 1336, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03ca, 1343, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03cb, 1348, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03cc, 1353, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03cd, 1358, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03ce, 1363, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x03d0, G_UNICODE_NOT_PRESENT_OFFSET, 1368 }, { 0x03d1, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x03d2, G_UNICODE_NOT_PRESENT_OFFSET, 1374 }, { 0x03d3, 1377, 1289 }, { 0x03d4, 1382, 1311 }, { 0x03d5, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x03d6, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x03f0, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x03f1, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x03f2, G_UNICODE_NOT_PRESENT_OFFSET, 1399 }, { 0x03f4, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x03f5, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x0400, 1408, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0401, 1413, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0403, 1418, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0407, 1423, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x040c, 1428, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x040d, 1433, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x040e, 1438, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0419, 1443, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0439, 1448, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0450, 1453, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0451, 1458, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0453, 1463, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0457, 1468, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x045c, 1473, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x045d, 1478, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x045e, 1483, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0476, 1488, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0477, 1493, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04c1, 1498, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04c2, 1503, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04d0, 1508, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04d1, 1513, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04d2, 1518, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04d3, 1523, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04d6, 1528, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04d7, 1533, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04da, 1538, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04db, 1543, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04dc, 1548, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04dd, 1553, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04de, 1558, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04df, 1563, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04e2, 1568, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04e3, 1573, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04e4, 1578, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04e5, 1583, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04e6, 1588, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04e7, 1593, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04ea, 1598, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04eb, 1603, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04ec, 1608, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04ed, 1613, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04ee, 1618, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04ef, 1623, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f0, 1628, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f1, 1633, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f2, 1638, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f3, 1643, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f4, 1648, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f5, 1653, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f8, 1658, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x04f9, 1663, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0587, G_UNICODE_NOT_PRESENT_OFFSET, 1668 }, { 0x0622, 1673, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0623, 1678, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0624, 1683, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0625, 1688, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0626, 1693, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0675, G_UNICODE_NOT_PRESENT_OFFSET, 1698 }, { 0x0676, G_UNICODE_NOT_PRESENT_OFFSET, 1703 }, { 0x0677, G_UNICODE_NOT_PRESENT_OFFSET, 1708 }, { 0x0678, G_UNICODE_NOT_PRESENT_OFFSET, 1713 }, { 0x06c0, 1718, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x06c2, 1723, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x06d3, 1728, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0929, 1733, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0931, 1740, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0934, 1747, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0958, 1754, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0959, 1761, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x095a, 1768, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x095b, 1775, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x095c, 1782, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x095d, 1789, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x095e, 1796, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x095f, 1803, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x09cb, 1810, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x09cc, 1817, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x09dc, 1824, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x09dd, 1831, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x09df, 1838, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0a33, 1845, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0a36, 1852, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0a59, 1859, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0a5a, 1866, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0a5b, 1873, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0a5e, 1880, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0b48, 1887, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0b4b, 1894, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0b4c, 1901, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0b5c, 1908, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0b5d, 1915, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0b94, 1922, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0bca, 1929, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0bcb, 1936, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0bcc, 1943, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0c48, 1950, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0cc0, 1957, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0cc7, 1964, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0cc8, 1971, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0cca, 1978, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0ccb, 1985, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0d4a, 1995, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0d4b, 2002, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0d4c, 2009, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0dda, 2016, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0ddc, 2023, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0ddd, 2030, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0dde, 2040, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0e33, G_UNICODE_NOT_PRESENT_OFFSET, 2047 }, { 0x0eb3, G_UNICODE_NOT_PRESENT_OFFSET, 2054 }, { 0x0edc, G_UNICODE_NOT_PRESENT_OFFSET, 2061 }, { 0x0edd, G_UNICODE_NOT_PRESENT_OFFSET, 2068 }, { 0x0f0c, G_UNICODE_NOT_PRESENT_OFFSET, 2075 }, { 0x0f43, 2079, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f4d, 2086, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f52, 2093, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f57, 2100, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f5c, 2107, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f69, 2114, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f73, 2121, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f75, 2128, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f76, 2135, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f77, G_UNICODE_NOT_PRESENT_OFFSET, 2142 }, { 0x0f78, 2152, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f79, G_UNICODE_NOT_PRESENT_OFFSET, 2159 }, { 0x0f81, 2169, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f93, 2176, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0f9d, 2183, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0fa2, 2190, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0fa7, 2197, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0fac, 2204, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x0fb9, 2211, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1026, 2218, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e00, 2225, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e01, 2229, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e02, 2233, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e03, 2237, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e04, 2241, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e05, 2245, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e06, 2249, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e07, 2253, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e08, 2257, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e09, 2263, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e0a, 2269, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e0b, 2273, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e0c, 2277, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e0d, 2281, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e0e, 2285, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e0f, 2289, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e10, 2293, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e11, 2297, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e12, 2301, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e13, 2305, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e14, 2309, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e15, 2315, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e16, 2321, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e17, 2327, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e18, 2333, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e19, 2337, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e1a, 2341, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e1b, 2345, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e1c, 2349, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e1d, 2355, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e1e, 2361, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e1f, 2365, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e20, 2369, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e21, 2373, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e22, 2377, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e23, 2381, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e24, 2385, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e25, 2389, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e26, 2393, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e27, 2397, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e28, 2401, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e29, 2405, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e2a, 2409, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e2b, 2413, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e2c, 2417, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e2d, 2421, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e2e, 2425, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e2f, 2431, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e30, 2437, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e31, 2441, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e32, 2445, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e33, 2449, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e34, 2453, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e35, 2457, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e36, 2461, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e37, 2465, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e38, 2469, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e39, 2475, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e3a, 2481, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e3b, 2485, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e3c, 2489, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e3d, 2493, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e3e, 2497, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e3f, 2501, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e40, 2505, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e41, 2509, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e42, 2513, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e43, 2517, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e44, 2521, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e45, 2525, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e46, 2529, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e47, 2533, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e48, 2537, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e49, 2541, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e4a, 2545, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e4b, 2549, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e4c, 2553, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e4d, 2559, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e4e, 2565, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e4f, 2571, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e50, 2577, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e51, 2583, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e52, 2589, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e53, 2595, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e54, 2601, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e55, 2605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e56, 2609, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e57, 2613, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e58, 2617, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e59, 2621, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e5a, 2625, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e5b, 2629, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e5c, 2633, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e5d, 2639, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e5e, 2645, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e5f, 2649, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e60, 2653, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e61, 2657, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e62, 2661, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e63, 2665, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e64, 2669, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e65, 2675, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e66, 2681, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e67, 2687, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e68, 2693, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e69, 2699, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e6a, 2705, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e6b, 2709, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e6c, 2713, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e6d, 2717, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e6e, 2721, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e6f, 2725, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e70, 2729, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e71, 2733, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e72, 2737, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e73, 2741, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e74, 2745, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e75, 2749, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e76, 2753, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e77, 2757, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e78, 2761, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e79, 2767, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e7a, 2773, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e7b, 2779, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e7c, 2785, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e7d, 2789, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e7e, 2793, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e7f, 2797, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e80, 2801, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e81, 2805, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e82, 2809, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e83, 2813, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e84, 2817, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e85, 2821, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e86, 2825, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e87, 2829, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e88, 2833, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e89, 2837, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e8a, 2841, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e8b, 2845, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e8c, 2849, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e8d, 2853, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e8e, 2857, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e8f, 2861, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e90, 2865, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e91, 2869, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e92, 2873, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e93, 2877, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e94, 2881, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e95, 2885, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e96, 2889, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e97, 2893, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e98, 2897, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e99, 2901, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1e9a, G_UNICODE_NOT_PRESENT_OFFSET, 2905 }, { 0x1e9b, 2909, 2657 }, { 0x1ea0, 2914, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea1, 2918, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea2, 2922, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea3, 2926, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea4, 2930, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea5, 2936, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea6, 2942, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea7, 2948, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea8, 2954, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ea9, 2960, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eaa, 2966, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eab, 2972, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eac, 2978, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ead, 2984, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eae, 2990, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eaf, 2996, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb0, 3002, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb1, 3008, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb2, 3014, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb3, 3020, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb4, 3026, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb5, 3032, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb6, 3038, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb7, 3044, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb8, 3050, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eb9, 3054, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eba, 3058, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ebb, 3062, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ebc, 3066, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ebd, 3070, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ebe, 3074, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ebf, 3080, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec0, 3086, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec1, 3092, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec2, 3098, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec3, 3104, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec4, 3110, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec5, 3116, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec6, 3122, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec7, 3128, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec8, 3134, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ec9, 3138, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eca, 3142, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ecb, 3146, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ecc, 3150, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ecd, 3154, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ece, 3158, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ecf, 3162, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed0, 3166, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed1, 3172, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed2, 3178, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed3, 3184, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed4, 3190, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed5, 3196, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed6, 3202, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed7, 3208, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed8, 3214, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ed9, 3220, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eda, 3226, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1edb, 3232, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1edc, 3238, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1edd, 3244, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ede, 3250, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1edf, 3256, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee0, 3262, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee1, 3268, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee2, 3274, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee3, 3280, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee4, 3286, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee5, 3290, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee6, 3294, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee7, 3298, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee8, 3302, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ee9, 3308, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eea, 3314, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eeb, 3320, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eec, 3326, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eed, 3332, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eee, 3338, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1eef, 3344, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef0, 3350, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef1, 3356, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef2, 3362, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef3, 3366, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef4, 3370, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef5, 3374, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef6, 3378, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef7, 3382, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef8, 3386, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ef9, 3390, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f00, 3394, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f01, 3399, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f02, 3404, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f03, 3411, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f04, 3418, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f05, 3425, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f06, 3432, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f07, 3439, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f08, 3446, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f09, 3451, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f0a, 3456, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f0b, 3463, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f0c, 3470, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f0d, 3477, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f0e, 3484, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f0f, 3491, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f10, 3498, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f11, 3503, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f12, 3508, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f13, 3515, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f14, 3522, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f15, 3529, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f18, 3536, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f19, 3541, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f1a, 3546, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f1b, 3553, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f1c, 3560, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f1d, 3567, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f20, 3574, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f21, 3579, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f22, 3584, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f23, 3591, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f24, 3598, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f25, 3605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f26, 3612, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f27, 3619, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f28, 3626, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f29, 3631, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f2a, 3636, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f2b, 3643, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f2c, 3650, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f2d, 3657, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f2e, 3664, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f2f, 3671, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f30, 3678, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f31, 3683, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f32, 3688, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f33, 3695, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f34, 3702, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f35, 3709, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f36, 3716, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f37, 3723, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f38, 3730, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f39, 3735, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f3a, 3740, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f3b, 3747, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f3c, 3754, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f3d, 3761, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f3e, 3768, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f3f, 3775, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f40, 3782, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f41, 3787, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f42, 3792, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f43, 3799, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f44, 3806, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f45, 3813, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f48, 3820, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f49, 3825, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f4a, 3830, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f4b, 3837, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f4c, 3844, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f4d, 3851, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f50, 3858, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f51, 3863, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f52, 3868, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f53, 3875, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f54, 3882, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f55, 3889, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f56, 3896, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f57, 3903, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f59, 3910, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f5b, 3915, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f5d, 3922, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f5f, 3929, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f60, 3936, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f61, 3941, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f62, 3946, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f63, 3953, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f64, 3960, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f65, 3967, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f66, 3974, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f67, 3981, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f68, 3988, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f69, 3993, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f6a, 3998, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f6b, 4005, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f6c, 4012, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f6d, 4019, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f6e, 4026, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f6f, 4033, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f70, 4040, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f71, 1316, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f72, 4045, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f73, 1321, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f74, 4050, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f75, 1326, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f76, 4055, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f77, 1331, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f78, 4060, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f79, 1353, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f7a, 4065, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f7b, 1358, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f7c, 4070, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f7d, 1363, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f80, 4075, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f81, 4082, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f82, 4089, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f83, 4098, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f84, 4107, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f85, 4116, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f86, 4125, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f87, 4134, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f88, 4143, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f89, 4150, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f8a, 4157, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f8b, 4166, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f8c, 4175, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f8d, 4184, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f8e, 4193, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f8f, 4202, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f90, 4211, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f91, 4218, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f92, 4225, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f93, 4234, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f94, 4243, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f95, 4252, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f96, 4261, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f97, 4270, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f98, 4279, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f99, 4286, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f9a, 4293, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f9b, 4302, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f9c, 4311, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f9d, 4320, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f9e, 4329, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1f9f, 4338, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa0, 4347, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa1, 4354, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa2, 4361, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa3, 4370, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa4, 4379, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa5, 4388, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa6, 4397, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa7, 4406, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa8, 4415, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fa9, 4422, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1faa, 4429, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fab, 4438, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fac, 4447, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fad, 4456, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fae, 4465, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1faf, 4474, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb0, 4483, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb1, 4488, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb2, 4493, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb3, 4500, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb4, 4505, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb6, 4512, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb7, 4517, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb8, 4524, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fb9, 4529, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fba, 4534, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fbb, 1261, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fbc, 4539, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fbd, G_UNICODE_NOT_PRESENT_OFFSET, 4544 }, { 0x1fbe, 4548, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fbf, G_UNICODE_NOT_PRESENT_OFFSET, 4544 }, { 0x1fc0, G_UNICODE_NOT_PRESENT_OFFSET, 4551 }, { 0x1fc1, 4555, 4560 }, { 0x1fc2, 4566, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fc3, 4573, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fc4, 4578, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fc6, 4585, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fc7, 4590, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fc8, 4597, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fc9, 1269, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fca, 4602, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fcb, 1274, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fcc, 4607, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fcd, 4612, 4618 }, { 0x1fce, 4624, 4630 }, { 0x1fcf, 4636, 4642 }, { 0x1fd0, 4648, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd1, 4653, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd2, 4658, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd3, 1299, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd6, 4665, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd7, 4670, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd8, 4677, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fd9, 4682, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fda, 4687, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fdb, 1279, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fdd, 4692, 4698 }, { 0x1fde, 4704, 4710 }, { 0x1fdf, 4716, 4722 }, { 0x1fe0, 4728, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe1, 4733, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe2, 4738, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe3, 1336, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe4, 4745, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe5, 4750, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe6, 4755, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe7, 4760, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe8, 4767, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fe9, 4772, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fea, 4777, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1feb, 1289, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fec, 4782, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1fed, 4787, 4792 }, { 0x1fee, 1250, 1255 }, { 0x1fef, 4798, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff2, 4800, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff3, 4807, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff4, 4812, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff6, 4819, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff7, 4824, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff8, 4831, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ff9, 1284, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ffa, 4836, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ffb, 1294, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ffc, 4841, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1ffd, 4846, 16 }, { 0x1ffe, G_UNICODE_NOT_PRESENT_OFFSET, 4849 }, { 0x2000, 4853, 0 }, { 0x2001, 4857, 0 }, { 0x2002, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2003, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2004, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2005, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2006, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2007, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2008, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2009, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x200a, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2011, G_UNICODE_NOT_PRESENT_OFFSET, 4861 }, { 0x2017, G_UNICODE_NOT_PRESENT_OFFSET, 4865 }, { 0x2024, G_UNICODE_NOT_PRESENT_OFFSET, 4869 }, { 0x2025, G_UNICODE_NOT_PRESENT_OFFSET, 4871 }, { 0x2026, G_UNICODE_NOT_PRESENT_OFFSET, 4874 }, { 0x202f, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2033, G_UNICODE_NOT_PRESENT_OFFSET, 4878 }, { 0x2034, G_UNICODE_NOT_PRESENT_OFFSET, 4885 }, { 0x2036, G_UNICODE_NOT_PRESENT_OFFSET, 4895 }, { 0x2037, G_UNICODE_NOT_PRESENT_OFFSET, 4902 }, { 0x203c, G_UNICODE_NOT_PRESENT_OFFSET, 4912 }, { 0x203e, G_UNICODE_NOT_PRESENT_OFFSET, 4915 }, { 0x2047, G_UNICODE_NOT_PRESENT_OFFSET, 4919 }, { 0x2048, G_UNICODE_NOT_PRESENT_OFFSET, 4922 }, { 0x2049, G_UNICODE_NOT_PRESENT_OFFSET, 4925 }, { 0x2057, G_UNICODE_NOT_PRESENT_OFFSET, 4928 }, { 0x205f, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x2070, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x2071, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x2074, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x2075, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x2076, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x2077, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x2078, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x2079, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x207a, G_UNICODE_NOT_PRESENT_OFFSET, 4957 }, { 0x207b, G_UNICODE_NOT_PRESENT_OFFSET, 4959 }, { 0x207c, G_UNICODE_NOT_PRESENT_OFFSET, 4963 }, { 0x207d, G_UNICODE_NOT_PRESENT_OFFSET, 4965 }, { 0x207e, G_UNICODE_NOT_PRESENT_OFFSET, 4967 }, { 0x207f, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x2080, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x2081, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x2082, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x2083, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x2084, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x2085, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x2086, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x2087, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x2088, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x2089, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x208a, G_UNICODE_NOT_PRESENT_OFFSET, 4957 }, { 0x208b, G_UNICODE_NOT_PRESENT_OFFSET, 4959 }, { 0x208c, G_UNICODE_NOT_PRESENT_OFFSET, 4963 }, { 0x208d, G_UNICODE_NOT_PRESENT_OFFSET, 4965 }, { 0x208e, G_UNICODE_NOT_PRESENT_OFFSET, 4967 }, { 0x20a8, G_UNICODE_NOT_PRESENT_OFFSET, 4971 }, { 0x2100, G_UNICODE_NOT_PRESENT_OFFSET, 4974 }, { 0x2101, G_UNICODE_NOT_PRESENT_OFFSET, 4978 }, { 0x2102, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x2103, G_UNICODE_NOT_PRESENT_OFFSET, 4984 }, { 0x2105, G_UNICODE_NOT_PRESENT_OFFSET, 4988 }, { 0x2106, G_UNICODE_NOT_PRESENT_OFFSET, 4992 }, { 0x2107, G_UNICODE_NOT_PRESENT_OFFSET, 4996 }, { 0x2109, G_UNICODE_NOT_PRESENT_OFFSET, 4999 }, { 0x210a, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x210b, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x210c, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x210d, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x210e, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x210f, G_UNICODE_NOT_PRESENT_OFFSET, 5007 }, { 0x2110, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x2111, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x2112, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x2113, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x2115, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x2116, G_UNICODE_NOT_PRESENT_OFFSET, 5016 }, { 0x2119, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x211a, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x211b, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x211c, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x211d, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x2120, G_UNICODE_NOT_PRESENT_OFFSET, 5025 }, { 0x2121, G_UNICODE_NOT_PRESENT_OFFSET, 5028 }, { 0x2122, G_UNICODE_NOT_PRESENT_OFFSET, 5032 }, { 0x2124, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x2126, 5037, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2128, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x212a, 5040, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x212b, 69, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x212c, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x212d, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x212f, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x2130, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x2131, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x2133, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x2134, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x2135, G_UNICODE_NOT_PRESENT_OFFSET, 5052 }, { 0x2136, G_UNICODE_NOT_PRESENT_OFFSET, 5055 }, { 0x2137, G_UNICODE_NOT_PRESENT_OFFSET, 5058 }, { 0x2138, G_UNICODE_NOT_PRESENT_OFFSET, 5061 }, { 0x2139, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x213d, G_UNICODE_NOT_PRESENT_OFFSET, 5064 }, { 0x213e, G_UNICODE_NOT_PRESENT_OFFSET, 5067 }, { 0x213f, G_UNICODE_NOT_PRESENT_OFFSET, 5070 }, { 0x2140, G_UNICODE_NOT_PRESENT_OFFSET, 5073 }, { 0x2145, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x2146, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x2147, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x2148, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x2149, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x2153, G_UNICODE_NOT_PRESENT_OFFSET, 5081 }, { 0x2154, G_UNICODE_NOT_PRESENT_OFFSET, 5087 }, { 0x2155, G_UNICODE_NOT_PRESENT_OFFSET, 5093 }, { 0x2156, G_UNICODE_NOT_PRESENT_OFFSET, 5099 }, { 0x2157, G_UNICODE_NOT_PRESENT_OFFSET, 5105 }, { 0x2158, G_UNICODE_NOT_PRESENT_OFFSET, 5111 }, { 0x2159, G_UNICODE_NOT_PRESENT_OFFSET, 5117 }, { 0x215a, G_UNICODE_NOT_PRESENT_OFFSET, 5123 }, { 0x215b, G_UNICODE_NOT_PRESENT_OFFSET, 5129 }, { 0x215c, G_UNICODE_NOT_PRESENT_OFFSET, 5135 }, { 0x215d, G_UNICODE_NOT_PRESENT_OFFSET, 5141 }, { 0x215e, G_UNICODE_NOT_PRESENT_OFFSET, 5147 }, { 0x215f, G_UNICODE_NOT_PRESENT_OFFSET, 5153 }, { 0x2160, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x2161, G_UNICODE_NOT_PRESENT_OFFSET, 5158 }, { 0x2162, G_UNICODE_NOT_PRESENT_OFFSET, 5161 }, { 0x2163, G_UNICODE_NOT_PRESENT_OFFSET, 5165 }, { 0x2164, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x2165, G_UNICODE_NOT_PRESENT_OFFSET, 5170 }, { 0x2166, G_UNICODE_NOT_PRESENT_OFFSET, 5173 }, { 0x2167, G_UNICODE_NOT_PRESENT_OFFSET, 5177 }, { 0x2168, G_UNICODE_NOT_PRESENT_OFFSET, 5182 }, { 0x2169, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x216a, G_UNICODE_NOT_PRESENT_OFFSET, 5187 }, { 0x216b, G_UNICODE_NOT_PRESENT_OFFSET, 5190 }, { 0x216c, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x216d, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x216e, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x216f, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x2170, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x2171, G_UNICODE_NOT_PRESENT_OFFSET, 5194 }, { 0x2172, G_UNICODE_NOT_PRESENT_OFFSET, 5197 }, { 0x2173, G_UNICODE_NOT_PRESENT_OFFSET, 5201 }, { 0x2174, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x2175, G_UNICODE_NOT_PRESENT_OFFSET, 5206 }, { 0x2176, G_UNICODE_NOT_PRESENT_OFFSET, 5209 }, { 0x2177, G_UNICODE_NOT_PRESENT_OFFSET, 5213 }, { 0x2178, G_UNICODE_NOT_PRESENT_OFFSET, 5218 }, { 0x2179, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x217a, G_UNICODE_NOT_PRESENT_OFFSET, 5221 }, { 0x217b, G_UNICODE_NOT_PRESENT_OFFSET, 5224 }, { 0x217c, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x217d, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x217e, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x217f, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x219a, 5232, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x219b, 5238, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x21ae, 5244, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x21cd, 5250, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x21ce, 5256, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x21cf, 5262, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2204, 5268, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2209, 5274, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x220c, 5280, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2224, 5286, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2226, 5292, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x222c, G_UNICODE_NOT_PRESENT_OFFSET, 5298 }, { 0x222d, G_UNICODE_NOT_PRESENT_OFFSET, 5305 }, { 0x222f, G_UNICODE_NOT_PRESENT_OFFSET, 5315 }, { 0x2230, G_UNICODE_NOT_PRESENT_OFFSET, 5322 }, { 0x2241, 5332, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2244, 5338, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2247, 5344, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2249, 5350, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2260, 5356, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2262, 5360, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x226d, 5366, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x226e, 5372, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x226f, 5376, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2270, 5380, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2271, 5386, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2274, 5392, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2275, 5398, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2278, 5404, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2279, 5410, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2280, 5416, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2281, 5422, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2284, 5428, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2285, 5434, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2288, 5440, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2289, 5446, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22ac, 5452, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22ad, 5458, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22ae, 5464, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22af, 5470, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22e0, 5476, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22e1, 5482, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22e2, 5488, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22e3, 5494, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22ea, 5500, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22eb, 5506, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22ec, 5512, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x22ed, 5518, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2329, 5524, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x232a, 5528, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2460, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x2461, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x2462, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x2463, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x2464, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x2465, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x2466, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x2467, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x2468, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x2469, G_UNICODE_NOT_PRESENT_OFFSET, 5532 }, { 0x246a, G_UNICODE_NOT_PRESENT_OFFSET, 5535 }, { 0x246b, G_UNICODE_NOT_PRESENT_OFFSET, 5538 }, { 0x246c, G_UNICODE_NOT_PRESENT_OFFSET, 5541 }, { 0x246d, G_UNICODE_NOT_PRESENT_OFFSET, 5544 }, { 0x246e, G_UNICODE_NOT_PRESENT_OFFSET, 5547 }, { 0x246f, G_UNICODE_NOT_PRESENT_OFFSET, 5550 }, { 0x2470, G_UNICODE_NOT_PRESENT_OFFSET, 5553 }, { 0x2471, G_UNICODE_NOT_PRESENT_OFFSET, 5556 }, { 0x2472, G_UNICODE_NOT_PRESENT_OFFSET, 5559 }, { 0x2473, G_UNICODE_NOT_PRESENT_OFFSET, 5562 }, { 0x2474, G_UNICODE_NOT_PRESENT_OFFSET, 5565 }, { 0x2475, G_UNICODE_NOT_PRESENT_OFFSET, 5569 }, { 0x2476, G_UNICODE_NOT_PRESENT_OFFSET, 5573 }, { 0x2477, G_UNICODE_NOT_PRESENT_OFFSET, 5577 }, { 0x2478, G_UNICODE_NOT_PRESENT_OFFSET, 5581 }, { 0x2479, G_UNICODE_NOT_PRESENT_OFFSET, 5585 }, { 0x247a, G_UNICODE_NOT_PRESENT_OFFSET, 5589 }, { 0x247b, G_UNICODE_NOT_PRESENT_OFFSET, 5593 }, { 0x247c, G_UNICODE_NOT_PRESENT_OFFSET, 5597 }, { 0x247d, G_UNICODE_NOT_PRESENT_OFFSET, 5601 }, { 0x247e, G_UNICODE_NOT_PRESENT_OFFSET, 5606 }, { 0x247f, G_UNICODE_NOT_PRESENT_OFFSET, 5611 }, { 0x2480, G_UNICODE_NOT_PRESENT_OFFSET, 5616 }, { 0x2481, G_UNICODE_NOT_PRESENT_OFFSET, 5621 }, { 0x2482, G_UNICODE_NOT_PRESENT_OFFSET, 5626 }, { 0x2483, G_UNICODE_NOT_PRESENT_OFFSET, 5631 }, { 0x2484, G_UNICODE_NOT_PRESENT_OFFSET, 5636 }, { 0x2485, G_UNICODE_NOT_PRESENT_OFFSET, 5641 }, { 0x2486, G_UNICODE_NOT_PRESENT_OFFSET, 5646 }, { 0x2487, G_UNICODE_NOT_PRESENT_OFFSET, 5651 }, { 0x2488, G_UNICODE_NOT_PRESENT_OFFSET, 5656 }, { 0x2489, G_UNICODE_NOT_PRESENT_OFFSET, 5659 }, { 0x248a, G_UNICODE_NOT_PRESENT_OFFSET, 5662 }, { 0x248b, G_UNICODE_NOT_PRESENT_OFFSET, 5665 }, { 0x248c, G_UNICODE_NOT_PRESENT_OFFSET, 5668 }, { 0x248d, G_UNICODE_NOT_PRESENT_OFFSET, 5671 }, { 0x248e, G_UNICODE_NOT_PRESENT_OFFSET, 5674 }, { 0x248f, G_UNICODE_NOT_PRESENT_OFFSET, 5677 }, { 0x2490, G_UNICODE_NOT_PRESENT_OFFSET, 5680 }, { 0x2491, G_UNICODE_NOT_PRESENT_OFFSET, 5683 }, { 0x2492, G_UNICODE_NOT_PRESENT_OFFSET, 5687 }, { 0x2493, G_UNICODE_NOT_PRESENT_OFFSET, 5691 }, { 0x2494, G_UNICODE_NOT_PRESENT_OFFSET, 5695 }, { 0x2495, G_UNICODE_NOT_PRESENT_OFFSET, 5699 }, { 0x2496, G_UNICODE_NOT_PRESENT_OFFSET, 5703 }, { 0x2497, G_UNICODE_NOT_PRESENT_OFFSET, 5707 }, { 0x2498, G_UNICODE_NOT_PRESENT_OFFSET, 5711 }, { 0x2499, G_UNICODE_NOT_PRESENT_OFFSET, 5715 }, { 0x249a, G_UNICODE_NOT_PRESENT_OFFSET, 5719 }, { 0x249b, G_UNICODE_NOT_PRESENT_OFFSET, 5723 }, { 0x249c, G_UNICODE_NOT_PRESENT_OFFSET, 5727 }, { 0x249d, G_UNICODE_NOT_PRESENT_OFFSET, 5731 }, { 0x249e, G_UNICODE_NOT_PRESENT_OFFSET, 5735 }, { 0x249f, G_UNICODE_NOT_PRESENT_OFFSET, 5739 }, { 0x24a0, G_UNICODE_NOT_PRESENT_OFFSET, 5743 }, { 0x24a1, G_UNICODE_NOT_PRESENT_OFFSET, 5747 }, { 0x24a2, G_UNICODE_NOT_PRESENT_OFFSET, 5751 }, { 0x24a3, G_UNICODE_NOT_PRESENT_OFFSET, 5755 }, { 0x24a4, G_UNICODE_NOT_PRESENT_OFFSET, 5759 }, { 0x24a5, G_UNICODE_NOT_PRESENT_OFFSET, 5763 }, { 0x24a6, G_UNICODE_NOT_PRESENT_OFFSET, 5767 }, { 0x24a7, G_UNICODE_NOT_PRESENT_OFFSET, 5771 }, { 0x24a8, G_UNICODE_NOT_PRESENT_OFFSET, 5775 }, { 0x24a9, G_UNICODE_NOT_PRESENT_OFFSET, 5779 }, { 0x24aa, G_UNICODE_NOT_PRESENT_OFFSET, 5783 }, { 0x24ab, G_UNICODE_NOT_PRESENT_OFFSET, 5787 }, { 0x24ac, G_UNICODE_NOT_PRESENT_OFFSET, 5791 }, { 0x24ad, G_UNICODE_NOT_PRESENT_OFFSET, 5795 }, { 0x24ae, G_UNICODE_NOT_PRESENT_OFFSET, 5799 }, { 0x24af, G_UNICODE_NOT_PRESENT_OFFSET, 5803 }, { 0x24b0, G_UNICODE_NOT_PRESENT_OFFSET, 5807 }, { 0x24b1, G_UNICODE_NOT_PRESENT_OFFSET, 5811 }, { 0x24b2, G_UNICODE_NOT_PRESENT_OFFSET, 5815 }, { 0x24b3, G_UNICODE_NOT_PRESENT_OFFSET, 5819 }, { 0x24b4, G_UNICODE_NOT_PRESENT_OFFSET, 5823 }, { 0x24b5, G_UNICODE_NOT_PRESENT_OFFSET, 5827 }, { 0x24b6, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x24b7, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x24b8, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x24b9, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x24ba, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x24bb, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x24bc, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x24bd, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x24be, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x24bf, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x24c0, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x24c1, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x24c2, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x24c3, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x24c4, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x24c5, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x24c6, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x24c7, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x24c8, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x24c9, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x24ca, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x24cb, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x24cc, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x24cd, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x24ce, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x24cf, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x24d0, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x24d1, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x24d2, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x24d3, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x24d4, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x24d5, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x24d6, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x24d7, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x24d8, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x24d9, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x24da, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x24db, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x24dc, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x24dd, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x24de, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x24df, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x24e0, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x24e1, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x24e2, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x24e3, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x24e4, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x24e5, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x24e6, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x24e7, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x24e8, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x24e9, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x24ea, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x2a0c, G_UNICODE_NOT_PRESENT_OFFSET, 5865 }, { 0x2a74, G_UNICODE_NOT_PRESENT_OFFSET, 5878 }, { 0x2a75, G_UNICODE_NOT_PRESENT_OFFSET, 5882 }, { 0x2a76, G_UNICODE_NOT_PRESENT_OFFSET, 5885 }, { 0x2adc, 5889, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2e9f, G_UNICODE_NOT_PRESENT_OFFSET, 5895 }, { 0x2ef3, G_UNICODE_NOT_PRESENT_OFFSET, 5899 }, { 0x2f00, G_UNICODE_NOT_PRESENT_OFFSET, 5903 }, { 0x2f01, G_UNICODE_NOT_PRESENT_OFFSET, 5907 }, { 0x2f02, G_UNICODE_NOT_PRESENT_OFFSET, 5911 }, { 0x2f03, G_UNICODE_NOT_PRESENT_OFFSET, 5915 }, { 0x2f04, G_UNICODE_NOT_PRESENT_OFFSET, 5919 }, { 0x2f05, G_UNICODE_NOT_PRESENT_OFFSET, 5923 }, { 0x2f06, G_UNICODE_NOT_PRESENT_OFFSET, 5927 }, { 0x2f07, G_UNICODE_NOT_PRESENT_OFFSET, 5931 }, { 0x2f08, G_UNICODE_NOT_PRESENT_OFFSET, 5935 }, { 0x2f09, G_UNICODE_NOT_PRESENT_OFFSET, 5939 }, { 0x2f0a, G_UNICODE_NOT_PRESENT_OFFSET, 5943 }, { 0x2f0b, G_UNICODE_NOT_PRESENT_OFFSET, 5947 }, { 0x2f0c, G_UNICODE_NOT_PRESENT_OFFSET, 5951 }, { 0x2f0d, G_UNICODE_NOT_PRESENT_OFFSET, 5955 }, { 0x2f0e, G_UNICODE_NOT_PRESENT_OFFSET, 5959 }, { 0x2f0f, G_UNICODE_NOT_PRESENT_OFFSET, 5963 }, { 0x2f10, G_UNICODE_NOT_PRESENT_OFFSET, 5967 }, { 0x2f11, G_UNICODE_NOT_PRESENT_OFFSET, 5971 }, { 0x2f12, G_UNICODE_NOT_PRESENT_OFFSET, 5975 }, { 0x2f13, G_UNICODE_NOT_PRESENT_OFFSET, 5979 }, { 0x2f14, G_UNICODE_NOT_PRESENT_OFFSET, 5983 }, { 0x2f15, G_UNICODE_NOT_PRESENT_OFFSET, 5987 }, { 0x2f16, G_UNICODE_NOT_PRESENT_OFFSET, 5991 }, { 0x2f17, G_UNICODE_NOT_PRESENT_OFFSET, 5995 }, { 0x2f18, G_UNICODE_NOT_PRESENT_OFFSET, 5999 }, { 0x2f19, G_UNICODE_NOT_PRESENT_OFFSET, 6003 }, { 0x2f1a, G_UNICODE_NOT_PRESENT_OFFSET, 6007 }, { 0x2f1b, G_UNICODE_NOT_PRESENT_OFFSET, 6011 }, { 0x2f1c, G_UNICODE_NOT_PRESENT_OFFSET, 6015 }, { 0x2f1d, G_UNICODE_NOT_PRESENT_OFFSET, 6019 }, { 0x2f1e, G_UNICODE_NOT_PRESENT_OFFSET, 6023 }, { 0x2f1f, G_UNICODE_NOT_PRESENT_OFFSET, 6027 }, { 0x2f20, G_UNICODE_NOT_PRESENT_OFFSET, 6031 }, { 0x2f21, G_UNICODE_NOT_PRESENT_OFFSET, 6035 }, { 0x2f22, G_UNICODE_NOT_PRESENT_OFFSET, 6039 }, { 0x2f23, G_UNICODE_NOT_PRESENT_OFFSET, 6043 }, { 0x2f24, G_UNICODE_NOT_PRESENT_OFFSET, 6047 }, { 0x2f25, G_UNICODE_NOT_PRESENT_OFFSET, 6051 }, { 0x2f26, G_UNICODE_NOT_PRESENT_OFFSET, 6055 }, { 0x2f27, G_UNICODE_NOT_PRESENT_OFFSET, 6059 }, { 0x2f28, G_UNICODE_NOT_PRESENT_OFFSET, 6063 }, { 0x2f29, G_UNICODE_NOT_PRESENT_OFFSET, 6067 }, { 0x2f2a, G_UNICODE_NOT_PRESENT_OFFSET, 6071 }, { 0x2f2b, G_UNICODE_NOT_PRESENT_OFFSET, 6075 }, { 0x2f2c, G_UNICODE_NOT_PRESENT_OFFSET, 6079 }, { 0x2f2d, G_UNICODE_NOT_PRESENT_OFFSET, 6083 }, { 0x2f2e, G_UNICODE_NOT_PRESENT_OFFSET, 6087 }, { 0x2f2f, G_UNICODE_NOT_PRESENT_OFFSET, 6091 }, { 0x2f30, G_UNICODE_NOT_PRESENT_OFFSET, 6095 }, { 0x2f31, G_UNICODE_NOT_PRESENT_OFFSET, 6099 }, { 0x2f32, G_UNICODE_NOT_PRESENT_OFFSET, 6103 }, { 0x2f33, G_UNICODE_NOT_PRESENT_OFFSET, 6107 }, { 0x2f34, G_UNICODE_NOT_PRESENT_OFFSET, 6111 }, { 0x2f35, G_UNICODE_NOT_PRESENT_OFFSET, 6115 }, { 0x2f36, G_UNICODE_NOT_PRESENT_OFFSET, 6119 }, { 0x2f37, G_UNICODE_NOT_PRESENT_OFFSET, 6123 }, { 0x2f38, G_UNICODE_NOT_PRESENT_OFFSET, 6127 }, { 0x2f39, G_UNICODE_NOT_PRESENT_OFFSET, 6131 }, { 0x2f3a, G_UNICODE_NOT_PRESENT_OFFSET, 6135 }, { 0x2f3b, G_UNICODE_NOT_PRESENT_OFFSET, 6139 }, { 0x2f3c, G_UNICODE_NOT_PRESENT_OFFSET, 6143 }, { 0x2f3d, G_UNICODE_NOT_PRESENT_OFFSET, 6147 }, { 0x2f3e, G_UNICODE_NOT_PRESENT_OFFSET, 6151 }, { 0x2f3f, G_UNICODE_NOT_PRESENT_OFFSET, 6155 }, { 0x2f40, G_UNICODE_NOT_PRESENT_OFFSET, 6159 }, { 0x2f41, G_UNICODE_NOT_PRESENT_OFFSET, 6163 }, { 0x2f42, G_UNICODE_NOT_PRESENT_OFFSET, 6167 }, { 0x2f43, G_UNICODE_NOT_PRESENT_OFFSET, 6171 }, { 0x2f44, G_UNICODE_NOT_PRESENT_OFFSET, 6175 }, { 0x2f45, G_UNICODE_NOT_PRESENT_OFFSET, 6179 }, { 0x2f46, G_UNICODE_NOT_PRESENT_OFFSET, 6183 }, { 0x2f47, G_UNICODE_NOT_PRESENT_OFFSET, 6187 }, { 0x2f48, G_UNICODE_NOT_PRESENT_OFFSET, 6191 }, { 0x2f49, G_UNICODE_NOT_PRESENT_OFFSET, 6195 }, { 0x2f4a, G_UNICODE_NOT_PRESENT_OFFSET, 6199 }, { 0x2f4b, G_UNICODE_NOT_PRESENT_OFFSET, 6203 }, { 0x2f4c, G_UNICODE_NOT_PRESENT_OFFSET, 6207 }, { 0x2f4d, G_UNICODE_NOT_PRESENT_OFFSET, 6211 }, { 0x2f4e, G_UNICODE_NOT_PRESENT_OFFSET, 6215 }, { 0x2f4f, G_UNICODE_NOT_PRESENT_OFFSET, 6219 }, { 0x2f50, G_UNICODE_NOT_PRESENT_OFFSET, 6223 }, { 0x2f51, G_UNICODE_NOT_PRESENT_OFFSET, 6227 }, { 0x2f52, G_UNICODE_NOT_PRESENT_OFFSET, 6231 }, { 0x2f53, G_UNICODE_NOT_PRESENT_OFFSET, 6235 }, { 0x2f54, G_UNICODE_NOT_PRESENT_OFFSET, 6239 }, { 0x2f55, G_UNICODE_NOT_PRESENT_OFFSET, 6243 }, { 0x2f56, G_UNICODE_NOT_PRESENT_OFFSET, 6247 }, { 0x2f57, G_UNICODE_NOT_PRESENT_OFFSET, 6251 }, { 0x2f58, G_UNICODE_NOT_PRESENT_OFFSET, 6255 }, { 0x2f59, G_UNICODE_NOT_PRESENT_OFFSET, 6259 }, { 0x2f5a, G_UNICODE_NOT_PRESENT_OFFSET, 6263 }, { 0x2f5b, G_UNICODE_NOT_PRESENT_OFFSET, 6267 }, { 0x2f5c, G_UNICODE_NOT_PRESENT_OFFSET, 6271 }, { 0x2f5d, G_UNICODE_NOT_PRESENT_OFFSET, 6275 }, { 0x2f5e, G_UNICODE_NOT_PRESENT_OFFSET, 6279 }, { 0x2f5f, G_UNICODE_NOT_PRESENT_OFFSET, 6283 }, { 0x2f60, G_UNICODE_NOT_PRESENT_OFFSET, 6287 }, { 0x2f61, G_UNICODE_NOT_PRESENT_OFFSET, 6291 }, { 0x2f62, G_UNICODE_NOT_PRESENT_OFFSET, 6295 }, { 0x2f63, G_UNICODE_NOT_PRESENT_OFFSET, 6299 }, { 0x2f64, G_UNICODE_NOT_PRESENT_OFFSET, 6303 }, { 0x2f65, G_UNICODE_NOT_PRESENT_OFFSET, 6307 }, { 0x2f66, G_UNICODE_NOT_PRESENT_OFFSET, 6311 }, { 0x2f67, G_UNICODE_NOT_PRESENT_OFFSET, 6315 }, { 0x2f68, G_UNICODE_NOT_PRESENT_OFFSET, 6319 }, { 0x2f69, G_UNICODE_NOT_PRESENT_OFFSET, 6323 }, { 0x2f6a, G_UNICODE_NOT_PRESENT_OFFSET, 6327 }, { 0x2f6b, G_UNICODE_NOT_PRESENT_OFFSET, 6331 }, { 0x2f6c, G_UNICODE_NOT_PRESENT_OFFSET, 6335 }, { 0x2f6d, G_UNICODE_NOT_PRESENT_OFFSET, 6339 }, { 0x2f6e, G_UNICODE_NOT_PRESENT_OFFSET, 6343 }, { 0x2f6f, G_UNICODE_NOT_PRESENT_OFFSET, 6347 }, { 0x2f70, G_UNICODE_NOT_PRESENT_OFFSET, 6351 }, { 0x2f71, G_UNICODE_NOT_PRESENT_OFFSET, 6355 }, { 0x2f72, G_UNICODE_NOT_PRESENT_OFFSET, 6359 }, { 0x2f73, G_UNICODE_NOT_PRESENT_OFFSET, 6363 }, { 0x2f74, G_UNICODE_NOT_PRESENT_OFFSET, 6367 }, { 0x2f75, G_UNICODE_NOT_PRESENT_OFFSET, 6371 }, { 0x2f76, G_UNICODE_NOT_PRESENT_OFFSET, 6375 }, { 0x2f77, G_UNICODE_NOT_PRESENT_OFFSET, 6379 }, { 0x2f78, G_UNICODE_NOT_PRESENT_OFFSET, 6383 }, { 0x2f79, G_UNICODE_NOT_PRESENT_OFFSET, 6387 }, { 0x2f7a, G_UNICODE_NOT_PRESENT_OFFSET, 6391 }, { 0x2f7b, G_UNICODE_NOT_PRESENT_OFFSET, 6395 }, { 0x2f7c, G_UNICODE_NOT_PRESENT_OFFSET, 6399 }, { 0x2f7d, G_UNICODE_NOT_PRESENT_OFFSET, 6403 }, { 0x2f7e, G_UNICODE_NOT_PRESENT_OFFSET, 6407 }, { 0x2f7f, G_UNICODE_NOT_PRESENT_OFFSET, 6411 }, { 0x2f80, G_UNICODE_NOT_PRESENT_OFFSET, 6415 }, { 0x2f81, G_UNICODE_NOT_PRESENT_OFFSET, 6419 }, { 0x2f82, G_UNICODE_NOT_PRESENT_OFFSET, 6423 }, { 0x2f83, G_UNICODE_NOT_PRESENT_OFFSET, 6427 }, { 0x2f84, G_UNICODE_NOT_PRESENT_OFFSET, 6431 }, { 0x2f85, G_UNICODE_NOT_PRESENT_OFFSET, 6435 }, { 0x2f86, G_UNICODE_NOT_PRESENT_OFFSET, 6439 }, { 0x2f87, G_UNICODE_NOT_PRESENT_OFFSET, 6443 }, { 0x2f88, G_UNICODE_NOT_PRESENT_OFFSET, 6447 }, { 0x2f89, G_UNICODE_NOT_PRESENT_OFFSET, 6451 }, { 0x2f8a, G_UNICODE_NOT_PRESENT_OFFSET, 6455 }, { 0x2f8b, G_UNICODE_NOT_PRESENT_OFFSET, 6459 }, { 0x2f8c, G_UNICODE_NOT_PRESENT_OFFSET, 6463 }, { 0x2f8d, G_UNICODE_NOT_PRESENT_OFFSET, 6467 }, { 0x2f8e, G_UNICODE_NOT_PRESENT_OFFSET, 6471 }, { 0x2f8f, G_UNICODE_NOT_PRESENT_OFFSET, 6475 }, { 0x2f90, G_UNICODE_NOT_PRESENT_OFFSET, 6479 }, { 0x2f91, G_UNICODE_NOT_PRESENT_OFFSET, 6483 }, { 0x2f92, G_UNICODE_NOT_PRESENT_OFFSET, 6487 }, { 0x2f93, G_UNICODE_NOT_PRESENT_OFFSET, 6491 }, { 0x2f94, G_UNICODE_NOT_PRESENT_OFFSET, 6495 }, { 0x2f95, G_UNICODE_NOT_PRESENT_OFFSET, 6499 }, { 0x2f96, G_UNICODE_NOT_PRESENT_OFFSET, 6503 }, { 0x2f97, G_UNICODE_NOT_PRESENT_OFFSET, 6507 }, { 0x2f98, G_UNICODE_NOT_PRESENT_OFFSET, 6511 }, { 0x2f99, G_UNICODE_NOT_PRESENT_OFFSET, 6515 }, { 0x2f9a, G_UNICODE_NOT_PRESENT_OFFSET, 6519 }, { 0x2f9b, G_UNICODE_NOT_PRESENT_OFFSET, 6523 }, { 0x2f9c, G_UNICODE_NOT_PRESENT_OFFSET, 6527 }, { 0x2f9d, G_UNICODE_NOT_PRESENT_OFFSET, 6531 }, { 0x2f9e, G_UNICODE_NOT_PRESENT_OFFSET, 6535 }, { 0x2f9f, G_UNICODE_NOT_PRESENT_OFFSET, 6539 }, { 0x2fa0, G_UNICODE_NOT_PRESENT_OFFSET, 6543 }, { 0x2fa1, G_UNICODE_NOT_PRESENT_OFFSET, 6547 }, { 0x2fa2, G_UNICODE_NOT_PRESENT_OFFSET, 6551 }, { 0x2fa3, G_UNICODE_NOT_PRESENT_OFFSET, 6555 }, { 0x2fa4, G_UNICODE_NOT_PRESENT_OFFSET, 6559 }, { 0x2fa5, G_UNICODE_NOT_PRESENT_OFFSET, 6563 }, { 0x2fa6, G_UNICODE_NOT_PRESENT_OFFSET, 6567 }, { 0x2fa7, G_UNICODE_NOT_PRESENT_OFFSET, 6571 }, { 0x2fa8, G_UNICODE_NOT_PRESENT_OFFSET, 6575 }, { 0x2fa9, G_UNICODE_NOT_PRESENT_OFFSET, 6579 }, { 0x2faa, G_UNICODE_NOT_PRESENT_OFFSET, 6583 }, { 0x2fab, G_UNICODE_NOT_PRESENT_OFFSET, 6587 }, { 0x2fac, G_UNICODE_NOT_PRESENT_OFFSET, 6591 }, { 0x2fad, G_UNICODE_NOT_PRESENT_OFFSET, 6595 }, { 0x2fae, G_UNICODE_NOT_PRESENT_OFFSET, 6599 }, { 0x2faf, G_UNICODE_NOT_PRESENT_OFFSET, 6603 }, { 0x2fb0, G_UNICODE_NOT_PRESENT_OFFSET, 6607 }, { 0x2fb1, G_UNICODE_NOT_PRESENT_OFFSET, 6611 }, { 0x2fb2, G_UNICODE_NOT_PRESENT_OFFSET, 6615 }, { 0x2fb3, G_UNICODE_NOT_PRESENT_OFFSET, 6619 }, { 0x2fb4, G_UNICODE_NOT_PRESENT_OFFSET, 6623 }, { 0x2fb5, G_UNICODE_NOT_PRESENT_OFFSET, 6627 }, { 0x2fb6, G_UNICODE_NOT_PRESENT_OFFSET, 6631 }, { 0x2fb7, G_UNICODE_NOT_PRESENT_OFFSET, 6635 }, { 0x2fb8, G_UNICODE_NOT_PRESENT_OFFSET, 6639 }, { 0x2fb9, G_UNICODE_NOT_PRESENT_OFFSET, 6643 }, { 0x2fba, G_UNICODE_NOT_PRESENT_OFFSET, 6647 }, { 0x2fbb, G_UNICODE_NOT_PRESENT_OFFSET, 6651 }, { 0x2fbc, G_UNICODE_NOT_PRESENT_OFFSET, 6655 }, { 0x2fbd, G_UNICODE_NOT_PRESENT_OFFSET, 6659 }, { 0x2fbe, G_UNICODE_NOT_PRESENT_OFFSET, 6663 }, { 0x2fbf, G_UNICODE_NOT_PRESENT_OFFSET, 6667 }, { 0x2fc0, G_UNICODE_NOT_PRESENT_OFFSET, 6671 }, { 0x2fc1, G_UNICODE_NOT_PRESENT_OFFSET, 6675 }, { 0x2fc2, G_UNICODE_NOT_PRESENT_OFFSET, 6679 }, { 0x2fc3, G_UNICODE_NOT_PRESENT_OFFSET, 6683 }, { 0x2fc4, G_UNICODE_NOT_PRESENT_OFFSET, 6687 }, { 0x2fc5, G_UNICODE_NOT_PRESENT_OFFSET, 6691 }, { 0x2fc6, G_UNICODE_NOT_PRESENT_OFFSET, 6695 }, { 0x2fc7, G_UNICODE_NOT_PRESENT_OFFSET, 6699 }, { 0x2fc8, G_UNICODE_NOT_PRESENT_OFFSET, 6703 }, { 0x2fc9, G_UNICODE_NOT_PRESENT_OFFSET, 6707 }, { 0x2fca, G_UNICODE_NOT_PRESENT_OFFSET, 6711 }, { 0x2fcb, G_UNICODE_NOT_PRESENT_OFFSET, 6715 }, { 0x2fcc, G_UNICODE_NOT_PRESENT_OFFSET, 6719 }, { 0x2fcd, G_UNICODE_NOT_PRESENT_OFFSET, 6723 }, { 0x2fce, G_UNICODE_NOT_PRESENT_OFFSET, 6727 }, { 0x2fcf, G_UNICODE_NOT_PRESENT_OFFSET, 6731 }, { 0x2fd0, G_UNICODE_NOT_PRESENT_OFFSET, 6735 }, { 0x2fd1, G_UNICODE_NOT_PRESENT_OFFSET, 6739 }, { 0x2fd2, G_UNICODE_NOT_PRESENT_OFFSET, 6743 }, { 0x2fd3, G_UNICODE_NOT_PRESENT_OFFSET, 6747 }, { 0x2fd4, G_UNICODE_NOT_PRESENT_OFFSET, 6751 }, { 0x2fd5, G_UNICODE_NOT_PRESENT_OFFSET, 6755 }, { 0x3000, G_UNICODE_NOT_PRESENT_OFFSET, 0 }, { 0x3036, G_UNICODE_NOT_PRESENT_OFFSET, 6759 }, { 0x3038, G_UNICODE_NOT_PRESENT_OFFSET, 5995 }, { 0x3039, G_UNICODE_NOT_PRESENT_OFFSET, 6763 }, { 0x303a, G_UNICODE_NOT_PRESENT_OFFSET, 6767 }, { 0x304c, 6771, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x304e, 6778, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3050, 6785, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3052, 6792, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3054, 6799, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3056, 6806, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3058, 6813, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x305a, 6820, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x305c, 6827, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x305e, 6834, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3060, 6841, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3062, 6848, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3065, 6855, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3067, 6862, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3069, 6869, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3070, 6876, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3071, 6883, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3073, 6890, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3074, 6897, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3076, 6904, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3077, 6911, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3079, 6918, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x307a, 6925, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x307c, 6932, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x307d, 6939, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x3094, 6946, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x309b, G_UNICODE_NOT_PRESENT_OFFSET, 6953 }, { 0x309c, G_UNICODE_NOT_PRESENT_OFFSET, 6958 }, { 0x309e, 6963, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x309f, G_UNICODE_NOT_PRESENT_OFFSET, 6970 }, { 0x30ac, 6977, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30ae, 6984, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30b0, 6991, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30b2, 6998, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30b4, 7005, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30b6, 7012, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30b8, 7019, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30ba, 7026, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30bc, 7033, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30be, 7040, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30c0, 7047, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30c2, 7054, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30c5, 7061, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30c7, 7068, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30c9, 7075, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d0, 7082, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d1, 7089, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d3, 7096, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d4, 7103, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d6, 7110, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d7, 7117, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30d9, 7124, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30da, 7131, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30dc, 7138, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30dd, 7145, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30f4, 7152, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30f7, 7159, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30f8, 7166, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30f9, 7173, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30fa, 7180, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30fe, 7187, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x30ff, G_UNICODE_NOT_PRESENT_OFFSET, 7194 }, { 0x3131, G_UNICODE_NOT_PRESENT_OFFSET, 7201 }, { 0x3132, G_UNICODE_NOT_PRESENT_OFFSET, 7205 }, { 0x3133, G_UNICODE_NOT_PRESENT_OFFSET, 7209 }, { 0x3134, G_UNICODE_NOT_PRESENT_OFFSET, 7213 }, { 0x3135, G_UNICODE_NOT_PRESENT_OFFSET, 7217 }, { 0x3136, G_UNICODE_NOT_PRESENT_OFFSET, 7221 }, { 0x3137, G_UNICODE_NOT_PRESENT_OFFSET, 7225 }, { 0x3138, G_UNICODE_NOT_PRESENT_OFFSET, 7229 }, { 0x3139, G_UNICODE_NOT_PRESENT_OFFSET, 7233 }, { 0x313a, G_UNICODE_NOT_PRESENT_OFFSET, 7237 }, { 0x313b, G_UNICODE_NOT_PRESENT_OFFSET, 7241 }, { 0x313c, G_UNICODE_NOT_PRESENT_OFFSET, 7245 }, { 0x313d, G_UNICODE_NOT_PRESENT_OFFSET, 7249 }, { 0x313e, G_UNICODE_NOT_PRESENT_OFFSET, 7253 }, { 0x313f, G_UNICODE_NOT_PRESENT_OFFSET, 7257 }, { 0x3140, G_UNICODE_NOT_PRESENT_OFFSET, 7261 }, { 0x3141, G_UNICODE_NOT_PRESENT_OFFSET, 7265 }, { 0x3142, G_UNICODE_NOT_PRESENT_OFFSET, 7269 }, { 0x3143, G_UNICODE_NOT_PRESENT_OFFSET, 7273 }, { 0x3144, G_UNICODE_NOT_PRESENT_OFFSET, 7277 }, { 0x3145, G_UNICODE_NOT_PRESENT_OFFSET, 7281 }, { 0x3146, G_UNICODE_NOT_PRESENT_OFFSET, 7285 }, { 0x3147, G_UNICODE_NOT_PRESENT_OFFSET, 7289 }, { 0x3148, G_UNICODE_NOT_PRESENT_OFFSET, 7293 }, { 0x3149, G_UNICODE_NOT_PRESENT_OFFSET, 7297 }, { 0x314a, G_UNICODE_NOT_PRESENT_OFFSET, 7301 }, { 0x314b, G_UNICODE_NOT_PRESENT_OFFSET, 7305 }, { 0x314c, G_UNICODE_NOT_PRESENT_OFFSET, 7309 }, { 0x314d, G_UNICODE_NOT_PRESENT_OFFSET, 7313 }, { 0x314e, G_UNICODE_NOT_PRESENT_OFFSET, 7317 }, { 0x314f, G_UNICODE_NOT_PRESENT_OFFSET, 7321 }, { 0x3150, G_UNICODE_NOT_PRESENT_OFFSET, 7325 }, { 0x3151, G_UNICODE_NOT_PRESENT_OFFSET, 7329 }, { 0x3152, G_UNICODE_NOT_PRESENT_OFFSET, 7333 }, { 0x3153, G_UNICODE_NOT_PRESENT_OFFSET, 7337 }, { 0x3154, G_UNICODE_NOT_PRESENT_OFFSET, 7341 }, { 0x3155, G_UNICODE_NOT_PRESENT_OFFSET, 7345 }, { 0x3156, G_UNICODE_NOT_PRESENT_OFFSET, 7349 }, { 0x3157, G_UNICODE_NOT_PRESENT_OFFSET, 7353 }, { 0x3158, G_UNICODE_NOT_PRESENT_OFFSET, 7357 }, { 0x3159, G_UNICODE_NOT_PRESENT_OFFSET, 7361 }, { 0x315a, G_UNICODE_NOT_PRESENT_OFFSET, 7365 }, { 0x315b, G_UNICODE_NOT_PRESENT_OFFSET, 7369 }, { 0x315c, G_UNICODE_NOT_PRESENT_OFFSET, 7373 }, { 0x315d, G_UNICODE_NOT_PRESENT_OFFSET, 7377 }, { 0x315e, G_UNICODE_NOT_PRESENT_OFFSET, 7381 }, { 0x315f, G_UNICODE_NOT_PRESENT_OFFSET, 7385 }, { 0x3160, G_UNICODE_NOT_PRESENT_OFFSET, 7389 }, { 0x3161, G_UNICODE_NOT_PRESENT_OFFSET, 7393 }, { 0x3162, G_UNICODE_NOT_PRESENT_OFFSET, 7397 }, { 0x3163, G_UNICODE_NOT_PRESENT_OFFSET, 7401 }, { 0x3164, G_UNICODE_NOT_PRESENT_OFFSET, 7405 }, { 0x3165, G_UNICODE_NOT_PRESENT_OFFSET, 7409 }, { 0x3166, G_UNICODE_NOT_PRESENT_OFFSET, 7413 }, { 0x3167, G_UNICODE_NOT_PRESENT_OFFSET, 7417 }, { 0x3168, G_UNICODE_NOT_PRESENT_OFFSET, 7421 }, { 0x3169, G_UNICODE_NOT_PRESENT_OFFSET, 7425 }, { 0x316a, G_UNICODE_NOT_PRESENT_OFFSET, 7429 }, { 0x316b, G_UNICODE_NOT_PRESENT_OFFSET, 7433 }, { 0x316c, G_UNICODE_NOT_PRESENT_OFFSET, 7437 }, { 0x316d, G_UNICODE_NOT_PRESENT_OFFSET, 7441 }, { 0x316e, G_UNICODE_NOT_PRESENT_OFFSET, 7445 }, { 0x316f, G_UNICODE_NOT_PRESENT_OFFSET, 7449 }, { 0x3170, G_UNICODE_NOT_PRESENT_OFFSET, 7453 }, { 0x3171, G_UNICODE_NOT_PRESENT_OFFSET, 7457 }, { 0x3172, G_UNICODE_NOT_PRESENT_OFFSET, 7461 }, { 0x3173, G_UNICODE_NOT_PRESENT_OFFSET, 7465 }, { 0x3174, G_UNICODE_NOT_PRESENT_OFFSET, 7469 }, { 0x3175, G_UNICODE_NOT_PRESENT_OFFSET, 7473 }, { 0x3176, G_UNICODE_NOT_PRESENT_OFFSET, 7477 }, { 0x3177, G_UNICODE_NOT_PRESENT_OFFSET, 7481 }, { 0x3178, G_UNICODE_NOT_PRESENT_OFFSET, 7485 }, { 0x3179, G_UNICODE_NOT_PRESENT_OFFSET, 7489 }, { 0x317a, G_UNICODE_NOT_PRESENT_OFFSET, 7493 }, { 0x317b, G_UNICODE_NOT_PRESENT_OFFSET, 7497 }, { 0x317c, G_UNICODE_NOT_PRESENT_OFFSET, 7501 }, { 0x317d, G_UNICODE_NOT_PRESENT_OFFSET, 7505 }, { 0x317e, G_UNICODE_NOT_PRESENT_OFFSET, 7509 }, { 0x317f, G_UNICODE_NOT_PRESENT_OFFSET, 7513 }, { 0x3180, G_UNICODE_NOT_PRESENT_OFFSET, 7517 }, { 0x3181, G_UNICODE_NOT_PRESENT_OFFSET, 7521 }, { 0x3182, G_UNICODE_NOT_PRESENT_OFFSET, 7525 }, { 0x3183, G_UNICODE_NOT_PRESENT_OFFSET, 7529 }, { 0x3184, G_UNICODE_NOT_PRESENT_OFFSET, 7533 }, { 0x3185, G_UNICODE_NOT_PRESENT_OFFSET, 7537 }, { 0x3186, G_UNICODE_NOT_PRESENT_OFFSET, 7541 }, { 0x3187, G_UNICODE_NOT_PRESENT_OFFSET, 7545 }, { 0x3188, G_UNICODE_NOT_PRESENT_OFFSET, 7549 }, { 0x3189, G_UNICODE_NOT_PRESENT_OFFSET, 7553 }, { 0x318a, G_UNICODE_NOT_PRESENT_OFFSET, 7557 }, { 0x318b, G_UNICODE_NOT_PRESENT_OFFSET, 7561 }, { 0x318c, G_UNICODE_NOT_PRESENT_OFFSET, 7565 }, { 0x318d, G_UNICODE_NOT_PRESENT_OFFSET, 7569 }, { 0x318e, G_UNICODE_NOT_PRESENT_OFFSET, 7573 }, { 0x3192, G_UNICODE_NOT_PRESENT_OFFSET, 5903 }, { 0x3193, G_UNICODE_NOT_PRESENT_OFFSET, 5927 }, { 0x3194, G_UNICODE_NOT_PRESENT_OFFSET, 7577 }, { 0x3195, G_UNICODE_NOT_PRESENT_OFFSET, 7581 }, { 0x3196, G_UNICODE_NOT_PRESENT_OFFSET, 7585 }, { 0x3197, G_UNICODE_NOT_PRESENT_OFFSET, 7589 }, { 0x3198, G_UNICODE_NOT_PRESENT_OFFSET, 7593 }, { 0x3199, G_UNICODE_NOT_PRESENT_OFFSET, 7597 }, { 0x319a, G_UNICODE_NOT_PRESENT_OFFSET, 5919 }, { 0x319b, G_UNICODE_NOT_PRESENT_OFFSET, 7601 }, { 0x319c, G_UNICODE_NOT_PRESENT_OFFSET, 7605 }, { 0x319d, G_UNICODE_NOT_PRESENT_OFFSET, 7609 }, { 0x319e, G_UNICODE_NOT_PRESENT_OFFSET, 7613 }, { 0x319f, G_UNICODE_NOT_PRESENT_OFFSET, 5935 }, { 0x3200, G_UNICODE_NOT_PRESENT_OFFSET, 7617 }, { 0x3201, G_UNICODE_NOT_PRESENT_OFFSET, 7623 }, { 0x3202, G_UNICODE_NOT_PRESENT_OFFSET, 7629 }, { 0x3203, G_UNICODE_NOT_PRESENT_OFFSET, 7635 }, { 0x3204, G_UNICODE_NOT_PRESENT_OFFSET, 7641 }, { 0x3205, G_UNICODE_NOT_PRESENT_OFFSET, 7647 }, { 0x3206, G_UNICODE_NOT_PRESENT_OFFSET, 7653 }, { 0x3207, G_UNICODE_NOT_PRESENT_OFFSET, 7659 }, { 0x3208, G_UNICODE_NOT_PRESENT_OFFSET, 7665 }, { 0x3209, G_UNICODE_NOT_PRESENT_OFFSET, 7671 }, { 0x320a, G_UNICODE_NOT_PRESENT_OFFSET, 7677 }, { 0x320b, G_UNICODE_NOT_PRESENT_OFFSET, 7683 }, { 0x320c, G_UNICODE_NOT_PRESENT_OFFSET, 7689 }, { 0x320d, G_UNICODE_NOT_PRESENT_OFFSET, 7695 }, { 0x320e, G_UNICODE_NOT_PRESENT_OFFSET, 7701 }, { 0x320f, G_UNICODE_NOT_PRESENT_OFFSET, 7710 }, { 0x3210, G_UNICODE_NOT_PRESENT_OFFSET, 7719 }, { 0x3211, G_UNICODE_NOT_PRESENT_OFFSET, 7728 }, { 0x3212, G_UNICODE_NOT_PRESENT_OFFSET, 7737 }, { 0x3213, G_UNICODE_NOT_PRESENT_OFFSET, 7746 }, { 0x3214, G_UNICODE_NOT_PRESENT_OFFSET, 7755 }, { 0x3215, G_UNICODE_NOT_PRESENT_OFFSET, 7764 }, { 0x3216, G_UNICODE_NOT_PRESENT_OFFSET, 7773 }, { 0x3217, G_UNICODE_NOT_PRESENT_OFFSET, 7782 }, { 0x3218, G_UNICODE_NOT_PRESENT_OFFSET, 7791 }, { 0x3219, G_UNICODE_NOT_PRESENT_OFFSET, 7800 }, { 0x321a, G_UNICODE_NOT_PRESENT_OFFSET, 7809 }, { 0x321b, G_UNICODE_NOT_PRESENT_OFFSET, 7818 }, { 0x321c, G_UNICODE_NOT_PRESENT_OFFSET, 7827 }, { 0x3220, G_UNICODE_NOT_PRESENT_OFFSET, 7836 }, { 0x3221, G_UNICODE_NOT_PRESENT_OFFSET, 7842 }, { 0x3222, G_UNICODE_NOT_PRESENT_OFFSET, 7848 }, { 0x3223, G_UNICODE_NOT_PRESENT_OFFSET, 7854 }, { 0x3224, G_UNICODE_NOT_PRESENT_OFFSET, 7860 }, { 0x3225, G_UNICODE_NOT_PRESENT_OFFSET, 7866 }, { 0x3226, G_UNICODE_NOT_PRESENT_OFFSET, 7872 }, { 0x3227, G_UNICODE_NOT_PRESENT_OFFSET, 7878 }, { 0x3228, G_UNICODE_NOT_PRESENT_OFFSET, 7884 }, { 0x3229, G_UNICODE_NOT_PRESENT_OFFSET, 7890 }, { 0x322a, G_UNICODE_NOT_PRESENT_OFFSET, 7896 }, { 0x322b, G_UNICODE_NOT_PRESENT_OFFSET, 7902 }, { 0x322c, G_UNICODE_NOT_PRESENT_OFFSET, 7908 }, { 0x322d, G_UNICODE_NOT_PRESENT_OFFSET, 7914 }, { 0x322e, G_UNICODE_NOT_PRESENT_OFFSET, 7920 }, { 0x322f, G_UNICODE_NOT_PRESENT_OFFSET, 7926 }, { 0x3230, G_UNICODE_NOT_PRESENT_OFFSET, 7932 }, { 0x3231, G_UNICODE_NOT_PRESENT_OFFSET, 7938 }, { 0x3232, G_UNICODE_NOT_PRESENT_OFFSET, 7944 }, { 0x3233, G_UNICODE_NOT_PRESENT_OFFSET, 7950 }, { 0x3234, G_UNICODE_NOT_PRESENT_OFFSET, 7956 }, { 0x3235, G_UNICODE_NOT_PRESENT_OFFSET, 7962 }, { 0x3236, G_UNICODE_NOT_PRESENT_OFFSET, 7968 }, { 0x3237, G_UNICODE_NOT_PRESENT_OFFSET, 7974 }, { 0x3238, G_UNICODE_NOT_PRESENT_OFFSET, 7980 }, { 0x3239, G_UNICODE_NOT_PRESENT_OFFSET, 7986 }, { 0x323a, G_UNICODE_NOT_PRESENT_OFFSET, 7992 }, { 0x323b, G_UNICODE_NOT_PRESENT_OFFSET, 7998 }, { 0x323c, G_UNICODE_NOT_PRESENT_OFFSET, 8004 }, { 0x323d, G_UNICODE_NOT_PRESENT_OFFSET, 8010 }, { 0x323e, G_UNICODE_NOT_PRESENT_OFFSET, 8016 }, { 0x323f, G_UNICODE_NOT_PRESENT_OFFSET, 8022 }, { 0x3240, G_UNICODE_NOT_PRESENT_OFFSET, 8028 }, { 0x3241, G_UNICODE_NOT_PRESENT_OFFSET, 8034 }, { 0x3242, G_UNICODE_NOT_PRESENT_OFFSET, 8040 }, { 0x3243, G_UNICODE_NOT_PRESENT_OFFSET, 8046 }, { 0x3251, G_UNICODE_NOT_PRESENT_OFFSET, 8052 }, { 0x3252, G_UNICODE_NOT_PRESENT_OFFSET, 8055 }, { 0x3253, G_UNICODE_NOT_PRESENT_OFFSET, 8058 }, { 0x3254, G_UNICODE_NOT_PRESENT_OFFSET, 8061 }, { 0x3255, G_UNICODE_NOT_PRESENT_OFFSET, 8064 }, { 0x3256, G_UNICODE_NOT_PRESENT_OFFSET, 8067 }, { 0x3257, G_UNICODE_NOT_PRESENT_OFFSET, 8070 }, { 0x3258, G_UNICODE_NOT_PRESENT_OFFSET, 8073 }, { 0x3259, G_UNICODE_NOT_PRESENT_OFFSET, 8076 }, { 0x325a, G_UNICODE_NOT_PRESENT_OFFSET, 8079 }, { 0x325b, G_UNICODE_NOT_PRESENT_OFFSET, 8082 }, { 0x325c, G_UNICODE_NOT_PRESENT_OFFSET, 8085 }, { 0x325d, G_UNICODE_NOT_PRESENT_OFFSET, 8088 }, { 0x325e, G_UNICODE_NOT_PRESENT_OFFSET, 8091 }, { 0x325f, G_UNICODE_NOT_PRESENT_OFFSET, 8094 }, { 0x3260, G_UNICODE_NOT_PRESENT_OFFSET, 7201 }, { 0x3261, G_UNICODE_NOT_PRESENT_OFFSET, 7213 }, { 0x3262, G_UNICODE_NOT_PRESENT_OFFSET, 7225 }, { 0x3263, G_UNICODE_NOT_PRESENT_OFFSET, 7233 }, { 0x3264, G_UNICODE_NOT_PRESENT_OFFSET, 7265 }, { 0x3265, G_UNICODE_NOT_PRESENT_OFFSET, 7269 }, { 0x3266, G_UNICODE_NOT_PRESENT_OFFSET, 7281 }, { 0x3267, G_UNICODE_NOT_PRESENT_OFFSET, 7289 }, { 0x3268, G_UNICODE_NOT_PRESENT_OFFSET, 7293 }, { 0x3269, G_UNICODE_NOT_PRESENT_OFFSET, 7301 }, { 0x326a, G_UNICODE_NOT_PRESENT_OFFSET, 7305 }, { 0x326b, G_UNICODE_NOT_PRESENT_OFFSET, 7309 }, { 0x326c, G_UNICODE_NOT_PRESENT_OFFSET, 7313 }, { 0x326d, G_UNICODE_NOT_PRESENT_OFFSET, 7317 }, { 0x326e, G_UNICODE_NOT_PRESENT_OFFSET, 8097 }, { 0x326f, G_UNICODE_NOT_PRESENT_OFFSET, 8104 }, { 0x3270, G_UNICODE_NOT_PRESENT_OFFSET, 8111 }, { 0x3271, G_UNICODE_NOT_PRESENT_OFFSET, 8118 }, { 0x3272, G_UNICODE_NOT_PRESENT_OFFSET, 8125 }, { 0x3273, G_UNICODE_NOT_PRESENT_OFFSET, 8132 }, { 0x3274, G_UNICODE_NOT_PRESENT_OFFSET, 8139 }, { 0x3275, G_UNICODE_NOT_PRESENT_OFFSET, 8146 }, { 0x3276, G_UNICODE_NOT_PRESENT_OFFSET, 8153 }, { 0x3277, G_UNICODE_NOT_PRESENT_OFFSET, 8160 }, { 0x3278, G_UNICODE_NOT_PRESENT_OFFSET, 8167 }, { 0x3279, G_UNICODE_NOT_PRESENT_OFFSET, 8174 }, { 0x327a, G_UNICODE_NOT_PRESENT_OFFSET, 8181 }, { 0x327b, G_UNICODE_NOT_PRESENT_OFFSET, 8188 }, { 0x3280, G_UNICODE_NOT_PRESENT_OFFSET, 5903 }, { 0x3281, G_UNICODE_NOT_PRESENT_OFFSET, 5927 }, { 0x3282, G_UNICODE_NOT_PRESENT_OFFSET, 7577 }, { 0x3283, G_UNICODE_NOT_PRESENT_OFFSET, 7581 }, { 0x3284, G_UNICODE_NOT_PRESENT_OFFSET, 8195 }, { 0x3285, G_UNICODE_NOT_PRESENT_OFFSET, 8199 }, { 0x3286, G_UNICODE_NOT_PRESENT_OFFSET, 8203 }, { 0x3287, G_UNICODE_NOT_PRESENT_OFFSET, 5947 }, { 0x3288, G_UNICODE_NOT_PRESENT_OFFSET, 8207 }, { 0x3289, G_UNICODE_NOT_PRESENT_OFFSET, 5995 }, { 0x328a, G_UNICODE_NOT_PRESENT_OFFSET, 6195 }, { 0x328b, G_UNICODE_NOT_PRESENT_OFFSET, 6243 }, { 0x328c, G_UNICODE_NOT_PRESENT_OFFSET, 6239 }, { 0x328d, G_UNICODE_NOT_PRESENT_OFFSET, 6199 }, { 0x328e, G_UNICODE_NOT_PRESENT_OFFSET, 6567 }, { 0x328f, G_UNICODE_NOT_PRESENT_OFFSET, 6027 }, { 0x3290, G_UNICODE_NOT_PRESENT_OFFSET, 6187 }, { 0x3291, G_UNICODE_NOT_PRESENT_OFFSET, 8211 }, { 0x3292, G_UNICODE_NOT_PRESENT_OFFSET, 8215 }, { 0x3293, G_UNICODE_NOT_PRESENT_OFFSET, 8219 }, { 0x3294, G_UNICODE_NOT_PRESENT_OFFSET, 8223 }, { 0x3295, G_UNICODE_NOT_PRESENT_OFFSET, 8227 }, { 0x3296, G_UNICODE_NOT_PRESENT_OFFSET, 8231 }, { 0x3297, G_UNICODE_NOT_PRESENT_OFFSET, 8235 }, { 0x3298, G_UNICODE_NOT_PRESENT_OFFSET, 8239 }, { 0x3299, G_UNICODE_NOT_PRESENT_OFFSET, 8243 }, { 0x329a, G_UNICODE_NOT_PRESENT_OFFSET, 8247 }, { 0x329b, G_UNICODE_NOT_PRESENT_OFFSET, 6051 }, { 0x329c, G_UNICODE_NOT_PRESENT_OFFSET, 8251 }, { 0x329d, G_UNICODE_NOT_PRESENT_OFFSET, 8255 }, { 0x329e, G_UNICODE_NOT_PRESENT_OFFSET, 8259 }, { 0x329f, G_UNICODE_NOT_PRESENT_OFFSET, 8263 }, { 0x32a0, G_UNICODE_NOT_PRESENT_OFFSET, 8267 }, { 0x32a1, G_UNICODE_NOT_PRESENT_OFFSET, 8271 }, { 0x32a2, G_UNICODE_NOT_PRESENT_OFFSET, 8275 }, { 0x32a3, G_UNICODE_NOT_PRESENT_OFFSET, 8279 }, { 0x32a4, G_UNICODE_NOT_PRESENT_OFFSET, 7585 }, { 0x32a5, G_UNICODE_NOT_PRESENT_OFFSET, 7589 }, { 0x32a6, G_UNICODE_NOT_PRESENT_OFFSET, 7593 }, { 0x32a7, G_UNICODE_NOT_PRESENT_OFFSET, 8283 }, { 0x32a8, G_UNICODE_NOT_PRESENT_OFFSET, 8287 }, { 0x32a9, G_UNICODE_NOT_PRESENT_OFFSET, 8291 }, { 0x32aa, G_UNICODE_NOT_PRESENT_OFFSET, 8295 }, { 0x32ab, G_UNICODE_NOT_PRESENT_OFFSET, 8299 }, { 0x32ac, G_UNICODE_NOT_PRESENT_OFFSET, 8303 }, { 0x32ad, G_UNICODE_NOT_PRESENT_OFFSET, 8307 }, { 0x32ae, G_UNICODE_NOT_PRESENT_OFFSET, 8311 }, { 0x32af, G_UNICODE_NOT_PRESENT_OFFSET, 8315 }, { 0x32b0, G_UNICODE_NOT_PRESENT_OFFSET, 8319 }, { 0x32b1, G_UNICODE_NOT_PRESENT_OFFSET, 8323 }, { 0x32b2, G_UNICODE_NOT_PRESENT_OFFSET, 8326 }, { 0x32b3, G_UNICODE_NOT_PRESENT_OFFSET, 8329 }, { 0x32b4, G_UNICODE_NOT_PRESENT_OFFSET, 8332 }, { 0x32b5, G_UNICODE_NOT_PRESENT_OFFSET, 8335 }, { 0x32b6, G_UNICODE_NOT_PRESENT_OFFSET, 8338 }, { 0x32b7, G_UNICODE_NOT_PRESENT_OFFSET, 8341 }, { 0x32b8, G_UNICODE_NOT_PRESENT_OFFSET, 8344 }, { 0x32b9, G_UNICODE_NOT_PRESENT_OFFSET, 8347 }, { 0x32ba, G_UNICODE_NOT_PRESENT_OFFSET, 8350 }, { 0x32bb, G_UNICODE_NOT_PRESENT_OFFSET, 8353 }, { 0x32bc, G_UNICODE_NOT_PRESENT_OFFSET, 8356 }, { 0x32bd, G_UNICODE_NOT_PRESENT_OFFSET, 8359 }, { 0x32be, G_UNICODE_NOT_PRESENT_OFFSET, 8362 }, { 0x32bf, G_UNICODE_NOT_PRESENT_OFFSET, 8365 }, { 0x32c0, G_UNICODE_NOT_PRESENT_OFFSET, 8368 }, { 0x32c1, G_UNICODE_NOT_PRESENT_OFFSET, 8373 }, { 0x32c2, G_UNICODE_NOT_PRESENT_OFFSET, 8378 }, { 0x32c3, G_UNICODE_NOT_PRESENT_OFFSET, 8383 }, { 0x32c4, G_UNICODE_NOT_PRESENT_OFFSET, 8388 }, { 0x32c5, G_UNICODE_NOT_PRESENT_OFFSET, 8393 }, { 0x32c6, G_UNICODE_NOT_PRESENT_OFFSET, 8398 }, { 0x32c7, G_UNICODE_NOT_PRESENT_OFFSET, 8403 }, { 0x32c8, G_UNICODE_NOT_PRESENT_OFFSET, 8408 }, { 0x32c9, G_UNICODE_NOT_PRESENT_OFFSET, 8413 }, { 0x32ca, G_UNICODE_NOT_PRESENT_OFFSET, 8419 }, { 0x32cb, G_UNICODE_NOT_PRESENT_OFFSET, 8425 }, { 0x32d0, G_UNICODE_NOT_PRESENT_OFFSET, 8431 }, { 0x32d1, G_UNICODE_NOT_PRESENT_OFFSET, 8435 }, { 0x32d2, G_UNICODE_NOT_PRESENT_OFFSET, 8439 }, { 0x32d3, G_UNICODE_NOT_PRESENT_OFFSET, 8443 }, { 0x32d4, G_UNICODE_NOT_PRESENT_OFFSET, 8447 }, { 0x32d5, G_UNICODE_NOT_PRESENT_OFFSET, 8451 }, { 0x32d6, G_UNICODE_NOT_PRESENT_OFFSET, 8455 }, { 0x32d7, G_UNICODE_NOT_PRESENT_OFFSET, 8459 }, { 0x32d8, G_UNICODE_NOT_PRESENT_OFFSET, 8463 }, { 0x32d9, G_UNICODE_NOT_PRESENT_OFFSET, 8467 }, { 0x32da, G_UNICODE_NOT_PRESENT_OFFSET, 8471 }, { 0x32db, G_UNICODE_NOT_PRESENT_OFFSET, 8475 }, { 0x32dc, G_UNICODE_NOT_PRESENT_OFFSET, 8479 }, { 0x32dd, G_UNICODE_NOT_PRESENT_OFFSET, 8483 }, { 0x32de, G_UNICODE_NOT_PRESENT_OFFSET, 8487 }, { 0x32df, G_UNICODE_NOT_PRESENT_OFFSET, 8491 }, { 0x32e0, G_UNICODE_NOT_PRESENT_OFFSET, 8495 }, { 0x32e1, G_UNICODE_NOT_PRESENT_OFFSET, 8499 }, { 0x32e2, G_UNICODE_NOT_PRESENT_OFFSET, 8503 }, { 0x32e3, G_UNICODE_NOT_PRESENT_OFFSET, 8507 }, { 0x32e4, G_UNICODE_NOT_PRESENT_OFFSET, 8511 }, { 0x32e5, G_UNICODE_NOT_PRESENT_OFFSET, 8515 }, { 0x32e6, G_UNICODE_NOT_PRESENT_OFFSET, 8519 }, { 0x32e7, G_UNICODE_NOT_PRESENT_OFFSET, 8523 }, { 0x32e8, G_UNICODE_NOT_PRESENT_OFFSET, 8527 }, { 0x32e9, G_UNICODE_NOT_PRESENT_OFFSET, 8531 }, { 0x32ea, G_UNICODE_NOT_PRESENT_OFFSET, 8535 }, { 0x32eb, G_UNICODE_NOT_PRESENT_OFFSET, 8539 }, { 0x32ec, G_UNICODE_NOT_PRESENT_OFFSET, 8543 }, { 0x32ed, G_UNICODE_NOT_PRESENT_OFFSET, 8547 }, { 0x32ee, G_UNICODE_NOT_PRESENT_OFFSET, 8551 }, { 0x32ef, G_UNICODE_NOT_PRESENT_OFFSET, 8555 }, { 0x32f0, G_UNICODE_NOT_PRESENT_OFFSET, 8559 }, { 0x32f1, G_UNICODE_NOT_PRESENT_OFFSET, 8563 }, { 0x32f2, G_UNICODE_NOT_PRESENT_OFFSET, 8567 }, { 0x32f3, G_UNICODE_NOT_PRESENT_OFFSET, 8571 }, { 0x32f4, G_UNICODE_NOT_PRESENT_OFFSET, 8575 }, { 0x32f5, G_UNICODE_NOT_PRESENT_OFFSET, 8579 }, { 0x32f6, G_UNICODE_NOT_PRESENT_OFFSET, 8583 }, { 0x32f7, G_UNICODE_NOT_PRESENT_OFFSET, 8587 }, { 0x32f8, G_UNICODE_NOT_PRESENT_OFFSET, 8591 }, { 0x32f9, G_UNICODE_NOT_PRESENT_OFFSET, 8595 }, { 0x32fa, G_UNICODE_NOT_PRESENT_OFFSET, 8599 }, { 0x32fb, G_UNICODE_NOT_PRESENT_OFFSET, 8603 }, { 0x32fc, G_UNICODE_NOT_PRESENT_OFFSET, 8607 }, { 0x32fd, G_UNICODE_NOT_PRESENT_OFFSET, 8611 }, { 0x32fe, G_UNICODE_NOT_PRESENT_OFFSET, 8615 }, { 0x3300, G_UNICODE_NOT_PRESENT_OFFSET, 8619 }, { 0x3301, G_UNICODE_NOT_PRESENT_OFFSET, 8635 }, { 0x3302, G_UNICODE_NOT_PRESENT_OFFSET, 8648 }, { 0x3303, G_UNICODE_NOT_PRESENT_OFFSET, 8664 }, { 0x3304, G_UNICODE_NOT_PRESENT_OFFSET, 8674 }, { 0x3305, G_UNICODE_NOT_PRESENT_OFFSET, 8690 }, { 0x3306, G_UNICODE_NOT_PRESENT_OFFSET, 8700 }, { 0x3307, G_UNICODE_NOT_PRESENT_OFFSET, 8710 }, { 0x3308, G_UNICODE_NOT_PRESENT_OFFSET, 8729 }, { 0x3309, G_UNICODE_NOT_PRESENT_OFFSET, 8742 }, { 0x330a, G_UNICODE_NOT_PRESENT_OFFSET, 8752 }, { 0x330b, G_UNICODE_NOT_PRESENT_OFFSET, 8762 }, { 0x330c, G_UNICODE_NOT_PRESENT_OFFSET, 8772 }, { 0x330d, G_UNICODE_NOT_PRESENT_OFFSET, 8785 }, { 0x330e, G_UNICODE_NOT_PRESENT_OFFSET, 8798 }, { 0x330f, G_UNICODE_NOT_PRESENT_OFFSET, 8811 }, { 0x3310, G_UNICODE_NOT_PRESENT_OFFSET, 8824 }, { 0x3311, G_UNICODE_NOT_PRESENT_OFFSET, 8837 }, { 0x3312, G_UNICODE_NOT_PRESENT_OFFSET, 8850 }, { 0x3313, G_UNICODE_NOT_PRESENT_OFFSET, 8863 }, { 0x3314, G_UNICODE_NOT_PRESENT_OFFSET, 8882 }, { 0x3315, G_UNICODE_NOT_PRESENT_OFFSET, 8889 }, { 0x3316, G_UNICODE_NOT_PRESENT_OFFSET, 8908 }, { 0x3317, G_UNICODE_NOT_PRESENT_OFFSET, 8927 }, { 0x3318, G_UNICODE_NOT_PRESENT_OFFSET, 8943 }, { 0x3319, G_UNICODE_NOT_PRESENT_OFFSET, 8956 }, { 0x331a, G_UNICODE_NOT_PRESENT_OFFSET, 8975 }, { 0x331b, G_UNICODE_NOT_PRESENT_OFFSET, 8994 }, { 0x331c, G_UNICODE_NOT_PRESENT_OFFSET, 9007 }, { 0x331d, G_UNICODE_NOT_PRESENT_OFFSET, 9017 }, { 0x331e, G_UNICODE_NOT_PRESENT_OFFSET, 9027 }, { 0x331f, G_UNICODE_NOT_PRESENT_OFFSET, 9040 }, { 0x3320, G_UNICODE_NOT_PRESENT_OFFSET, 9053 }, { 0x3321, G_UNICODE_NOT_PRESENT_OFFSET, 9069 }, { 0x3322, G_UNICODE_NOT_PRESENT_OFFSET, 9085 }, { 0x3323, G_UNICODE_NOT_PRESENT_OFFSET, 9095 }, { 0x3324, G_UNICODE_NOT_PRESENT_OFFSET, 9105 }, { 0x3325, G_UNICODE_NOT_PRESENT_OFFSET, 9118 }, { 0x3326, G_UNICODE_NOT_PRESENT_OFFSET, 9128 }, { 0x3327, G_UNICODE_NOT_PRESENT_OFFSET, 9138 }, { 0x3328, G_UNICODE_NOT_PRESENT_OFFSET, 9145 }, { 0x3329, G_UNICODE_NOT_PRESENT_OFFSET, 9152 }, { 0x332a, G_UNICODE_NOT_PRESENT_OFFSET, 9162 }, { 0x332b, G_UNICODE_NOT_PRESENT_OFFSET, 9172 }, { 0x332c, G_UNICODE_NOT_PRESENT_OFFSET, 9191 }, { 0x332d, G_UNICODE_NOT_PRESENT_OFFSET, 9204 }, { 0x332e, G_UNICODE_NOT_PRESENT_OFFSET, 9220 }, { 0x332f, G_UNICODE_NOT_PRESENT_OFFSET, 9239 }, { 0x3330, G_UNICODE_NOT_PRESENT_OFFSET, 9252 }, { 0x3331, G_UNICODE_NOT_PRESENT_OFFSET, 9262 }, { 0x3332, G_UNICODE_NOT_PRESENT_OFFSET, 9272 }, { 0x3333, G_UNICODE_NOT_PRESENT_OFFSET, 9291 }, { 0x3334, G_UNICODE_NOT_PRESENT_OFFSET, 9304 }, { 0x3335, G_UNICODE_NOT_PRESENT_OFFSET, 9323 }, { 0x3336, G_UNICODE_NOT_PRESENT_OFFSET, 9333 }, { 0x3337, G_UNICODE_NOT_PRESENT_OFFSET, 9349 }, { 0x3338, G_UNICODE_NOT_PRESENT_OFFSET, 9359 }, { 0x3339, G_UNICODE_NOT_PRESENT_OFFSET, 9372 }, { 0x333a, G_UNICODE_NOT_PRESENT_OFFSET, 9382 }, { 0x333b, G_UNICODE_NOT_PRESENT_OFFSET, 9395 }, { 0x333c, G_UNICODE_NOT_PRESENT_OFFSET, 9411 }, { 0x333d, G_UNICODE_NOT_PRESENT_OFFSET, 9424 }, { 0x333e, G_UNICODE_NOT_PRESENT_OFFSET, 9440 }, { 0x333f, G_UNICODE_NOT_PRESENT_OFFSET, 9453 }, { 0x3340, G_UNICODE_NOT_PRESENT_OFFSET, 9460 }, { 0x3341, G_UNICODE_NOT_PRESENT_OFFSET, 9476 }, { 0x3342, G_UNICODE_NOT_PRESENT_OFFSET, 9486 }, { 0x3343, G_UNICODE_NOT_PRESENT_OFFSET, 9496 }, { 0x3344, G_UNICODE_NOT_PRESENT_OFFSET, 9509 }, { 0x3345, G_UNICODE_NOT_PRESENT_OFFSET, 9519 }, { 0x3346, G_UNICODE_NOT_PRESENT_OFFSET, 9529 }, { 0x3347, G_UNICODE_NOT_PRESENT_OFFSET, 9539 }, { 0x3348, G_UNICODE_NOT_PRESENT_OFFSET, 9555 }, { 0x3349, G_UNICODE_NOT_PRESENT_OFFSET, 9568 }, { 0x334a, G_UNICODE_NOT_PRESENT_OFFSET, 9575 }, { 0x334b, G_UNICODE_NOT_PRESENT_OFFSET, 9594 }, { 0x334c, G_UNICODE_NOT_PRESENT_OFFSET, 9604 }, { 0x334d, G_UNICODE_NOT_PRESENT_OFFSET, 9620 }, { 0x334e, G_UNICODE_NOT_PRESENT_OFFSET, 9633 }, { 0x334f, G_UNICODE_NOT_PRESENT_OFFSET, 9646 }, { 0x3350, G_UNICODE_NOT_PRESENT_OFFSET, 9656 }, { 0x3351, G_UNICODE_NOT_PRESENT_OFFSET, 9666 }, { 0x3352, G_UNICODE_NOT_PRESENT_OFFSET, 9679 }, { 0x3353, G_UNICODE_NOT_PRESENT_OFFSET, 9686 }, { 0x3354, G_UNICODE_NOT_PRESENT_OFFSET, 9699 }, { 0x3355, G_UNICODE_NOT_PRESENT_OFFSET, 9715 }, { 0x3356, G_UNICODE_NOT_PRESENT_OFFSET, 9722 }, { 0x3357, G_UNICODE_NOT_PRESENT_OFFSET, 9741 }, { 0x3358, G_UNICODE_NOT_PRESENT_OFFSET, 9751 }, { 0x3359, G_UNICODE_NOT_PRESENT_OFFSET, 9756 }, { 0x335a, G_UNICODE_NOT_PRESENT_OFFSET, 9761 }, { 0x335b, G_UNICODE_NOT_PRESENT_OFFSET, 9766 }, { 0x335c, G_UNICODE_NOT_PRESENT_OFFSET, 9771 }, { 0x335d, G_UNICODE_NOT_PRESENT_OFFSET, 9776 }, { 0x335e, G_UNICODE_NOT_PRESENT_OFFSET, 9781 }, { 0x335f, G_UNICODE_NOT_PRESENT_OFFSET, 9786 }, { 0x3360, G_UNICODE_NOT_PRESENT_OFFSET, 9791 }, { 0x3361, G_UNICODE_NOT_PRESENT_OFFSET, 9796 }, { 0x3362, G_UNICODE_NOT_PRESENT_OFFSET, 9801 }, { 0x3363, G_UNICODE_NOT_PRESENT_OFFSET, 9807 }, { 0x3364, G_UNICODE_NOT_PRESENT_OFFSET, 9813 }, { 0x3365, G_UNICODE_NOT_PRESENT_OFFSET, 9819 }, { 0x3366, G_UNICODE_NOT_PRESENT_OFFSET, 9825 }, { 0x3367, G_UNICODE_NOT_PRESENT_OFFSET, 9831 }, { 0x3368, G_UNICODE_NOT_PRESENT_OFFSET, 9837 }, { 0x3369, G_UNICODE_NOT_PRESENT_OFFSET, 9843 }, { 0x336a, G_UNICODE_NOT_PRESENT_OFFSET, 9849 }, { 0x336b, G_UNICODE_NOT_PRESENT_OFFSET, 9855 }, { 0x336c, G_UNICODE_NOT_PRESENT_OFFSET, 9861 }, { 0x336d, G_UNICODE_NOT_PRESENT_OFFSET, 9867 }, { 0x336e, G_UNICODE_NOT_PRESENT_OFFSET, 9873 }, { 0x336f, G_UNICODE_NOT_PRESENT_OFFSET, 9879 }, { 0x3370, G_UNICODE_NOT_PRESENT_OFFSET, 9885 }, { 0x3371, G_UNICODE_NOT_PRESENT_OFFSET, 9891 }, { 0x3372, G_UNICODE_NOT_PRESENT_OFFSET, 9895 }, { 0x3373, G_UNICODE_NOT_PRESENT_OFFSET, 9898 }, { 0x3374, G_UNICODE_NOT_PRESENT_OFFSET, 9901 }, { 0x3375, G_UNICODE_NOT_PRESENT_OFFSET, 9905 }, { 0x3376, G_UNICODE_NOT_PRESENT_OFFSET, 9908 }, { 0x337b, G_UNICODE_NOT_PRESENT_OFFSET, 9911 }, { 0x337c, G_UNICODE_NOT_PRESENT_OFFSET, 9918 }, { 0x337d, G_UNICODE_NOT_PRESENT_OFFSET, 9925 }, { 0x337e, G_UNICODE_NOT_PRESENT_OFFSET, 9932 }, { 0x337f, G_UNICODE_NOT_PRESENT_OFFSET, 9939 }, { 0x3380, G_UNICODE_NOT_PRESENT_OFFSET, 9952 }, { 0x3381, G_UNICODE_NOT_PRESENT_OFFSET, 9955 }, { 0x3382, G_UNICODE_NOT_PRESENT_OFFSET, 9958 }, { 0x3383, G_UNICODE_NOT_PRESENT_OFFSET, 9962 }, { 0x3384, G_UNICODE_NOT_PRESENT_OFFSET, 9965 }, { 0x3385, G_UNICODE_NOT_PRESENT_OFFSET, 9968 }, { 0x3386, G_UNICODE_NOT_PRESENT_OFFSET, 9971 }, { 0x3387, G_UNICODE_NOT_PRESENT_OFFSET, 9974 }, { 0x3388, G_UNICODE_NOT_PRESENT_OFFSET, 9977 }, { 0x3389, G_UNICODE_NOT_PRESENT_OFFSET, 9981 }, { 0x338a, G_UNICODE_NOT_PRESENT_OFFSET, 9986 }, { 0x338b, G_UNICODE_NOT_PRESENT_OFFSET, 9989 }, { 0x338c, G_UNICODE_NOT_PRESENT_OFFSET, 9992 }, { 0x338d, G_UNICODE_NOT_PRESENT_OFFSET, 9996 }, { 0x338e, G_UNICODE_NOT_PRESENT_OFFSET, 10000 }, { 0x338f, G_UNICODE_NOT_PRESENT_OFFSET, 10003 }, { 0x3390, G_UNICODE_NOT_PRESENT_OFFSET, 10006 }, { 0x3391, G_UNICODE_NOT_PRESENT_OFFSET, 10009 }, { 0x3392, G_UNICODE_NOT_PRESENT_OFFSET, 10013 }, { 0x3393, G_UNICODE_NOT_PRESENT_OFFSET, 10017 }, { 0x3394, G_UNICODE_NOT_PRESENT_OFFSET, 10021 }, { 0x3395, G_UNICODE_NOT_PRESENT_OFFSET, 10025 }, { 0x3396, G_UNICODE_NOT_PRESENT_OFFSET, 10029 }, { 0x3397, G_UNICODE_NOT_PRESENT_OFFSET, 10032 }, { 0x3398, G_UNICODE_NOT_PRESENT_OFFSET, 10035 }, { 0x3399, G_UNICODE_NOT_PRESENT_OFFSET, 10038 }, { 0x339a, G_UNICODE_NOT_PRESENT_OFFSET, 10041 }, { 0x339b, G_UNICODE_NOT_PRESENT_OFFSET, 10044 }, { 0x339c, G_UNICODE_NOT_PRESENT_OFFSET, 10048 }, { 0x339d, G_UNICODE_NOT_PRESENT_OFFSET, 10051 }, { 0x339e, G_UNICODE_NOT_PRESENT_OFFSET, 10054 }, { 0x339f, G_UNICODE_NOT_PRESENT_OFFSET, 10057 }, { 0x33a0, G_UNICODE_NOT_PRESENT_OFFSET, 10061 }, { 0x33a1, G_UNICODE_NOT_PRESENT_OFFSET, 10065 }, { 0x33a2, G_UNICODE_NOT_PRESENT_OFFSET, 10068 }, { 0x33a3, G_UNICODE_NOT_PRESENT_OFFSET, 10072 }, { 0x33a4, G_UNICODE_NOT_PRESENT_OFFSET, 10076 }, { 0x33a5, G_UNICODE_NOT_PRESENT_OFFSET, 10080 }, { 0x33a6, G_UNICODE_NOT_PRESENT_OFFSET, 10083 }, { 0x33a7, G_UNICODE_NOT_PRESENT_OFFSET, 10087 }, { 0x33a8, G_UNICODE_NOT_PRESENT_OFFSET, 10093 }, { 0x33a9, G_UNICODE_NOT_PRESENT_OFFSET, 10100 }, { 0x33aa, G_UNICODE_NOT_PRESENT_OFFSET, 10103 }, { 0x33ab, G_UNICODE_NOT_PRESENT_OFFSET, 10107 }, { 0x33ac, G_UNICODE_NOT_PRESENT_OFFSET, 10111 }, { 0x33ad, G_UNICODE_NOT_PRESENT_OFFSET, 10115 }, { 0x33ae, G_UNICODE_NOT_PRESENT_OFFSET, 10119 }, { 0x33af, G_UNICODE_NOT_PRESENT_OFFSET, 10127 }, { 0x33b0, G_UNICODE_NOT_PRESENT_OFFSET, 10136 }, { 0x33b1, G_UNICODE_NOT_PRESENT_OFFSET, 10139 }, { 0x33b2, G_UNICODE_NOT_PRESENT_OFFSET, 10142 }, { 0x33b3, G_UNICODE_NOT_PRESENT_OFFSET, 10146 }, { 0x33b4, G_UNICODE_NOT_PRESENT_OFFSET, 10149 }, { 0x33b5, G_UNICODE_NOT_PRESENT_OFFSET, 10152 }, { 0x33b6, G_UNICODE_NOT_PRESENT_OFFSET, 10155 }, { 0x33b7, G_UNICODE_NOT_PRESENT_OFFSET, 10159 }, { 0x33b8, G_UNICODE_NOT_PRESENT_OFFSET, 10162 }, { 0x33b9, G_UNICODE_NOT_PRESENT_OFFSET, 10165 }, { 0x33ba, G_UNICODE_NOT_PRESENT_OFFSET, 10168 }, { 0x33bb, G_UNICODE_NOT_PRESENT_OFFSET, 10171 }, { 0x33bc, G_UNICODE_NOT_PRESENT_OFFSET, 10174 }, { 0x33bd, G_UNICODE_NOT_PRESENT_OFFSET, 10178 }, { 0x33be, G_UNICODE_NOT_PRESENT_OFFSET, 10181 }, { 0x33bf, G_UNICODE_NOT_PRESENT_OFFSET, 10184 }, { 0x33c0, G_UNICODE_NOT_PRESENT_OFFSET, 10187 }, { 0x33c1, G_UNICODE_NOT_PRESENT_OFFSET, 10191 }, { 0x33c2, G_UNICODE_NOT_PRESENT_OFFSET, 10195 }, { 0x33c3, G_UNICODE_NOT_PRESENT_OFFSET, 10200 }, { 0x33c4, G_UNICODE_NOT_PRESENT_OFFSET, 10203 }, { 0x33c5, G_UNICODE_NOT_PRESENT_OFFSET, 10206 }, { 0x33c6, G_UNICODE_NOT_PRESENT_OFFSET, 10209 }, { 0x33c7, G_UNICODE_NOT_PRESENT_OFFSET, 10216 }, { 0x33c8, G_UNICODE_NOT_PRESENT_OFFSET, 10220 }, { 0x33c9, G_UNICODE_NOT_PRESENT_OFFSET, 10223 }, { 0x33ca, G_UNICODE_NOT_PRESENT_OFFSET, 10226 }, { 0x33cb, G_UNICODE_NOT_PRESENT_OFFSET, 10229 }, { 0x33cc, G_UNICODE_NOT_PRESENT_OFFSET, 10232 }, { 0x33cd, G_UNICODE_NOT_PRESENT_OFFSET, 10235 }, { 0x33ce, G_UNICODE_NOT_PRESENT_OFFSET, 10238 }, { 0x33cf, G_UNICODE_NOT_PRESENT_OFFSET, 10241 }, { 0x33d0, G_UNICODE_NOT_PRESENT_OFFSET, 10244 }, { 0x33d1, G_UNICODE_NOT_PRESENT_OFFSET, 10247 }, { 0x33d2, G_UNICODE_NOT_PRESENT_OFFSET, 10250 }, { 0x33d3, G_UNICODE_NOT_PRESENT_OFFSET, 10254 }, { 0x33d4, G_UNICODE_NOT_PRESENT_OFFSET, 10257 }, { 0x33d5, G_UNICODE_NOT_PRESENT_OFFSET, 10260 }, { 0x33d6, G_UNICODE_NOT_PRESENT_OFFSET, 10264 }, { 0x33d7, G_UNICODE_NOT_PRESENT_OFFSET, 10268 }, { 0x33d8, G_UNICODE_NOT_PRESENT_OFFSET, 10271 }, { 0x33d9, G_UNICODE_NOT_PRESENT_OFFSET, 10276 }, { 0x33da, G_UNICODE_NOT_PRESENT_OFFSET, 10280 }, { 0x33db, G_UNICODE_NOT_PRESENT_OFFSET, 10283 }, { 0x33dc, G_UNICODE_NOT_PRESENT_OFFSET, 10286 }, { 0x33dd, G_UNICODE_NOT_PRESENT_OFFSET, 10289 }, { 0x33e0, G_UNICODE_NOT_PRESENT_OFFSET, 10292 }, { 0x33e1, G_UNICODE_NOT_PRESENT_OFFSET, 10297 }, { 0x33e2, G_UNICODE_NOT_PRESENT_OFFSET, 10302 }, { 0x33e3, G_UNICODE_NOT_PRESENT_OFFSET, 10307 }, { 0x33e4, G_UNICODE_NOT_PRESENT_OFFSET, 10312 }, { 0x33e5, G_UNICODE_NOT_PRESENT_OFFSET, 10317 }, { 0x33e6, G_UNICODE_NOT_PRESENT_OFFSET, 10322 }, { 0x33e7, G_UNICODE_NOT_PRESENT_OFFSET, 10327 }, { 0x33e8, G_UNICODE_NOT_PRESENT_OFFSET, 10332 }, { 0x33e9, G_UNICODE_NOT_PRESENT_OFFSET, 10337 }, { 0x33ea, G_UNICODE_NOT_PRESENT_OFFSET, 10343 }, { 0x33eb, G_UNICODE_NOT_PRESENT_OFFSET, 10349 }, { 0x33ec, G_UNICODE_NOT_PRESENT_OFFSET, 10355 }, { 0x33ed, G_UNICODE_NOT_PRESENT_OFFSET, 10361 }, { 0x33ee, G_UNICODE_NOT_PRESENT_OFFSET, 10367 }, { 0x33ef, G_UNICODE_NOT_PRESENT_OFFSET, 10373 }, { 0x33f0, G_UNICODE_NOT_PRESENT_OFFSET, 10379 }, { 0x33f1, G_UNICODE_NOT_PRESENT_OFFSET, 10385 }, { 0x33f2, G_UNICODE_NOT_PRESENT_OFFSET, 10391 }, { 0x33f3, G_UNICODE_NOT_PRESENT_OFFSET, 10397 }, { 0x33f4, G_UNICODE_NOT_PRESENT_OFFSET, 10403 }, { 0x33f5, G_UNICODE_NOT_PRESENT_OFFSET, 10409 }, { 0x33f6, G_UNICODE_NOT_PRESENT_OFFSET, 10415 }, { 0x33f7, G_UNICODE_NOT_PRESENT_OFFSET, 10421 }, { 0x33f8, G_UNICODE_NOT_PRESENT_OFFSET, 10427 }, { 0x33f9, G_UNICODE_NOT_PRESENT_OFFSET, 10433 }, { 0x33fa, G_UNICODE_NOT_PRESENT_OFFSET, 10439 }, { 0x33fb, G_UNICODE_NOT_PRESENT_OFFSET, 10445 }, { 0x33fc, G_UNICODE_NOT_PRESENT_OFFSET, 10451 }, { 0x33fd, G_UNICODE_NOT_PRESENT_OFFSET, 10457 }, { 0x33fe, G_UNICODE_NOT_PRESENT_OFFSET, 10463 }, { 0xf900, 10469, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf901, 10473, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf902, 6535, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf903, 10477, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf904, 10481, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf905, 10485, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf906, 10489, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf907, 6751, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf908, 6751, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf909, 10493, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf90a, 6567, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf90b, 10497, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf90c, 10501, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf90d, 10505, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf90e, 10509, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf90f, 10513, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf910, 10517, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf911, 10521, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf912, 10525, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf913, 10529, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf914, 10533, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf915, 10537, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf916, 10541, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf917, 10545, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf918, 10549, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf919, 10553, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf91a, 10557, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf91b, 10561, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf91c, 10565, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf91d, 10569, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf91e, 10573, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf91f, 10577, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf920, 10581, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf921, 10585, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf922, 10589, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf923, 10593, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf924, 10597, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf925, 10601, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf926, 10605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf927, 10609, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf928, 10613, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf929, 10617, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf92a, 10621, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf92b, 10625, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf92c, 10629, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf92d, 10633, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf92e, 10637, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf92f, 10641, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf930, 10645, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf931, 10649, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf932, 10653, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf933, 10657, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf934, 6399, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf935, 10661, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf936, 10665, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf937, 10669, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf938, 10673, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf939, 10677, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf93a, 10681, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf93b, 10685, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf93c, 10689, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf93d, 10693, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf93e, 10697, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf93f, 10701, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf940, 6691, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf941, 10705, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf942, 10709, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf943, 10713, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf944, 10717, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf945, 10721, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf946, 10725, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf947, 10729, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf948, 10733, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf949, 10737, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf94a, 10741, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf94b, 10745, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf94c, 10749, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf94d, 10753, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf94e, 10757, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf94f, 10761, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf950, 10765, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf951, 10769, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf952, 10773, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf953, 10777, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf954, 10781, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf955, 10785, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf956, 10789, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf957, 10793, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf958, 10797, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf959, 10801, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf95a, 10805, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf95b, 10809, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf95c, 10533, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf95d, 10813, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf95e, 10817, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf95f, 10821, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf960, 10825, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf961, 10829, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf962, 10833, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf963, 10837, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf964, 10841, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf965, 10845, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf966, 10849, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf967, 10853, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf968, 10857, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf969, 10861, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf96a, 10865, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf96b, 10869, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf96c, 10873, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf96d, 10877, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf96e, 10881, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf96f, 10885, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf970, 10889, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf971, 6543, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf972, 10893, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf973, 10897, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf974, 10901, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf975, 10905, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf976, 10909, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf977, 10913, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf978, 10917, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf979, 10921, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf97a, 10925, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf97b, 10929, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf97c, 10933, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf97d, 10937, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf97e, 10941, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf97f, 10945, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf980, 10949, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf981, 6051, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf982, 10953, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf983, 10957, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf984, 10961, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf985, 10965, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf986, 10969, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf987, 10973, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf988, 10977, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf989, 10981, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf98a, 5975, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf98b, 10985, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf98c, 10989, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf98d, 10993, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf98e, 10997, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf98f, 11001, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf990, 11005, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf991, 11009, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf992, 11013, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf993, 11017, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf994, 11021, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf995, 11025, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf996, 11029, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf997, 11033, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf998, 11037, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf999, 11041, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf99a, 11045, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf99b, 11049, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf99c, 11053, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf99d, 11057, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf99e, 11061, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf99f, 11065, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a0, 11069, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a1, 10885, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a2, 11073, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a3, 11077, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a4, 11081, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a5, 11085, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a6, 11089, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a7, 11093, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a8, 11097, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9a9, 11101, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9aa, 10821, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ab, 11105, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ac, 11109, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ad, 11113, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ae, 11117, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9af, 11121, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b0, 11125, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b1, 11129, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b2, 11133, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b3, 11137, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b4, 11141, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b5, 11145, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b6, 11149, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b7, 11153, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b8, 11157, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9b9, 11161, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ba, 11165, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9bb, 11169, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9bc, 11173, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9bd, 11177, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9be, 11181, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9bf, 10533, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c0, 11185, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c1, 11189, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c2, 11193, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c3, 11197, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c4, 6747, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c5, 11201, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c6, 11205, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c7, 11209, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c8, 11213, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9c9, 11217, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ca, 11221, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9cb, 11225, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9cc, 11229, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9cd, 11233, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ce, 11237, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9cf, 11241, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d0, 11245, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d1, 8199, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d2, 11249, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d3, 11253, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d4, 11257, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d5, 11261, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d6, 11265, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d7, 11269, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d8, 11273, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9d9, 11277, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9da, 11281, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9db, 10829, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9dc, 11285, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9dd, 11289, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9de, 11293, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9df, 11297, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e0, 11301, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e1, 11305, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e2, 11309, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e3, 11313, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e4, 11317, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e5, 11321, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e6, 11325, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e7, 11329, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e8, 11333, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9e9, 6563, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ea, 11337, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9eb, 11341, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ec, 11345, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ed, 11349, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ee, 11353, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ef, 11357, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f0, 11361, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f1, 11365, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f2, 11369, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f3, 11373, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f4, 11377, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f5, 11381, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f6, 11385, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f7, 6367, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f8, 11389, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9f9, 11393, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9fa, 11397, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9fb, 11401, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9fc, 11405, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9fd, 11409, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9fe, 11413, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xf9ff, 11417, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa00, 11421, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa01, 11425, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa02, 11429, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa03, 11433, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa04, 11437, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa05, 11441, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa06, 11445, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa07, 11449, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa08, 6475, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa09, 11453, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa0a, 6487, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa0b, 11457, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa0c, 11461, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa0d, 11465, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa10, 11469, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa12, 11473, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa15, 11477, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa16, 11481, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa17, 11485, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa18, 11489, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa19, 11493, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa1a, 11497, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa1b, 11501, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa1c, 11505, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa1d, 11509, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa1e, 6395, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa20, 11513, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa22, 11517, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa25, 11521, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa26, 11525, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa2a, 11529, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa2b, 11533, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa2c, 11537, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa2d, 11541, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa30, 11545, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa31, 11549, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa32, 11553, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa33, 11557, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa34, 11561, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa35, 11565, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa36, 11569, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa37, 11573, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa38, 11577, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa39, 11581, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa3a, 11585, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa3b, 11589, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa3c, 6079, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa3d, 11593, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa3e, 11597, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa3f, 11601, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa40, 11605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa41, 11609, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa42, 11613, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa43, 11617, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa44, 11621, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa45, 11625, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa46, 11629, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa47, 11633, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa48, 11637, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa49, 11641, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa4a, 11645, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa4b, 11649, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa4c, 8219, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa4d, 11653, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa4e, 11657, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa4f, 11661, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa50, 11665, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa51, 8235, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa52, 11669, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa53, 11673, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa54, 11677, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa55, 11681, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa56, 11685, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa57, 11029, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa58, 11689, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa59, 11693, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa5a, 11697, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa5b, 11701, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa5c, 11705, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa5d, 11709, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa5e, 11709, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa5f, 11713, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa60, 11717, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa61, 11721, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa62, 11725, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa63, 11729, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa64, 11733, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa65, 11737, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa66, 11741, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa67, 11521, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa68, 11745, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa69, 11749, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfa6a, 11753, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb00, G_UNICODE_NOT_PRESENT_OFFSET, 11757 }, { 0xfb01, G_UNICODE_NOT_PRESENT_OFFSET, 11760 }, { 0xfb02, G_UNICODE_NOT_PRESENT_OFFSET, 11763 }, { 0xfb03, G_UNICODE_NOT_PRESENT_OFFSET, 11766 }, { 0xfb04, G_UNICODE_NOT_PRESENT_OFFSET, 11770 }, { 0xfb05, G_UNICODE_NOT_PRESENT_OFFSET, 11774 }, { 0xfb06, G_UNICODE_NOT_PRESENT_OFFSET, 11774 }, { 0xfb13, G_UNICODE_NOT_PRESENT_OFFSET, 11777 }, { 0xfb14, G_UNICODE_NOT_PRESENT_OFFSET, 11782 }, { 0xfb15, G_UNICODE_NOT_PRESENT_OFFSET, 11787 }, { 0xfb16, G_UNICODE_NOT_PRESENT_OFFSET, 11792 }, { 0xfb17, G_UNICODE_NOT_PRESENT_OFFSET, 11797 }, { 0xfb1d, 11802, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb1f, 11807, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb20, G_UNICODE_NOT_PRESENT_OFFSET, 11812 }, { 0xfb21, G_UNICODE_NOT_PRESENT_OFFSET, 5052 }, { 0xfb22, G_UNICODE_NOT_PRESENT_OFFSET, 5061 }, { 0xfb23, G_UNICODE_NOT_PRESENT_OFFSET, 11815 }, { 0xfb24, G_UNICODE_NOT_PRESENT_OFFSET, 11818 }, { 0xfb25, G_UNICODE_NOT_PRESENT_OFFSET, 11821 }, { 0xfb26, G_UNICODE_NOT_PRESENT_OFFSET, 11824 }, { 0xfb27, G_UNICODE_NOT_PRESENT_OFFSET, 11827 }, { 0xfb28, G_UNICODE_NOT_PRESENT_OFFSET, 11830 }, { 0xfb29, G_UNICODE_NOT_PRESENT_OFFSET, 4957 }, { 0xfb2a, 11833, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb2b, 11838, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb2c, 11843, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb2d, 11850, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb2e, 11857, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb2f, 11862, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb30, 11867, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb31, 11872, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb32, 11877, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb33, 11882, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb34, 11887, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb35, 11892, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb36, 11897, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb38, 11902, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb39, 11907, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb3a, 11912, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb3b, 11917, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb3c, 11922, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb3e, 11927, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb40, 11932, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb41, 11937, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb43, 11942, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb44, 11947, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb46, 11952, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb47, 11957, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb48, 11962, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb49, 11967, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb4a, 11972, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb4b, 11977, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb4c, 11982, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb4d, 11987, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb4e, 11992, G_UNICODE_NOT_PRESENT_OFFSET }, { 0xfb4f, G_UNICODE_NOT_PRESENT_OFFSET, 11997 }, { 0xfb50, G_UNICODE_NOT_PRESENT_OFFSET, 12002 }, { 0xfb51, G_UNICODE_NOT_PRESENT_OFFSET, 12002 }, { 0xfb52, G_UNICODE_NOT_PRESENT_OFFSET, 12005 }, { 0xfb53, G_UNICODE_NOT_PRESENT_OFFSET, 12005 }, { 0xfb54, G_UNICODE_NOT_PRESENT_OFFSET, 12005 }, { 0xfb55, G_UNICODE_NOT_PRESENT_OFFSET, 12005 }, { 0xfb56, G_UNICODE_NOT_PRESENT_OFFSET, 12008 }, { 0xfb57, G_UNICODE_NOT_PRESENT_OFFSET, 12008 }, { 0xfb58, G_UNICODE_NOT_PRESENT_OFFSET, 12008 }, { 0xfb59, G_UNICODE_NOT_PRESENT_OFFSET, 12008 }, { 0xfb5a, G_UNICODE_NOT_PRESENT_OFFSET, 12011 }, { 0xfb5b, G_UNICODE_NOT_PRESENT_OFFSET, 12011 }, { 0xfb5c, G_UNICODE_NOT_PRESENT_OFFSET, 12011 }, { 0xfb5d, G_UNICODE_NOT_PRESENT_OFFSET, 12011 }, { 0xfb5e, G_UNICODE_NOT_PRESENT_OFFSET, 12014 }, { 0xfb5f, G_UNICODE_NOT_PRESENT_OFFSET, 12014 }, { 0xfb60, G_UNICODE_NOT_PRESENT_OFFSET, 12014 }, { 0xfb61, G_UNICODE_NOT_PRESENT_OFFSET, 12014 }, { 0xfb62, G_UNICODE_NOT_PRESENT_OFFSET, 12017 }, { 0xfb63, G_UNICODE_NOT_PRESENT_OFFSET, 12017 }, { 0xfb64, G_UNICODE_NOT_PRESENT_OFFSET, 12017 }, { 0xfb65, G_UNICODE_NOT_PRESENT_OFFSET, 12017 }, { 0xfb66, G_UNICODE_NOT_PRESENT_OFFSET, 12020 }, { 0xfb67, G_UNICODE_NOT_PRESENT_OFFSET, 12020 }, { 0xfb68, G_UNICODE_NOT_PRESENT_OFFSET, 12020 }, { 0xfb69, G_UNICODE_NOT_PRESENT_OFFSET, 12020 }, { 0xfb6a, G_UNICODE_NOT_PRESENT_OFFSET, 12023 }, { 0xfb6b, G_UNICODE_NOT_PRESENT_OFFSET, 12023 }, { 0xfb6c, G_UNICODE_NOT_PRESENT_OFFSET, 12023 }, { 0xfb6d, G_UNICODE_NOT_PRESENT_OFFSET, 12023 }, { 0xfb6e, G_UNICODE_NOT_PRESENT_OFFSET, 12026 }, { 0xfb6f, G_UNICODE_NOT_PRESENT_OFFSET, 12026 }, { 0xfb70, G_UNICODE_NOT_PRESENT_OFFSET, 12026 }, { 0xfb71, G_UNICODE_NOT_PRESENT_OFFSET, 12026 }, { 0xfb72, G_UNICODE_NOT_PRESENT_OFFSET, 12029 }, { 0xfb73, G_UNICODE_NOT_PRESENT_OFFSET, 12029 }, { 0xfb74, G_UNICODE_NOT_PRESENT_OFFSET, 12029 }, { 0xfb75, G_UNICODE_NOT_PRESENT_OFFSET, 12029 }, { 0xfb76, G_UNICODE_NOT_PRESENT_OFFSET, 12032 }, { 0xfb77, G_UNICODE_NOT_PRESENT_OFFSET, 12032 }, { 0xfb78, G_UNICODE_NOT_PRESENT_OFFSET, 12032 }, { 0xfb79, G_UNICODE_NOT_PRESENT_OFFSET, 12032 }, { 0xfb7a, G_UNICODE_NOT_PRESENT_OFFSET, 12035 }, { 0xfb7b, G_UNICODE_NOT_PRESENT_OFFSET, 12035 }, { 0xfb7c, G_UNICODE_NOT_PRESENT_OFFSET, 12035 }, { 0xfb7d, G_UNICODE_NOT_PRESENT_OFFSET, 12035 }, { 0xfb7e, G_UNICODE_NOT_PRESENT_OFFSET, 12038 }, { 0xfb7f, G_UNICODE_NOT_PRESENT_OFFSET, 12038 }, { 0xfb80, G_UNICODE_NOT_PRESENT_OFFSET, 12038 }, { 0xfb81, G_UNICODE_NOT_PRESENT_OFFSET, 12038 }, { 0xfb82, G_UNICODE_NOT_PRESENT_OFFSET, 12041 }, { 0xfb83, G_UNICODE_NOT_PRESENT_OFFSET, 12041 }, { 0xfb84, G_UNICODE_NOT_PRESENT_OFFSET, 12044 }, { 0xfb85, G_UNICODE_NOT_PRESENT_OFFSET, 12044 }, { 0xfb86, G_UNICODE_NOT_PRESENT_OFFSET, 12047 }, { 0xfb87, G_UNICODE_NOT_PRESENT_OFFSET, 12047 }, { 0xfb88, G_UNICODE_NOT_PRESENT_OFFSET, 12050 }, { 0xfb89, G_UNICODE_NOT_PRESENT_OFFSET, 12050 }, { 0xfb8a, G_UNICODE_NOT_PRESENT_OFFSET, 12053 }, { 0xfb8b, G_UNICODE_NOT_PRESENT_OFFSET, 12053 }, { 0xfb8c, G_UNICODE_NOT_PRESENT_OFFSET, 12056 }, { 0xfb8d, G_UNICODE_NOT_PRESENT_OFFSET, 12056 }, { 0xfb8e, G_UNICODE_NOT_PRESENT_OFFSET, 12059 }, { 0xfb8f, G_UNICODE_NOT_PRESENT_OFFSET, 12059 }, { 0xfb90, G_UNICODE_NOT_PRESENT_OFFSET, 12059 }, { 0xfb91, G_UNICODE_NOT_PRESENT_OFFSET, 12059 }, { 0xfb92, G_UNICODE_NOT_PRESENT_OFFSET, 12062 }, { 0xfb93, G_UNICODE_NOT_PRESENT_OFFSET, 12062 }, { 0xfb94, G_UNICODE_NOT_PRESENT_OFFSET, 12062 }, { 0xfb95, G_UNICODE_NOT_PRESENT_OFFSET, 12062 }, { 0xfb96, G_UNICODE_NOT_PRESENT_OFFSET, 12065 }, { 0xfb97, G_UNICODE_NOT_PRESENT_OFFSET, 12065 }, { 0xfb98, G_UNICODE_NOT_PRESENT_OFFSET, 12065 }, { 0xfb99, G_UNICODE_NOT_PRESENT_OFFSET, 12065 }, { 0xfb9a, G_UNICODE_NOT_PRESENT_OFFSET, 12068 }, { 0xfb9b, G_UNICODE_NOT_PRESENT_OFFSET, 12068 }, { 0xfb9c, G_UNICODE_NOT_PRESENT_OFFSET, 12068 }, { 0xfb9d, G_UNICODE_NOT_PRESENT_OFFSET, 12068 }, { 0xfb9e, G_UNICODE_NOT_PRESENT_OFFSET, 12071 }, { 0xfb9f, G_UNICODE_NOT_PRESENT_OFFSET, 12071 }, { 0xfba0, G_UNICODE_NOT_PRESENT_OFFSET, 12074 }, { 0xfba1, G_UNICODE_NOT_PRESENT_OFFSET, 12074 }, { 0xfba2, G_UNICODE_NOT_PRESENT_OFFSET, 12074 }, { 0xfba3, G_UNICODE_NOT_PRESENT_OFFSET, 12074 }, { 0xfba4, G_UNICODE_NOT_PRESENT_OFFSET, 1718 }, { 0xfba5, G_UNICODE_NOT_PRESENT_OFFSET, 1718 }, { 0xfba6, G_UNICODE_NOT_PRESENT_OFFSET, 12077 }, { 0xfba7, G_UNICODE_NOT_PRESENT_OFFSET, 12077 }, { 0xfba8, G_UNICODE_NOT_PRESENT_OFFSET, 12077 }, { 0xfba9, G_UNICODE_NOT_PRESENT_OFFSET, 12077 }, { 0xfbaa, G_UNICODE_NOT_PRESENT_OFFSET, 12080 }, { 0xfbab, G_UNICODE_NOT_PRESENT_OFFSET, 12080 }, { 0xfbac, G_UNICODE_NOT_PRESENT_OFFSET, 12080 }, { 0xfbad, G_UNICODE_NOT_PRESENT_OFFSET, 12080 }, { 0xfbae, G_UNICODE_NOT_PRESENT_OFFSET, 12083 }, { 0xfbaf, G_UNICODE_NOT_PRESENT_OFFSET, 12083 }, { 0xfbb0, G_UNICODE_NOT_PRESENT_OFFSET, 1728 }, { 0xfbb1, G_UNICODE_NOT_PRESENT_OFFSET, 1728 }, { 0xfbd3, G_UNICODE_NOT_PRESENT_OFFSET, 12086 }, { 0xfbd4, G_UNICODE_NOT_PRESENT_OFFSET, 12086 }, { 0xfbd5, G_UNICODE_NOT_PRESENT_OFFSET, 12086 }, { 0xfbd6, G_UNICODE_NOT_PRESENT_OFFSET, 12086 }, { 0xfbd7, G_UNICODE_NOT_PRESENT_OFFSET, 12089 }, { 0xfbd8, G_UNICODE_NOT_PRESENT_OFFSET, 12089 }, { 0xfbd9, G_UNICODE_NOT_PRESENT_OFFSET, 12092 }, { 0xfbda, G_UNICODE_NOT_PRESENT_OFFSET, 12092 }, { 0xfbdb, G_UNICODE_NOT_PRESENT_OFFSET, 12095 }, { 0xfbdc, G_UNICODE_NOT_PRESENT_OFFSET, 12095 }, { 0xfbdd, G_UNICODE_NOT_PRESENT_OFFSET, 1708 }, { 0xfbde, G_UNICODE_NOT_PRESENT_OFFSET, 12098 }, { 0xfbdf, G_UNICODE_NOT_PRESENT_OFFSET, 12098 }, { 0xfbe0, G_UNICODE_NOT_PRESENT_OFFSET, 12101 }, { 0xfbe1, G_UNICODE_NOT_PRESENT_OFFSET, 12101 }, { 0xfbe2, G_UNICODE_NOT_PRESENT_OFFSET, 12104 }, { 0xfbe3, G_UNICODE_NOT_PRESENT_OFFSET, 12104 }, { 0xfbe4, G_UNICODE_NOT_PRESENT_OFFSET, 12107 }, { 0xfbe5, G_UNICODE_NOT_PRESENT_OFFSET, 12107 }, { 0xfbe6, G_UNICODE_NOT_PRESENT_OFFSET, 12107 }, { 0xfbe7, G_UNICODE_NOT_PRESENT_OFFSET, 12107 }, { 0xfbe8, G_UNICODE_NOT_PRESENT_OFFSET, 12110 }, { 0xfbe9, G_UNICODE_NOT_PRESENT_OFFSET, 12110 }, { 0xfbea, G_UNICODE_NOT_PRESENT_OFFSET, 12113 }, { 0xfbeb, G_UNICODE_NOT_PRESENT_OFFSET, 12113 }, { 0xfbec, G_UNICODE_NOT_PRESENT_OFFSET, 12120 }, { 0xfbed, G_UNICODE_NOT_PRESENT_OFFSET, 12120 }, { 0xfbee, G_UNICODE_NOT_PRESENT_OFFSET, 12127 }, { 0xfbef, G_UNICODE_NOT_PRESENT_OFFSET, 12127 }, { 0xfbf0, G_UNICODE_NOT_PRESENT_OFFSET, 12134 }, { 0xfbf1, G_UNICODE_NOT_PRESENT_OFFSET, 12134 }, { 0xfbf2, G_UNICODE_NOT_PRESENT_OFFSET, 12141 }, { 0xfbf3, G_UNICODE_NOT_PRESENT_OFFSET, 12141 }, { 0xfbf4, G_UNICODE_NOT_PRESENT_OFFSET, 12148 }, { 0xfbf5, G_UNICODE_NOT_PRESENT_OFFSET, 12148 }, { 0xfbf6, G_UNICODE_NOT_PRESENT_OFFSET, 12155 }, { 0xfbf7, G_UNICODE_NOT_PRESENT_OFFSET, 12155 }, { 0xfbf8, G_UNICODE_NOT_PRESENT_OFFSET, 12155 }, { 0xfbf9, G_UNICODE_NOT_PRESENT_OFFSET, 12162 }, { 0xfbfa, G_UNICODE_NOT_PRESENT_OFFSET, 12162 }, { 0xfbfb, G_UNICODE_NOT_PRESENT_OFFSET, 12162 }, { 0xfbfc, G_UNICODE_NOT_PRESENT_OFFSET, 12169 }, { 0xfbfd, G_UNICODE_NOT_PRESENT_OFFSET, 12169 }, { 0xfbfe, G_UNICODE_NOT_PRESENT_OFFSET, 12169 }, { 0xfbff, G_UNICODE_NOT_PRESENT_OFFSET, 12169 }, { 0xfc00, G_UNICODE_NOT_PRESENT_OFFSET, 12172 }, { 0xfc01, G_UNICODE_NOT_PRESENT_OFFSET, 12179 }, { 0xfc02, G_UNICODE_NOT_PRESENT_OFFSET, 12186 }, { 0xfc03, G_UNICODE_NOT_PRESENT_OFFSET, 12162 }, { 0xfc04, G_UNICODE_NOT_PRESENT_OFFSET, 12193 }, { 0xfc05, G_UNICODE_NOT_PRESENT_OFFSET, 12200 }, { 0xfc06, G_UNICODE_NOT_PRESENT_OFFSET, 12205 }, { 0xfc07, G_UNICODE_NOT_PRESENT_OFFSET, 12210 }, { 0xfc08, G_UNICODE_NOT_PRESENT_OFFSET, 12215 }, { 0xfc09, G_UNICODE_NOT_PRESENT_OFFSET, 12220 }, { 0xfc0a, G_UNICODE_NOT_PRESENT_OFFSET, 12225 }, { 0xfc0b, G_UNICODE_NOT_PRESENT_OFFSET, 12230 }, { 0xfc0c, G_UNICODE_NOT_PRESENT_OFFSET, 12235 }, { 0xfc0d, G_UNICODE_NOT_PRESENT_OFFSET, 12240 }, { 0xfc0e, G_UNICODE_NOT_PRESENT_OFFSET, 12245 }, { 0xfc0f, G_UNICODE_NOT_PRESENT_OFFSET, 12250 }, { 0xfc10, G_UNICODE_NOT_PRESENT_OFFSET, 12255 }, { 0xfc11, G_UNICODE_NOT_PRESENT_OFFSET, 12260 }, { 0xfc12, G_UNICODE_NOT_PRESENT_OFFSET, 12265 }, { 0xfc13, G_UNICODE_NOT_PRESENT_OFFSET, 12270 }, { 0xfc14, G_UNICODE_NOT_PRESENT_OFFSET, 12275 }, { 0xfc15, G_UNICODE_NOT_PRESENT_OFFSET, 12280 }, { 0xfc16, G_UNICODE_NOT_PRESENT_OFFSET, 12285 }, { 0xfc17, G_UNICODE_NOT_PRESENT_OFFSET, 12290 }, { 0xfc18, G_UNICODE_NOT_PRESENT_OFFSET, 12295 }, { 0xfc19, G_UNICODE_NOT_PRESENT_OFFSET, 12300 }, { 0xfc1a, G_UNICODE_NOT_PRESENT_OFFSET, 12305 }, { 0xfc1b, G_UNICODE_NOT_PRESENT_OFFSET, 12310 }, { 0xfc1c, G_UNICODE_NOT_PRESENT_OFFSET, 12315 }, { 0xfc1d, G_UNICODE_NOT_PRESENT_OFFSET, 12320 }, { 0xfc1e, G_UNICODE_NOT_PRESENT_OFFSET, 12325 }, { 0xfc1f, G_UNICODE_NOT_PRESENT_OFFSET, 12330 }, { 0xfc20, G_UNICODE_NOT_PRESENT_OFFSET, 12335 }, { 0xfc21, G_UNICODE_NOT_PRESENT_OFFSET, 12340 }, { 0xfc22, G_UNICODE_NOT_PRESENT_OFFSET, 12345 }, { 0xfc23, G_UNICODE_NOT_PRESENT_OFFSET, 12350 }, { 0xfc24, G_UNICODE_NOT_PRESENT_OFFSET, 12355 }, { 0xfc25, G_UNICODE_NOT_PRESENT_OFFSET, 12360 }, { 0xfc26, G_UNICODE_NOT_PRESENT_OFFSET, 12365 }, { 0xfc27, G_UNICODE_NOT_PRESENT_OFFSET, 12370 }, { 0xfc28, G_UNICODE_NOT_PRESENT_OFFSET, 12375 }, { 0xfc29, G_UNICODE_NOT_PRESENT_OFFSET, 12380 }, { 0xfc2a, G_UNICODE_NOT_PRESENT_OFFSET, 12385 }, { 0xfc2b, G_UNICODE_NOT_PRESENT_OFFSET, 12390 }, { 0xfc2c, G_UNICODE_NOT_PRESENT_OFFSET, 12395 }, { 0xfc2d, G_UNICODE_NOT_PRESENT_OFFSET, 12400 }, { 0xfc2e, G_UNICODE_NOT_PRESENT_OFFSET, 12405 }, { 0xfc2f, G_UNICODE_NOT_PRESENT_OFFSET, 12410 }, { 0xfc30, G_UNICODE_NOT_PRESENT_OFFSET, 12415 }, { 0xfc31, G_UNICODE_NOT_PRESENT_OFFSET, 12420 }, { 0xfc32, G_UNICODE_NOT_PRESENT_OFFSET, 12425 }, { 0xfc33, G_UNICODE_NOT_PRESENT_OFFSET, 12430 }, { 0xfc34, G_UNICODE_NOT_PRESENT_OFFSET, 12435 }, { 0xfc35, G_UNICODE_NOT_PRESENT_OFFSET, 12440 }, { 0xfc36, G_UNICODE_NOT_PRESENT_OFFSET, 12445 }, { 0xfc37, G_UNICODE_NOT_PRESENT_OFFSET, 12450 }, { 0xfc38, G_UNICODE_NOT_PRESENT_OFFSET, 12455 }, { 0xfc39, G_UNICODE_NOT_PRESENT_OFFSET, 12460 }, { 0xfc3a, G_UNICODE_NOT_PRESENT_OFFSET, 12465 }, { 0xfc3b, G_UNICODE_NOT_PRESENT_OFFSET, 12470 }, { 0xfc3c, G_UNICODE_NOT_PRESENT_OFFSET, 12475 }, { 0xfc3d, G_UNICODE_NOT_PRESENT_OFFSET, 12480 }, { 0xfc3e, G_UNICODE_NOT_PRESENT_OFFSET, 12485 }, { 0xfc3f, G_UNICODE_NOT_PRESENT_OFFSET, 12490 }, { 0xfc40, G_UNICODE_NOT_PRESENT_OFFSET, 12495 }, { 0xfc41, G_UNICODE_NOT_PRESENT_OFFSET, 12500 }, { 0xfc42, G_UNICODE_NOT_PRESENT_OFFSET, 12505 }, { 0xfc43, G_UNICODE_NOT_PRESENT_OFFSET, 12510 }, { 0xfc44, G_UNICODE_NOT_PRESENT_OFFSET, 12515 }, { 0xfc45, G_UNICODE_NOT_PRESENT_OFFSET, 12520 }, { 0xfc46, G_UNICODE_NOT_PRESENT_OFFSET, 12525 }, { 0xfc47, G_UNICODE_NOT_PRESENT_OFFSET, 12530 }, { 0xfc48, G_UNICODE_NOT_PRESENT_OFFSET, 12535 }, { 0xfc49, G_UNICODE_NOT_PRESENT_OFFSET, 12540 }, { 0xfc4a, G_UNICODE_NOT_PRESENT_OFFSET, 12545 }, { 0xfc4b, G_UNICODE_NOT_PRESENT_OFFSET, 12550 }, { 0xfc4c, G_UNICODE_NOT_PRESENT_OFFSET, 12555 }, { 0xfc4d, G_UNICODE_NOT_PRESENT_OFFSET, 12560 }, { 0xfc4e, G_UNICODE_NOT_PRESENT_OFFSET, 12565 }, { 0xfc4f, G_UNICODE_NOT_PRESENT_OFFSET, 12570 }, { 0xfc50, G_UNICODE_NOT_PRESENT_OFFSET, 12575 }, { 0xfc51, G_UNICODE_NOT_PRESENT_OFFSET, 12580 }, { 0xfc52, G_UNICODE_NOT_PRESENT_OFFSET, 12585 }, { 0xfc53, G_UNICODE_NOT_PRESENT_OFFSET, 12590 }, { 0xfc54, G_UNICODE_NOT_PRESENT_OFFSET, 12595 }, { 0xfc55, G_UNICODE_NOT_PRESENT_OFFSET, 12600 }, { 0xfc56, G_UNICODE_NOT_PRESENT_OFFSET, 12605 }, { 0xfc57, G_UNICODE_NOT_PRESENT_OFFSET, 12610 }, { 0xfc58, G_UNICODE_NOT_PRESENT_OFFSET, 12615 }, { 0xfc59, G_UNICODE_NOT_PRESENT_OFFSET, 12620 }, { 0xfc5a, G_UNICODE_NOT_PRESENT_OFFSET, 12625 }, { 0xfc5b, G_UNICODE_NOT_PRESENT_OFFSET, 12630 }, { 0xfc5c, G_UNICODE_NOT_PRESENT_OFFSET, 12635 }, { 0xfc5d, G_UNICODE_NOT_PRESENT_OFFSET, 12640 }, { 0xfc5e, G_UNICODE_NOT_PRESENT_OFFSET, 12645 }, { 0xfc5f, G_UNICODE_NOT_PRESENT_OFFSET, 12651 }, { 0xfc60, G_UNICODE_NOT_PRESENT_OFFSET, 12657 }, { 0xfc61, G_UNICODE_NOT_PRESENT_OFFSET, 12663 }, { 0xfc62, G_UNICODE_NOT_PRESENT_OFFSET, 12669 }, { 0xfc63, G_UNICODE_NOT_PRESENT_OFFSET, 12675 }, { 0xfc64, G_UNICODE_NOT_PRESENT_OFFSET, 12681 }, { 0xfc65, G_UNICODE_NOT_PRESENT_OFFSET, 12688 }, { 0xfc66, G_UNICODE_NOT_PRESENT_OFFSET, 12186 }, { 0xfc67, G_UNICODE_NOT_PRESENT_OFFSET, 12695 }, { 0xfc68, G_UNICODE_NOT_PRESENT_OFFSET, 12162 }, { 0xfc69, G_UNICODE_NOT_PRESENT_OFFSET, 12193 }, { 0xfc6a, G_UNICODE_NOT_PRESENT_OFFSET, 12702 }, { 0xfc6b, G_UNICODE_NOT_PRESENT_OFFSET, 12707 }, { 0xfc6c, G_UNICODE_NOT_PRESENT_OFFSET, 12215 }, { 0xfc6d, G_UNICODE_NOT_PRESENT_OFFSET, 12712 }, { 0xfc6e, G_UNICODE_NOT_PRESENT_OFFSET, 12220 }, { 0xfc6f, G_UNICODE_NOT_PRESENT_OFFSET, 12225 }, { 0xfc70, G_UNICODE_NOT_PRESENT_OFFSET, 12717 }, { 0xfc71, G_UNICODE_NOT_PRESENT_OFFSET, 12722 }, { 0xfc72, G_UNICODE_NOT_PRESENT_OFFSET, 12245 }, { 0xfc73, G_UNICODE_NOT_PRESENT_OFFSET, 12727 }, { 0xfc74, G_UNICODE_NOT_PRESENT_OFFSET, 12250 }, { 0xfc75, G_UNICODE_NOT_PRESENT_OFFSET, 12255 }, { 0xfc76, G_UNICODE_NOT_PRESENT_OFFSET, 12732 }, { 0xfc77, G_UNICODE_NOT_PRESENT_OFFSET, 12737 }, { 0xfc78, G_UNICODE_NOT_PRESENT_OFFSET, 12265 }, { 0xfc79, G_UNICODE_NOT_PRESENT_OFFSET, 12742 }, { 0xfc7a, G_UNICODE_NOT_PRESENT_OFFSET, 12270 }, { 0xfc7b, G_UNICODE_NOT_PRESENT_OFFSET, 12275 }, { 0xfc7c, G_UNICODE_NOT_PRESENT_OFFSET, 12420 }, { 0xfc7d, G_UNICODE_NOT_PRESENT_OFFSET, 12425 }, { 0xfc7e, G_UNICODE_NOT_PRESENT_OFFSET, 12440 }, { 0xfc7f, G_UNICODE_NOT_PRESENT_OFFSET, 12445 }, { 0xfc80, G_UNICODE_NOT_PRESENT_OFFSET, 12450 }, { 0xfc81, G_UNICODE_NOT_PRESENT_OFFSET, 12470 }, { 0xfc82, G_UNICODE_NOT_PRESENT_OFFSET, 12475 }, { 0xfc83, G_UNICODE_NOT_PRESENT_OFFSET, 12480 }, { 0xfc84, G_UNICODE_NOT_PRESENT_OFFSET, 12485 }, { 0xfc85, G_UNICODE_NOT_PRESENT_OFFSET, 12505 }, { 0xfc86, G_UNICODE_NOT_PRESENT_OFFSET, 12510 }, { 0xfc87, G_UNICODE_NOT_PRESENT_OFFSET, 12515 }, { 0xfc88, G_UNICODE_NOT_PRESENT_OFFSET, 12747 }, { 0xfc89, G_UNICODE_NOT_PRESENT_OFFSET, 12535 }, { 0xfc8a, G_UNICODE_NOT_PRESENT_OFFSET, 12752 }, { 0xfc8b, G_UNICODE_NOT_PRESENT_OFFSET, 12757 }, { 0xfc8c, G_UNICODE_NOT_PRESENT_OFFSET, 12565 }, { 0xfc8d, G_UNICODE_NOT_PRESENT_OFFSET, 12762 }, { 0xfc8e, G_UNICODE_NOT_PRESENT_OFFSET, 12570 }, { 0xfc8f, G_UNICODE_NOT_PRESENT_OFFSET, 12575 }, { 0xfc90, G_UNICODE_NOT_PRESENT_OFFSET, 12640 }, { 0xfc91, G_UNICODE_NOT_PRESENT_OFFSET, 12767 }, { 0xfc92, G_UNICODE_NOT_PRESENT_OFFSET, 12772 }, { 0xfc93, G_UNICODE_NOT_PRESENT_OFFSET, 12615 }, { 0xfc94, G_UNICODE_NOT_PRESENT_OFFSET, 12777 }, { 0xfc95, G_UNICODE_NOT_PRESENT_OFFSET, 12620 }, { 0xfc96, G_UNICODE_NOT_PRESENT_OFFSET, 12625 }, { 0xfc97, G_UNICODE_NOT_PRESENT_OFFSET, 12172 }, { 0xfc98, G_UNICODE_NOT_PRESENT_OFFSET, 12179 }, { 0xfc99, G_UNICODE_NOT_PRESENT_OFFSET, 12782 }, { 0xfc9a, G_UNICODE_NOT_PRESENT_OFFSET, 12186 }, { 0xfc9b, G_UNICODE_NOT_PRESENT_OFFSET, 12789 }, { 0xfc9c, G_UNICODE_NOT_PRESENT_OFFSET, 12200 }, { 0xfc9d, G_UNICODE_NOT_PRESENT_OFFSET, 12205 }, { 0xfc9e, G_UNICODE_NOT_PRESENT_OFFSET, 12210 }, { 0xfc9f, G_UNICODE_NOT_PRESENT_OFFSET, 12215 }, { 0xfca0, G_UNICODE_NOT_PRESENT_OFFSET, 12796 }, { 0xfca1, G_UNICODE_NOT_PRESENT_OFFSET, 12230 }, { 0xfca2, G_UNICODE_NOT_PRESENT_OFFSET, 12235 }, { 0xfca3, G_UNICODE_NOT_PRESENT_OFFSET, 12240 }, { 0xfca4, G_UNICODE_NOT_PRESENT_OFFSET, 12245 }, { 0xfca5, G_UNICODE_NOT_PRESENT_OFFSET, 12801 }, { 0xfca6, G_UNICODE_NOT_PRESENT_OFFSET, 12265 }, { 0xfca7, G_UNICODE_NOT_PRESENT_OFFSET, 12280 }, { 0xfca8, G_UNICODE_NOT_PRESENT_OFFSET, 12285 }, { 0xfca9, G_UNICODE_NOT_PRESENT_OFFSET, 12290 }, { 0xfcaa, G_UNICODE_NOT_PRESENT_OFFSET, 12295 }, { 0xfcab, G_UNICODE_NOT_PRESENT_OFFSET, 12300 }, { 0xfcac, G_UNICODE_NOT_PRESENT_OFFSET, 12310 }, { 0xfcad, G_UNICODE_NOT_PRESENT_OFFSET, 12315 }, { 0xfcae, G_UNICODE_NOT_PRESENT_OFFSET, 12320 }, { 0xfcaf, G_UNICODE_NOT_PRESENT_OFFSET, 12325 }, { 0xfcb0, G_UNICODE_NOT_PRESENT_OFFSET, 12330 }, { 0xfcb1, G_UNICODE_NOT_PRESENT_OFFSET, 12335 }, { 0xfcb2, G_UNICODE_NOT_PRESENT_OFFSET, 12806 }, { 0xfcb3, G_UNICODE_NOT_PRESENT_OFFSET, 12340 }, { 0xfcb4, G_UNICODE_NOT_PRESENT_OFFSET, 12345 }, { 0xfcb5, G_UNICODE_NOT_PRESENT_OFFSET, 12350 }, { 0xfcb6, G_UNICODE_NOT_PRESENT_OFFSET, 12355 }, { 0xfcb7, G_UNICODE_NOT_PRESENT_OFFSET, 12360 }, { 0xfcb8, G_UNICODE_NOT_PRESENT_OFFSET, 12365 }, { 0xfcb9, G_UNICODE_NOT_PRESENT_OFFSET, 12375 }, { 0xfcba, G_UNICODE_NOT_PRESENT_OFFSET, 12380 }, { 0xfcbb, G_UNICODE_NOT_PRESENT_OFFSET, 12385 }, { 0xfcbc, G_UNICODE_NOT_PRESENT_OFFSET, 12390 }, { 0xfcbd, G_UNICODE_NOT_PRESENT_OFFSET, 12395 }, { 0xfcbe, G_UNICODE_NOT_PRESENT_OFFSET, 12400 }, { 0xfcbf, G_UNICODE_NOT_PRESENT_OFFSET, 12405 }, { 0xfcc0, G_UNICODE_NOT_PRESENT_OFFSET, 12410 }, { 0xfcc1, G_UNICODE_NOT_PRESENT_OFFSET, 12415 }, { 0xfcc2, G_UNICODE_NOT_PRESENT_OFFSET, 12430 }, { 0xfcc3, G_UNICODE_NOT_PRESENT_OFFSET, 12435 }, { 0xfcc4, G_UNICODE_NOT_PRESENT_OFFSET, 12455 }, { 0xfcc5, G_UNICODE_NOT_PRESENT_OFFSET, 12460 }, { 0xfcc6, G_UNICODE_NOT_PRESENT_OFFSET, 12465 }, { 0xfcc7, G_UNICODE_NOT_PRESENT_OFFSET, 12470 }, { 0xfcc8, G_UNICODE_NOT_PRESENT_OFFSET, 12475 }, { 0xfcc9, G_UNICODE_NOT_PRESENT_OFFSET, 12490 }, { 0xfcca, G_UNICODE_NOT_PRESENT_OFFSET, 12495 }, { 0xfccb, G_UNICODE_NOT_PRESENT_OFFSET, 12500 }, { 0xfccc, G_UNICODE_NOT_PRESENT_OFFSET, 12505 }, { 0xfccd, G_UNICODE_NOT_PRESENT_OFFSET, 12811 }, { 0xfcce, G_UNICODE_NOT_PRESENT_OFFSET, 12520 }, { 0xfccf, G_UNICODE_NOT_PRESENT_OFFSET, 12525 }, { 0xfcd0, G_UNICODE_NOT_PRESENT_OFFSET, 12530 }, { 0xfcd1, G_UNICODE_NOT_PRESENT_OFFSET, 12535 }, { 0xfcd2, G_UNICODE_NOT_PRESENT_OFFSET, 12550 }, { 0xfcd3, G_UNICODE_NOT_PRESENT_OFFSET, 12555 }, { 0xfcd4, G_UNICODE_NOT_PRESENT_OFFSET, 12560 }, { 0xfcd5, G_UNICODE_NOT_PRESENT_OFFSET, 12565 }, { 0xfcd6, G_UNICODE_NOT_PRESENT_OFFSET, 12816 }, { 0xfcd7, G_UNICODE_NOT_PRESENT_OFFSET, 12580 }, { 0xfcd8, G_UNICODE_NOT_PRESENT_OFFSET, 12585 }, { 0xfcd9, G_UNICODE_NOT_PRESENT_OFFSET, 12821 }, { 0xfcda, G_UNICODE_NOT_PRESENT_OFFSET, 12600 }, { 0xfcdb, G_UNICODE_NOT_PRESENT_OFFSET, 12605 }, { 0xfcdc, G_UNICODE_NOT_PRESENT_OFFSET, 12610 }, { 0xfcdd, G_UNICODE_NOT_PRESENT_OFFSET, 12615 }, { 0xfcde, G_UNICODE_NOT_PRESENT_OFFSET, 12826 }, { 0xfcdf, G_UNICODE_NOT_PRESENT_OFFSET, 12186 }, { 0xfce0, G_UNICODE_NOT_PRESENT_OFFSET, 12789 }, { 0xfce1, G_UNICODE_NOT_PRESENT_OFFSET, 12215 }, { 0xfce2, G_UNICODE_NOT_PRESENT_OFFSET, 12796 }, { 0xfce3, G_UNICODE_NOT_PRESENT_OFFSET, 12245 }, { 0xfce4, G_UNICODE_NOT_PRESENT_OFFSET, 12801 }, { 0xfce5, G_UNICODE_NOT_PRESENT_OFFSET, 12265 }, { 0xfce6, G_UNICODE_NOT_PRESENT_OFFSET, 12831 }, { 0xfce7, G_UNICODE_NOT_PRESENT_OFFSET, 12330 }, { 0xfce8, G_UNICODE_NOT_PRESENT_OFFSET, 12836 }, { 0xfce9, G_UNICODE_NOT_PRESENT_OFFSET, 12841 }, { 0xfcea, G_UNICODE_NOT_PRESENT_OFFSET, 12846 }, { 0xfceb, G_UNICODE_NOT_PRESENT_OFFSET, 12470 }, { 0xfcec, G_UNICODE_NOT_PRESENT_OFFSET, 12475 }, { 0xfced, G_UNICODE_NOT_PRESENT_OFFSET, 12505 }, { 0xfcee, G_UNICODE_NOT_PRESENT_OFFSET, 12565 }, { 0xfcef, G_UNICODE_NOT_PRESENT_OFFSET, 12816 }, { 0xfcf0, G_UNICODE_NOT_PRESENT_OFFSET, 12615 }, { 0xfcf1, G_UNICODE_NOT_PRESENT_OFFSET, 12826 }, { 0xfcf2, G_UNICODE_NOT_PRESENT_OFFSET, 12851 }, { 0xfcf3, G_UNICODE_NOT_PRESENT_OFFSET, 12858 }, { 0xfcf4, G_UNICODE_NOT_PRESENT_OFFSET, 12865 }, { 0xfcf5, G_UNICODE_NOT_PRESENT_OFFSET, 12872 }, { 0xfcf6, G_UNICODE_NOT_PRESENT_OFFSET, 12877 }, { 0xfcf7, G_UNICODE_NOT_PRESENT_OFFSET, 12882 }, { 0xfcf8, G_UNICODE_NOT_PRESENT_OFFSET, 12887 }, { 0xfcf9, G_UNICODE_NOT_PRESENT_OFFSET, 12892 }, { 0xfcfa, G_UNICODE_NOT_PRESENT_OFFSET, 12897 }, { 0xfcfb, G_UNICODE_NOT_PRESENT_OFFSET, 12902 }, { 0xfcfc, G_UNICODE_NOT_PRESENT_OFFSET, 12907 }, { 0xfcfd, G_UNICODE_NOT_PRESENT_OFFSET, 12912 }, { 0xfcfe, G_UNICODE_NOT_PRESENT_OFFSET, 12917 }, { 0xfcff, G_UNICODE_NOT_PRESENT_OFFSET, 12922 }, { 0xfd00, G_UNICODE_NOT_PRESENT_OFFSET, 12927 }, { 0xfd01, G_UNICODE_NOT_PRESENT_OFFSET, 12932 }, { 0xfd02, G_UNICODE_NOT_PRESENT_OFFSET, 12937 }, { 0xfd03, G_UNICODE_NOT_PRESENT_OFFSET, 12942 }, { 0xfd04, G_UNICODE_NOT_PRESENT_OFFSET, 12947 }, { 0xfd05, G_UNICODE_NOT_PRESENT_OFFSET, 12952 }, { 0xfd06, G_UNICODE_NOT_PRESENT_OFFSET, 12957 }, { 0xfd07, G_UNICODE_NOT_PRESENT_OFFSET, 12962 }, { 0xfd08, G_UNICODE_NOT_PRESENT_OFFSET, 12967 }, { 0xfd09, G_UNICODE_NOT_PRESENT_OFFSET, 12972 }, { 0xfd0a, G_UNICODE_NOT_PRESENT_OFFSET, 12977 }, { 0xfd0b, G_UNICODE_NOT_PRESENT_OFFSET, 12982 }, { 0xfd0c, G_UNICODE_NOT_PRESENT_OFFSET, 12841 }, { 0xfd0d, G_UNICODE_NOT_PRESENT_OFFSET, 12987 }, { 0xfd0e, G_UNICODE_NOT_PRESENT_OFFSET, 12992 }, { 0xfd0f, G_UNICODE_NOT_PRESENT_OFFSET, 12997 }, { 0xfd10, G_UNICODE_NOT_PRESENT_OFFSET, 13002 }, { 0xfd11, G_UNICODE_NOT_PRESENT_OFFSET, 12872 }, { 0xfd12, G_UNICODE_NOT_PRESENT_OFFSET, 12877 }, { 0xfd13, G_UNICODE_NOT_PRESENT_OFFSET, 12882 }, { 0xfd14, G_UNICODE_NOT_PRESENT_OFFSET, 12887 }, { 0xfd15, G_UNICODE_NOT_PRESENT_OFFSET, 12892 }, { 0xfd16, G_UNICODE_NOT_PRESENT_OFFSET, 12897 }, { 0xfd17, G_UNICODE_NOT_PRESENT_OFFSET, 12902 }, { 0xfd18, G_UNICODE_NOT_PRESENT_OFFSET, 12907 }, { 0xfd19, G_UNICODE_NOT_PRESENT_OFFSET, 12912 }, { 0xfd1a, G_UNICODE_NOT_PRESENT_OFFSET, 12917 }, { 0xfd1b, G_UNICODE_NOT_PRESENT_OFFSET, 12922 }, { 0xfd1c, G_UNICODE_NOT_PRESENT_OFFSET, 12927 }, { 0xfd1d, G_UNICODE_NOT_PRESENT_OFFSET, 12932 }, { 0xfd1e, G_UNICODE_NOT_PRESENT_OFFSET, 12937 }, { 0xfd1f, G_UNICODE_NOT_PRESENT_OFFSET, 12942 }, { 0xfd20, G_UNICODE_NOT_PRESENT_OFFSET, 12947 }, { 0xfd21, G_UNICODE_NOT_PRESENT_OFFSET, 12952 }, { 0xfd22, G_UNICODE_NOT_PRESENT_OFFSET, 12957 }, { 0xfd23, G_UNICODE_NOT_PRESENT_OFFSET, 12962 }, { 0xfd24, G_UNICODE_NOT_PRESENT_OFFSET, 12967 }, { 0xfd25, G_UNICODE_NOT_PRESENT_OFFSET, 12972 }, { 0xfd26, G_UNICODE_NOT_PRESENT_OFFSET, 12977 }, { 0xfd27, G_UNICODE_NOT_PRESENT_OFFSET, 12982 }, { 0xfd28, G_UNICODE_NOT_PRESENT_OFFSET, 12841 }, { 0xfd29, G_UNICODE_NOT_PRESENT_OFFSET, 12987 }, { 0xfd2a, G_UNICODE_NOT_PRESENT_OFFSET, 12992 }, { 0xfd2b, G_UNICODE_NOT_PRESENT_OFFSET, 12997 }, { 0xfd2c, G_UNICODE_NOT_PRESENT_OFFSET, 13002 }, { 0xfd2d, G_UNICODE_NOT_PRESENT_OFFSET, 12972 }, { 0xfd2e, G_UNICODE_NOT_PRESENT_OFFSET, 12977 }, { 0xfd2f, G_UNICODE_NOT_PRESENT_OFFSET, 12982 }, { 0xfd30, G_UNICODE_NOT_PRESENT_OFFSET, 12841 }, { 0xfd31, G_UNICODE_NOT_PRESENT_OFFSET, 12836 }, { 0xfd32, G_UNICODE_NOT_PRESENT_OFFSET, 12846 }, { 0xfd33, G_UNICODE_NOT_PRESENT_OFFSET, 12370 }, { 0xfd34, G_UNICODE_NOT_PRESENT_OFFSET, 12315 }, { 0xfd35, G_UNICODE_NOT_PRESENT_OFFSET, 12320 }, { 0xfd36, G_UNICODE_NOT_PRESENT_OFFSET, 12325 }, { 0xfd37, G_UNICODE_NOT_PRESENT_OFFSET, 12972 }, { 0xfd38, G_UNICODE_NOT_PRESENT_OFFSET, 12977 }, { 0xfd39, G_UNICODE_NOT_PRESENT_OFFSET, 12982 }, { 0xfd3a, G_UNICODE_NOT_PRESENT_OFFSET, 12370 }, { 0xfd3b, G_UNICODE_NOT_PRESENT_OFFSET, 12375 }, { 0xfd3c, G_UNICODE_NOT_PRESENT_OFFSET, 13007 }, { 0xfd3d, G_UNICODE_NOT_PRESENT_OFFSET, 13007 }, { 0xfd50, G_UNICODE_NOT_PRESENT_OFFSET, 13012 }, { 0xfd51, G_UNICODE_NOT_PRESENT_OFFSET, 13019 }, { 0xfd52, G_UNICODE_NOT_PRESENT_OFFSET, 13019 }, { 0xfd53, G_UNICODE_NOT_PRESENT_OFFSET, 13026 }, { 0xfd54, G_UNICODE_NOT_PRESENT_OFFSET, 13033 }, { 0xfd55, G_UNICODE_NOT_PRESENT_OFFSET, 13040 }, { 0xfd56, G_UNICODE_NOT_PRESENT_OFFSET, 13047 }, { 0xfd57, G_UNICODE_NOT_PRESENT_OFFSET, 13054 }, { 0xfd58, G_UNICODE_NOT_PRESENT_OFFSET, 13061 }, { 0xfd59, G_UNICODE_NOT_PRESENT_OFFSET, 13061 }, { 0xfd5a, G_UNICODE_NOT_PRESENT_OFFSET, 13068 }, { 0xfd5b, G_UNICODE_NOT_PRESENT_OFFSET, 13075 }, { 0xfd5c, G_UNICODE_NOT_PRESENT_OFFSET, 13082 }, { 0xfd5d, G_UNICODE_NOT_PRESENT_OFFSET, 13089 }, { 0xfd5e, G_UNICODE_NOT_PRESENT_OFFSET, 13096 }, { 0xfd5f, G_UNICODE_NOT_PRESENT_OFFSET, 13103 }, { 0xfd60, G_UNICODE_NOT_PRESENT_OFFSET, 13103 }, { 0xfd61, G_UNICODE_NOT_PRESENT_OFFSET, 13110 }, { 0xfd62, G_UNICODE_NOT_PRESENT_OFFSET, 13117 }, { 0xfd63, G_UNICODE_NOT_PRESENT_OFFSET, 13117 }, { 0xfd64, G_UNICODE_NOT_PRESENT_OFFSET, 13124 }, { 0xfd65, G_UNICODE_NOT_PRESENT_OFFSET, 13124 }, { 0xfd66, G_UNICODE_NOT_PRESENT_OFFSET, 13131 }, { 0xfd67, G_UNICODE_NOT_PRESENT_OFFSET, 13138 }, { 0xfd68, G_UNICODE_NOT_PRESENT_OFFSET, 13138 }, { 0xfd69, G_UNICODE_NOT_PRESENT_OFFSET, 13145 }, { 0xfd6a, G_UNICODE_NOT_PRESENT_OFFSET, 13152 }, { 0xfd6b, G_UNICODE_NOT_PRESENT_OFFSET, 13152 }, { 0xfd6c, G_UNICODE_NOT_PRESENT_OFFSET, 13159 }, { 0xfd6d, G_UNICODE_NOT_PRESENT_OFFSET, 13159 }, { 0xfd6e, G_UNICODE_NOT_PRESENT_OFFSET, 13166 }, { 0xfd6f, G_UNICODE_NOT_PRESENT_OFFSET, 13173 }, { 0xfd70, G_UNICODE_NOT_PRESENT_OFFSET, 13173 }, { 0xfd71, G_UNICODE_NOT_PRESENT_OFFSET, 13180 }, { 0xfd72, G_UNICODE_NOT_PRESENT_OFFSET, 13180 }, { 0xfd73, G_UNICODE_NOT_PRESENT_OFFSET, 13187 }, { 0xfd74, G_UNICODE_NOT_PRESENT_OFFSET, 13194 }, { 0xfd75, G_UNICODE_NOT_PRESENT_OFFSET, 13201 }, { 0xfd76, G_UNICODE_NOT_PRESENT_OFFSET, 13208 }, { 0xfd77, G_UNICODE_NOT_PRESENT_OFFSET, 13208 }, { 0xfd78, G_UNICODE_NOT_PRESENT_OFFSET, 13215 }, { 0xfd79, G_UNICODE_NOT_PRESENT_OFFSET, 13222 }, { 0xfd7a, G_UNICODE_NOT_PRESENT_OFFSET, 13229 }, { 0xfd7b, G_UNICODE_NOT_PRESENT_OFFSET, 13236 }, { 0xfd7c, G_UNICODE_NOT_PRESENT_OFFSET, 13243 }, { 0xfd7d, G_UNICODE_NOT_PRESENT_OFFSET, 13243 }, { 0xfd7e, G_UNICODE_NOT_PRESENT_OFFSET, 13250 }, { 0xfd7f, G_UNICODE_NOT_PRESENT_OFFSET, 13257 }, { 0xfd80, G_UNICODE_NOT_PRESENT_OFFSET, 13264 }, { 0xfd81, G_UNICODE_NOT_PRESENT_OFFSET, 13271 }, { 0xfd82, G_UNICODE_NOT_PRESENT_OFFSET, 13278 }, { 0xfd83, G_UNICODE_NOT_PRESENT_OFFSET, 13285 }, { 0xfd84, G_UNICODE_NOT_PRESENT_OFFSET, 13285 }, { 0xfd85, G_UNICODE_NOT_PRESENT_OFFSET, 13292 }, { 0xfd86, G_UNICODE_NOT_PRESENT_OFFSET, 13292 }, { 0xfd87, G_UNICODE_NOT_PRESENT_OFFSET, 13299 }, { 0xfd88, G_UNICODE_NOT_PRESENT_OFFSET, 13299 }, { 0xfd89, G_UNICODE_NOT_PRESENT_OFFSET, 13306 }, { 0xfd8a, G_UNICODE_NOT_PRESENT_OFFSET, 13313 }, { 0xfd8b, G_UNICODE_NOT_PRESENT_OFFSET, 13320 }, { 0xfd8c, G_UNICODE_NOT_PRESENT_OFFSET, 13327 }, { 0xfd8d, G_UNICODE_NOT_PRESENT_OFFSET, 13334 }, { 0xfd8e, G_UNICODE_NOT_PRESENT_OFFSET, 13341 }, { 0xfd8f, G_UNICODE_NOT_PRESENT_OFFSET, 13348 }, { 0xfd92, G_UNICODE_NOT_PRESENT_OFFSET, 13355 }, { 0xfd93, G_UNICODE_NOT_PRESENT_OFFSET, 13362 }, { 0xfd94, G_UNICODE_NOT_PRESENT_OFFSET, 13369 }, { 0xfd95, G_UNICODE_NOT_PRESENT_OFFSET, 13376 }, { 0xfd96, G_UNICODE_NOT_PRESENT_OFFSET, 13383 }, { 0xfd97, G_UNICODE_NOT_PRESENT_OFFSET, 13390 }, { 0xfd98, G_UNICODE_NOT_PRESENT_OFFSET, 13390 }, { 0xfd99, G_UNICODE_NOT_PRESENT_OFFSET, 13397 }, { 0xfd9a, G_UNICODE_NOT_PRESENT_OFFSET, 13404 }, { 0xfd9b, G_UNICODE_NOT_PRESENT_OFFSET, 13411 }, { 0xfd9c, G_UNICODE_NOT_PRESENT_OFFSET, 13418 }, { 0xfd9d, G_UNICODE_NOT_PRESENT_OFFSET, 13418 }, { 0xfd9e, G_UNICODE_NOT_PRESENT_OFFSET, 13425 }, { 0xfd9f, G_UNICODE_NOT_PRESENT_OFFSET, 13432 }, { 0xfda0, G_UNICODE_NOT_PRESENT_OFFSET, 13439 }, { 0xfda1, G_UNICODE_NOT_PRESENT_OFFSET, 13446 }, { 0xfda2, G_UNICODE_NOT_PRESENT_OFFSET, 13453 }, { 0xfda3, G_UNICODE_NOT_PRESENT_OFFSET, 13460 }, { 0xfda4, G_UNICODE_NOT_PRESENT_OFFSET, 13467 }, { 0xfda5, G_UNICODE_NOT_PRESENT_OFFSET, 13474 }, { 0xfda6, G_UNICODE_NOT_PRESENT_OFFSET, 13481 }, { 0xfda7, G_UNICODE_NOT_PRESENT_OFFSET, 13488 }, { 0xfda8, G_UNICODE_NOT_PRESENT_OFFSET, 13495 }, { 0xfda9, G_UNICODE_NOT_PRESENT_OFFSET, 13502 }, { 0xfdaa, G_UNICODE_NOT_PRESENT_OFFSET, 13509 }, { 0xfdab, G_UNICODE_NOT_PRESENT_OFFSET, 13516 }, { 0xfdac, G_UNICODE_NOT_PRESENT_OFFSET, 13523 }, { 0xfdad, G_UNICODE_NOT_PRESENT_OFFSET, 13530 }, { 0xfdae, G_UNICODE_NOT_PRESENT_OFFSET, 13537 }, { 0xfdaf, G_UNICODE_NOT_PRESENT_OFFSET, 13544 }, { 0xfdb0, G_UNICODE_NOT_PRESENT_OFFSET, 13551 }, { 0xfdb1, G_UNICODE_NOT_PRESENT_OFFSET, 13558 }, { 0xfdb2, G_UNICODE_NOT_PRESENT_OFFSET, 13565 }, { 0xfdb3, G_UNICODE_NOT_PRESENT_OFFSET, 13572 }, { 0xfdb4, G_UNICODE_NOT_PRESENT_OFFSET, 13250 }, { 0xfdb5, G_UNICODE_NOT_PRESENT_OFFSET, 13264 }, { 0xfdb6, G_UNICODE_NOT_PRESENT_OFFSET, 13579 }, { 0xfdb7, G_UNICODE_NOT_PRESENT_OFFSET, 13586 }, { 0xfdb8, G_UNICODE_NOT_PRESENT_OFFSET, 13593 }, { 0xfdb9, G_UNICODE_NOT_PRESENT_OFFSET, 13600 }, { 0xfdba, G_UNICODE_NOT_PRESENT_OFFSET, 13607 }, { 0xfdbb, G_UNICODE_NOT_PRESENT_OFFSET, 13614 }, { 0xfdbc, G_UNICODE_NOT_PRESENT_OFFSET, 13607 }, { 0xfdbd, G_UNICODE_NOT_PRESENT_OFFSET, 13593 }, { 0xfdbe, G_UNICODE_NOT_PRESENT_OFFSET, 13621 }, { 0xfdbf, G_UNICODE_NOT_PRESENT_OFFSET, 13628 }, { 0xfdc0, G_UNICODE_NOT_PRESENT_OFFSET, 13635 }, { 0xfdc1, G_UNICODE_NOT_PRESENT_OFFSET, 13642 }, { 0xfdc2, G_UNICODE_NOT_PRESENT_OFFSET, 13649 }, { 0xfdc3, G_UNICODE_NOT_PRESENT_OFFSET, 13614 }, { 0xfdc4, G_UNICODE_NOT_PRESENT_OFFSET, 13201 }, { 0xfdc5, G_UNICODE_NOT_PRESENT_OFFSET, 13131 }, { 0xfdc6, G_UNICODE_NOT_PRESENT_OFFSET, 13656 }, { 0xfdc7, G_UNICODE_NOT_PRESENT_OFFSET, 13663 }, { 0xfdf0, G_UNICODE_NOT_PRESENT_OFFSET, 13670 }, { 0xfdf1, G_UNICODE_NOT_PRESENT_OFFSET, 13677 }, { 0xfdf2, G_UNICODE_NOT_PRESENT_OFFSET, 13684 }, { 0xfdf3, G_UNICODE_NOT_PRESENT_OFFSET, 13693 }, { 0xfdf4, G_UNICODE_NOT_PRESENT_OFFSET, 13702 }, { 0xfdf5, G_UNICODE_NOT_PRESENT_OFFSET, 13711 }, { 0xfdf6, G_UNICODE_NOT_PRESENT_OFFSET, 13720 }, { 0xfdf7, G_UNICODE_NOT_PRESENT_OFFSET, 13729 }, { 0xfdf8, G_UNICODE_NOT_PRESENT_OFFSET, 13738 }, { 0xfdf9, G_UNICODE_NOT_PRESENT_OFFSET, 13747 }, { 0xfdfa, G_UNICODE_NOT_PRESENT_OFFSET, 13754 }, { 0xfdfb, G_UNICODE_NOT_PRESENT_OFFSET, 13788 }, { 0xfdfc, G_UNICODE_NOT_PRESENT_OFFSET, 13804 }, { 0xfe30, G_UNICODE_NOT_PRESENT_OFFSET, 4871 }, { 0xfe31, G_UNICODE_NOT_PRESENT_OFFSET, 13813 }, { 0xfe32, G_UNICODE_NOT_PRESENT_OFFSET, 13817 }, { 0xfe33, G_UNICODE_NOT_PRESENT_OFFSET, 13821 }, { 0xfe34, G_UNICODE_NOT_PRESENT_OFFSET, 13821 }, { 0xfe35, G_UNICODE_NOT_PRESENT_OFFSET, 4965 }, { 0xfe36, G_UNICODE_NOT_PRESENT_OFFSET, 4967 }, { 0xfe37, G_UNICODE_NOT_PRESENT_OFFSET, 13823 }, { 0xfe38, G_UNICODE_NOT_PRESENT_OFFSET, 13825 }, { 0xfe39, G_UNICODE_NOT_PRESENT_OFFSET, 13827 }, { 0xfe3a, G_UNICODE_NOT_PRESENT_OFFSET, 13831 }, { 0xfe3b, G_UNICODE_NOT_PRESENT_OFFSET, 13835 }, { 0xfe3c, G_UNICODE_NOT_PRESENT_OFFSET, 13839 }, { 0xfe3d, G_UNICODE_NOT_PRESENT_OFFSET, 13843 }, { 0xfe3e, G_UNICODE_NOT_PRESENT_OFFSET, 13847 }, { 0xfe3f, G_UNICODE_NOT_PRESENT_OFFSET, 5524 }, { 0xfe40, G_UNICODE_NOT_PRESENT_OFFSET, 5528 }, { 0xfe41, G_UNICODE_NOT_PRESENT_OFFSET, 13851 }, { 0xfe42, G_UNICODE_NOT_PRESENT_OFFSET, 13855 }, { 0xfe43, G_UNICODE_NOT_PRESENT_OFFSET, 13859 }, { 0xfe44, G_UNICODE_NOT_PRESENT_OFFSET, 13863 }, { 0xfe49, G_UNICODE_NOT_PRESENT_OFFSET, 4915 }, { 0xfe4a, G_UNICODE_NOT_PRESENT_OFFSET, 4915 }, { 0xfe4b, G_UNICODE_NOT_PRESENT_OFFSET, 4915 }, { 0xfe4c, G_UNICODE_NOT_PRESENT_OFFSET, 4915 }, { 0xfe4d, G_UNICODE_NOT_PRESENT_OFFSET, 13821 }, { 0xfe4e, G_UNICODE_NOT_PRESENT_OFFSET, 13821 }, { 0xfe4f, G_UNICODE_NOT_PRESENT_OFFSET, 13821 }, { 0xfe50, G_UNICODE_NOT_PRESENT_OFFSET, 13867 }, { 0xfe51, G_UNICODE_NOT_PRESENT_OFFSET, 13869 }, { 0xfe52, G_UNICODE_NOT_PRESENT_OFFSET, 4869 }, { 0xfe54, G_UNICODE_NOT_PRESENT_OFFSET, 1248 }, { 0xfe55, G_UNICODE_NOT_PRESENT_OFFSET, 13873 }, { 0xfe56, G_UNICODE_NOT_PRESENT_OFFSET, 13875 }, { 0xfe57, G_UNICODE_NOT_PRESENT_OFFSET, 13877 }, { 0xfe58, G_UNICODE_NOT_PRESENT_OFFSET, 13813 }, { 0xfe59, G_UNICODE_NOT_PRESENT_OFFSET, 4965 }, { 0xfe5a, G_UNICODE_NOT_PRESENT_OFFSET, 4967 }, { 0xfe5b, G_UNICODE_NOT_PRESENT_OFFSET, 13823 }, { 0xfe5c, G_UNICODE_NOT_PRESENT_OFFSET, 13825 }, { 0xfe5d, G_UNICODE_NOT_PRESENT_OFFSET, 13827 }, { 0xfe5e, G_UNICODE_NOT_PRESENT_OFFSET, 13831 }, { 0xfe5f, G_UNICODE_NOT_PRESENT_OFFSET, 13879 }, { 0xfe60, G_UNICODE_NOT_PRESENT_OFFSET, 13881 }, { 0xfe61, G_UNICODE_NOT_PRESENT_OFFSET, 13883 }, { 0xfe62, G_UNICODE_NOT_PRESENT_OFFSET, 4957 }, { 0xfe63, G_UNICODE_NOT_PRESENT_OFFSET, 13885 }, { 0xfe64, G_UNICODE_NOT_PRESENT_OFFSET, 13887 }, { 0xfe65, G_UNICODE_NOT_PRESENT_OFFSET, 13889 }, { 0xfe66, G_UNICODE_NOT_PRESENT_OFFSET, 4963 }, { 0xfe68, G_UNICODE_NOT_PRESENT_OFFSET, 13891 }, { 0xfe69, G_UNICODE_NOT_PRESENT_OFFSET, 13893 }, { 0xfe6a, G_UNICODE_NOT_PRESENT_OFFSET, 13895 }, { 0xfe6b, G_UNICODE_NOT_PRESENT_OFFSET, 13897 }, { 0xfe70, G_UNICODE_NOT_PRESENT_OFFSET, 13899 }, { 0xfe71, G_UNICODE_NOT_PRESENT_OFFSET, 13903 }, { 0xfe72, G_UNICODE_NOT_PRESENT_OFFSET, 13908 }, { 0xfe74, G_UNICODE_NOT_PRESENT_OFFSET, 13912 }, { 0xfe76, G_UNICODE_NOT_PRESENT_OFFSET, 13916 }, { 0xfe77, G_UNICODE_NOT_PRESENT_OFFSET, 13920 }, { 0xfe78, G_UNICODE_NOT_PRESENT_OFFSET, 13925 }, { 0xfe79, G_UNICODE_NOT_PRESENT_OFFSET, 13929 }, { 0xfe7a, G_UNICODE_NOT_PRESENT_OFFSET, 13934 }, { 0xfe7b, G_UNICODE_NOT_PRESENT_OFFSET, 13938 }, { 0xfe7c, G_UNICODE_NOT_PRESENT_OFFSET, 13943 }, { 0xfe7d, G_UNICODE_NOT_PRESENT_OFFSET, 13947 }, { 0xfe7e, G_UNICODE_NOT_PRESENT_OFFSET, 13952 }, { 0xfe7f, G_UNICODE_NOT_PRESENT_OFFSET, 13956 }, { 0xfe80, G_UNICODE_NOT_PRESENT_OFFSET, 13961 }, { 0xfe81, G_UNICODE_NOT_PRESENT_OFFSET, 1673 }, { 0xfe82, G_UNICODE_NOT_PRESENT_OFFSET, 1673 }, { 0xfe83, G_UNICODE_NOT_PRESENT_OFFSET, 1678 }, { 0xfe84, G_UNICODE_NOT_PRESENT_OFFSET, 1678 }, { 0xfe85, G_UNICODE_NOT_PRESENT_OFFSET, 1683 }, { 0xfe86, G_UNICODE_NOT_PRESENT_OFFSET, 1683 }, { 0xfe87, G_UNICODE_NOT_PRESENT_OFFSET, 1688 }, { 0xfe88, G_UNICODE_NOT_PRESENT_OFFSET, 1688 }, { 0xfe89, G_UNICODE_NOT_PRESENT_OFFSET, 1693 }, { 0xfe8a, G_UNICODE_NOT_PRESENT_OFFSET, 1693 }, { 0xfe8b, G_UNICODE_NOT_PRESENT_OFFSET, 1693 }, { 0xfe8c, G_UNICODE_NOT_PRESENT_OFFSET, 1693 }, { 0xfe8d, G_UNICODE_NOT_PRESENT_OFFSET, 13964 }, { 0xfe8e, G_UNICODE_NOT_PRESENT_OFFSET, 13964 }, { 0xfe8f, G_UNICODE_NOT_PRESENT_OFFSET, 13967 }, { 0xfe90, G_UNICODE_NOT_PRESENT_OFFSET, 13967 }, { 0xfe91, G_UNICODE_NOT_PRESENT_OFFSET, 13967 }, { 0xfe92, G_UNICODE_NOT_PRESENT_OFFSET, 13967 }, { 0xfe93, G_UNICODE_NOT_PRESENT_OFFSET, 13970 }, { 0xfe94, G_UNICODE_NOT_PRESENT_OFFSET, 13970 }, { 0xfe95, G_UNICODE_NOT_PRESENT_OFFSET, 13973 }, { 0xfe96, G_UNICODE_NOT_PRESENT_OFFSET, 13973 }, { 0xfe97, G_UNICODE_NOT_PRESENT_OFFSET, 13973 }, { 0xfe98, G_UNICODE_NOT_PRESENT_OFFSET, 13973 }, { 0xfe99, G_UNICODE_NOT_PRESENT_OFFSET, 13976 }, { 0xfe9a, G_UNICODE_NOT_PRESENT_OFFSET, 13976 }, { 0xfe9b, G_UNICODE_NOT_PRESENT_OFFSET, 13976 }, { 0xfe9c, G_UNICODE_NOT_PRESENT_OFFSET, 13976 }, { 0xfe9d, G_UNICODE_NOT_PRESENT_OFFSET, 13979 }, { 0xfe9e, G_UNICODE_NOT_PRESENT_OFFSET, 13979 }, { 0xfe9f, G_UNICODE_NOT_PRESENT_OFFSET, 13979 }, { 0xfea0, G_UNICODE_NOT_PRESENT_OFFSET, 13979 }, { 0xfea1, G_UNICODE_NOT_PRESENT_OFFSET, 13982 }, { 0xfea2, G_UNICODE_NOT_PRESENT_OFFSET, 13982 }, { 0xfea3, G_UNICODE_NOT_PRESENT_OFFSET, 13982 }, { 0xfea4, G_UNICODE_NOT_PRESENT_OFFSET, 13982 }, { 0xfea5, G_UNICODE_NOT_PRESENT_OFFSET, 13985 }, { 0xfea6, G_UNICODE_NOT_PRESENT_OFFSET, 13985 }, { 0xfea7, G_UNICODE_NOT_PRESENT_OFFSET, 13985 }, { 0xfea8, G_UNICODE_NOT_PRESENT_OFFSET, 13985 }, { 0xfea9, G_UNICODE_NOT_PRESENT_OFFSET, 13988 }, { 0xfeaa, G_UNICODE_NOT_PRESENT_OFFSET, 13988 }, { 0xfeab, G_UNICODE_NOT_PRESENT_OFFSET, 13991 }, { 0xfeac, G_UNICODE_NOT_PRESENT_OFFSET, 13991 }, { 0xfead, G_UNICODE_NOT_PRESENT_OFFSET, 13994 }, { 0xfeae, G_UNICODE_NOT_PRESENT_OFFSET, 13994 }, { 0xfeaf, G_UNICODE_NOT_PRESENT_OFFSET, 13997 }, { 0xfeb0, G_UNICODE_NOT_PRESENT_OFFSET, 13997 }, { 0xfeb1, G_UNICODE_NOT_PRESENT_OFFSET, 14000 }, { 0xfeb2, G_UNICODE_NOT_PRESENT_OFFSET, 14000 }, { 0xfeb3, G_UNICODE_NOT_PRESENT_OFFSET, 14000 }, { 0xfeb4, G_UNICODE_NOT_PRESENT_OFFSET, 14000 }, { 0xfeb5, G_UNICODE_NOT_PRESENT_OFFSET, 14003 }, { 0xfeb6, G_UNICODE_NOT_PRESENT_OFFSET, 14003 }, { 0xfeb7, G_UNICODE_NOT_PRESENT_OFFSET, 14003 }, { 0xfeb8, G_UNICODE_NOT_PRESENT_OFFSET, 14003 }, { 0xfeb9, G_UNICODE_NOT_PRESENT_OFFSET, 14006 }, { 0xfeba, G_UNICODE_NOT_PRESENT_OFFSET, 14006 }, { 0xfebb, G_UNICODE_NOT_PRESENT_OFFSET, 14006 }, { 0xfebc, G_UNICODE_NOT_PRESENT_OFFSET, 14006 }, { 0xfebd, G_UNICODE_NOT_PRESENT_OFFSET, 14009 }, { 0xfebe, G_UNICODE_NOT_PRESENT_OFFSET, 14009 }, { 0xfebf, G_UNICODE_NOT_PRESENT_OFFSET, 14009 }, { 0xfec0, G_UNICODE_NOT_PRESENT_OFFSET, 14009 }, { 0xfec1, G_UNICODE_NOT_PRESENT_OFFSET, 14012 }, { 0xfec2, G_UNICODE_NOT_PRESENT_OFFSET, 14012 }, { 0xfec3, G_UNICODE_NOT_PRESENT_OFFSET, 14012 }, { 0xfec4, G_UNICODE_NOT_PRESENT_OFFSET, 14012 }, { 0xfec5, G_UNICODE_NOT_PRESENT_OFFSET, 14015 }, { 0xfec6, G_UNICODE_NOT_PRESENT_OFFSET, 14015 }, { 0xfec7, G_UNICODE_NOT_PRESENT_OFFSET, 14015 }, { 0xfec8, G_UNICODE_NOT_PRESENT_OFFSET, 14015 }, { 0xfec9, G_UNICODE_NOT_PRESENT_OFFSET, 14018 }, { 0xfeca, G_UNICODE_NOT_PRESENT_OFFSET, 14018 }, { 0xfecb, G_UNICODE_NOT_PRESENT_OFFSET, 14018 }, { 0xfecc, G_UNICODE_NOT_PRESENT_OFFSET, 14018 }, { 0xfecd, G_UNICODE_NOT_PRESENT_OFFSET, 14021 }, { 0xfece, G_UNICODE_NOT_PRESENT_OFFSET, 14021 }, { 0xfecf, G_UNICODE_NOT_PRESENT_OFFSET, 14021 }, { 0xfed0, G_UNICODE_NOT_PRESENT_OFFSET, 14021 }, { 0xfed1, G_UNICODE_NOT_PRESENT_OFFSET, 14024 }, { 0xfed2, G_UNICODE_NOT_PRESENT_OFFSET, 14024 }, { 0xfed3, G_UNICODE_NOT_PRESENT_OFFSET, 14024 }, { 0xfed4, G_UNICODE_NOT_PRESENT_OFFSET, 14024 }, { 0xfed5, G_UNICODE_NOT_PRESENT_OFFSET, 14027 }, { 0xfed6, G_UNICODE_NOT_PRESENT_OFFSET, 14027 }, { 0xfed7, G_UNICODE_NOT_PRESENT_OFFSET, 14027 }, { 0xfed8, G_UNICODE_NOT_PRESENT_OFFSET, 14027 }, { 0xfed9, G_UNICODE_NOT_PRESENT_OFFSET, 14030 }, { 0xfeda, G_UNICODE_NOT_PRESENT_OFFSET, 14030 }, { 0xfedb, G_UNICODE_NOT_PRESENT_OFFSET, 14030 }, { 0xfedc, G_UNICODE_NOT_PRESENT_OFFSET, 14030 }, { 0xfedd, G_UNICODE_NOT_PRESENT_OFFSET, 14033 }, { 0xfede, G_UNICODE_NOT_PRESENT_OFFSET, 14033 }, { 0xfedf, G_UNICODE_NOT_PRESENT_OFFSET, 14033 }, { 0xfee0, G_UNICODE_NOT_PRESENT_OFFSET, 14033 }, { 0xfee1, G_UNICODE_NOT_PRESENT_OFFSET, 14036 }, { 0xfee2, G_UNICODE_NOT_PRESENT_OFFSET, 14036 }, { 0xfee3, G_UNICODE_NOT_PRESENT_OFFSET, 14036 }, { 0xfee4, G_UNICODE_NOT_PRESENT_OFFSET, 14036 }, { 0xfee5, G_UNICODE_NOT_PRESENT_OFFSET, 14039 }, { 0xfee6, G_UNICODE_NOT_PRESENT_OFFSET, 14039 }, { 0xfee7, G_UNICODE_NOT_PRESENT_OFFSET, 14039 }, { 0xfee8, G_UNICODE_NOT_PRESENT_OFFSET, 14039 }, { 0xfee9, G_UNICODE_NOT_PRESENT_OFFSET, 14042 }, { 0xfeea, G_UNICODE_NOT_PRESENT_OFFSET, 14042 }, { 0xfeeb, G_UNICODE_NOT_PRESENT_OFFSET, 14042 }, { 0xfeec, G_UNICODE_NOT_PRESENT_OFFSET, 14042 }, { 0xfeed, G_UNICODE_NOT_PRESENT_OFFSET, 14045 }, { 0xfeee, G_UNICODE_NOT_PRESENT_OFFSET, 14045 }, { 0xfeef, G_UNICODE_NOT_PRESENT_OFFSET, 12110 }, { 0xfef0, G_UNICODE_NOT_PRESENT_OFFSET, 12110 }, { 0xfef1, G_UNICODE_NOT_PRESENT_OFFSET, 14048 }, { 0xfef2, G_UNICODE_NOT_PRESENT_OFFSET, 14048 }, { 0xfef3, G_UNICODE_NOT_PRESENT_OFFSET, 14048 }, { 0xfef4, G_UNICODE_NOT_PRESENT_OFFSET, 14048 }, { 0xfef5, G_UNICODE_NOT_PRESENT_OFFSET, 14051 }, { 0xfef6, G_UNICODE_NOT_PRESENT_OFFSET, 14051 }, { 0xfef7, G_UNICODE_NOT_PRESENT_OFFSET, 14058 }, { 0xfef8, G_UNICODE_NOT_PRESENT_OFFSET, 14058 }, { 0xfef9, G_UNICODE_NOT_PRESENT_OFFSET, 14065 }, { 0xfefa, G_UNICODE_NOT_PRESENT_OFFSET, 14065 }, { 0xfefb, G_UNICODE_NOT_PRESENT_OFFSET, 14072 }, { 0xfefc, G_UNICODE_NOT_PRESENT_OFFSET, 14072 }, { 0xff01, G_UNICODE_NOT_PRESENT_OFFSET, 13877 }, { 0xff02, G_UNICODE_NOT_PRESENT_OFFSET, 14077 }, { 0xff03, G_UNICODE_NOT_PRESENT_OFFSET, 13879 }, { 0xff04, G_UNICODE_NOT_PRESENT_OFFSET, 13893 }, { 0xff05, G_UNICODE_NOT_PRESENT_OFFSET, 13895 }, { 0xff06, G_UNICODE_NOT_PRESENT_OFFSET, 13881 }, { 0xff07, G_UNICODE_NOT_PRESENT_OFFSET, 14079 }, { 0xff08, G_UNICODE_NOT_PRESENT_OFFSET, 4965 }, { 0xff09, G_UNICODE_NOT_PRESENT_OFFSET, 4967 }, { 0xff0a, G_UNICODE_NOT_PRESENT_OFFSET, 13883 }, { 0xff0b, G_UNICODE_NOT_PRESENT_OFFSET, 4957 }, { 0xff0c, G_UNICODE_NOT_PRESENT_OFFSET, 13867 }, { 0xff0d, G_UNICODE_NOT_PRESENT_OFFSET, 13885 }, { 0xff0e, G_UNICODE_NOT_PRESENT_OFFSET, 4869 }, { 0xff0f, G_UNICODE_NOT_PRESENT_OFFSET, 14081 }, { 0xff10, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0xff11, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0xff12, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0xff13, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0xff14, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0xff15, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0xff16, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0xff17, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0xff18, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0xff19, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0xff1a, G_UNICODE_NOT_PRESENT_OFFSET, 13873 }, { 0xff1b, G_UNICODE_NOT_PRESENT_OFFSET, 1248 }, { 0xff1c, G_UNICODE_NOT_PRESENT_OFFSET, 13887 }, { 0xff1d, G_UNICODE_NOT_PRESENT_OFFSET, 4963 }, { 0xff1e, G_UNICODE_NOT_PRESENT_OFFSET, 13889 }, { 0xff1f, G_UNICODE_NOT_PRESENT_OFFSET, 13875 }, { 0xff20, G_UNICODE_NOT_PRESENT_OFFSET, 13897 }, { 0xff21, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0xff22, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0xff23, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0xff24, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0xff25, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0xff26, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0xff27, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0xff28, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0xff29, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0xff2a, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0xff2b, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0xff2c, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0xff2d, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0xff2e, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0xff2f, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0xff30, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0xff31, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0xff32, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0xff33, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0xff34, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0xff35, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0xff36, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0xff37, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0xff38, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0xff39, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0xff3a, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0xff3b, G_UNICODE_NOT_PRESENT_OFFSET, 14083 }, { 0xff3c, G_UNICODE_NOT_PRESENT_OFFSET, 13891 }, { 0xff3d, G_UNICODE_NOT_PRESENT_OFFSET, 14085 }, { 0xff3e, G_UNICODE_NOT_PRESENT_OFFSET, 14087 }, { 0xff3f, G_UNICODE_NOT_PRESENT_OFFSET, 13821 }, { 0xff40, G_UNICODE_NOT_PRESENT_OFFSET, 4798 }, { 0xff41, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0xff42, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0xff43, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0xff44, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0xff45, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0xff46, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0xff47, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0xff48, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0xff49, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0xff4a, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0xff4b, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0xff4c, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0xff4d, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0xff4e, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0xff4f, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0xff50, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0xff51, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0xff52, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0xff53, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0xff54, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0xff55, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0xff56, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0xff57, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0xff58, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0xff59, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0xff5a, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0xff5b, G_UNICODE_NOT_PRESENT_OFFSET, 13823 }, { 0xff5c, G_UNICODE_NOT_PRESENT_OFFSET, 14089 }, { 0xff5d, G_UNICODE_NOT_PRESENT_OFFSET, 13825 }, { 0xff5e, G_UNICODE_NOT_PRESENT_OFFSET, 14091 }, { 0xff5f, G_UNICODE_NOT_PRESENT_OFFSET, 14093 }, { 0xff60, G_UNICODE_NOT_PRESENT_OFFSET, 14097 }, { 0xff61, G_UNICODE_NOT_PRESENT_OFFSET, 14101 }, { 0xff62, G_UNICODE_NOT_PRESENT_OFFSET, 13851 }, { 0xff63, G_UNICODE_NOT_PRESENT_OFFSET, 13855 }, { 0xff64, G_UNICODE_NOT_PRESENT_OFFSET, 13869 }, { 0xff65, G_UNICODE_NOT_PRESENT_OFFSET, 14105 }, { 0xff66, G_UNICODE_NOT_PRESENT_OFFSET, 8615 }, { 0xff67, G_UNICODE_NOT_PRESENT_OFFSET, 14109 }, { 0xff68, G_UNICODE_NOT_PRESENT_OFFSET, 14113 }, { 0xff69, G_UNICODE_NOT_PRESENT_OFFSET, 14117 }, { 0xff6a, G_UNICODE_NOT_PRESENT_OFFSET, 14121 }, { 0xff6b, G_UNICODE_NOT_PRESENT_OFFSET, 14125 }, { 0xff6c, G_UNICODE_NOT_PRESENT_OFFSET, 14129 }, { 0xff6d, G_UNICODE_NOT_PRESENT_OFFSET, 14133 }, { 0xff6e, G_UNICODE_NOT_PRESENT_OFFSET, 14137 }, { 0xff6f, G_UNICODE_NOT_PRESENT_OFFSET, 14141 }, { 0xff70, G_UNICODE_NOT_PRESENT_OFFSET, 14145 }, { 0xff71, G_UNICODE_NOT_PRESENT_OFFSET, 8431 }, { 0xff72, G_UNICODE_NOT_PRESENT_OFFSET, 8435 }, { 0xff73, G_UNICODE_NOT_PRESENT_OFFSET, 8439 }, { 0xff74, G_UNICODE_NOT_PRESENT_OFFSET, 8443 }, { 0xff75, G_UNICODE_NOT_PRESENT_OFFSET, 8447 }, { 0xff76, G_UNICODE_NOT_PRESENT_OFFSET, 8451 }, { 0xff77, G_UNICODE_NOT_PRESENT_OFFSET, 8455 }, { 0xff78, G_UNICODE_NOT_PRESENT_OFFSET, 8459 }, { 0xff79, G_UNICODE_NOT_PRESENT_OFFSET, 8463 }, { 0xff7a, G_UNICODE_NOT_PRESENT_OFFSET, 8467 }, { 0xff7b, G_UNICODE_NOT_PRESENT_OFFSET, 8471 }, { 0xff7c, G_UNICODE_NOT_PRESENT_OFFSET, 8475 }, { 0xff7d, G_UNICODE_NOT_PRESENT_OFFSET, 8479 }, { 0xff7e, G_UNICODE_NOT_PRESENT_OFFSET, 8483 }, { 0xff7f, G_UNICODE_NOT_PRESENT_OFFSET, 8487 }, { 0xff80, G_UNICODE_NOT_PRESENT_OFFSET, 8491 }, { 0xff81, G_UNICODE_NOT_PRESENT_OFFSET, 8495 }, { 0xff82, G_UNICODE_NOT_PRESENT_OFFSET, 8499 }, { 0xff83, G_UNICODE_NOT_PRESENT_OFFSET, 8503 }, { 0xff84, G_UNICODE_NOT_PRESENT_OFFSET, 8507 }, { 0xff85, G_UNICODE_NOT_PRESENT_OFFSET, 8511 }, { 0xff86, G_UNICODE_NOT_PRESENT_OFFSET, 8515 }, { 0xff87, G_UNICODE_NOT_PRESENT_OFFSET, 8519 }, { 0xff88, G_UNICODE_NOT_PRESENT_OFFSET, 8523 }, { 0xff89, G_UNICODE_NOT_PRESENT_OFFSET, 8527 }, { 0xff8a, G_UNICODE_NOT_PRESENT_OFFSET, 8531 }, { 0xff8b, G_UNICODE_NOT_PRESENT_OFFSET, 8535 }, { 0xff8c, G_UNICODE_NOT_PRESENT_OFFSET, 8539 }, { 0xff8d, G_UNICODE_NOT_PRESENT_OFFSET, 8543 }, { 0xff8e, G_UNICODE_NOT_PRESENT_OFFSET, 8547 }, { 0xff8f, G_UNICODE_NOT_PRESENT_OFFSET, 8551 }, { 0xff90, G_UNICODE_NOT_PRESENT_OFFSET, 8555 }, { 0xff91, G_UNICODE_NOT_PRESENT_OFFSET, 8559 }, { 0xff92, G_UNICODE_NOT_PRESENT_OFFSET, 8563 }, { 0xff93, G_UNICODE_NOT_PRESENT_OFFSET, 8567 }, { 0xff94, G_UNICODE_NOT_PRESENT_OFFSET, 8571 }, { 0xff95, G_UNICODE_NOT_PRESENT_OFFSET, 8575 }, { 0xff96, G_UNICODE_NOT_PRESENT_OFFSET, 8579 }, { 0xff97, G_UNICODE_NOT_PRESENT_OFFSET, 8583 }, { 0xff98, G_UNICODE_NOT_PRESENT_OFFSET, 8587 }, { 0xff99, G_UNICODE_NOT_PRESENT_OFFSET, 8591 }, { 0xff9a, G_UNICODE_NOT_PRESENT_OFFSET, 8595 }, { 0xff9b, G_UNICODE_NOT_PRESENT_OFFSET, 8599 }, { 0xff9c, G_UNICODE_NOT_PRESENT_OFFSET, 8603 }, { 0xff9d, G_UNICODE_NOT_PRESENT_OFFSET, 14149 }, { 0xff9e, G_UNICODE_NOT_PRESENT_OFFSET, 14153 }, { 0xff9f, G_UNICODE_NOT_PRESENT_OFFSET, 14157 }, { 0xffa0, G_UNICODE_NOT_PRESENT_OFFSET, 7405 }, { 0xffa1, G_UNICODE_NOT_PRESENT_OFFSET, 7201 }, { 0xffa2, G_UNICODE_NOT_PRESENT_OFFSET, 7205 }, { 0xffa3, G_UNICODE_NOT_PRESENT_OFFSET, 7209 }, { 0xffa4, G_UNICODE_NOT_PRESENT_OFFSET, 7213 }, { 0xffa5, G_UNICODE_NOT_PRESENT_OFFSET, 7217 }, { 0xffa6, G_UNICODE_NOT_PRESENT_OFFSET, 7221 }, { 0xffa7, G_UNICODE_NOT_PRESENT_OFFSET, 7225 }, { 0xffa8, G_UNICODE_NOT_PRESENT_OFFSET, 7229 }, { 0xffa9, G_UNICODE_NOT_PRESENT_OFFSET, 7233 }, { 0xffaa, G_UNICODE_NOT_PRESENT_OFFSET, 7237 }, { 0xffab, G_UNICODE_NOT_PRESENT_OFFSET, 7241 }, { 0xffac, G_UNICODE_NOT_PRESENT_OFFSET, 7245 }, { 0xffad, G_UNICODE_NOT_PRESENT_OFFSET, 7249 }, { 0xffae, G_UNICODE_NOT_PRESENT_OFFSET, 7253 }, { 0xffaf, G_UNICODE_NOT_PRESENT_OFFSET, 7257 }, { 0xffb0, G_UNICODE_NOT_PRESENT_OFFSET, 7261 }, { 0xffb1, G_UNICODE_NOT_PRESENT_OFFSET, 7265 }, { 0xffb2, G_UNICODE_NOT_PRESENT_OFFSET, 7269 }, { 0xffb3, G_UNICODE_NOT_PRESENT_OFFSET, 7273 }, { 0xffb4, G_UNICODE_NOT_PRESENT_OFFSET, 7277 }, { 0xffb5, G_UNICODE_NOT_PRESENT_OFFSET, 7281 }, { 0xffb6, G_UNICODE_NOT_PRESENT_OFFSET, 7285 }, { 0xffb7, G_UNICODE_NOT_PRESENT_OFFSET, 7289 }, { 0xffb8, G_UNICODE_NOT_PRESENT_OFFSET, 7293 }, { 0xffb9, G_UNICODE_NOT_PRESENT_OFFSET, 7297 }, { 0xffba, G_UNICODE_NOT_PRESENT_OFFSET, 7301 }, { 0xffbb, G_UNICODE_NOT_PRESENT_OFFSET, 7305 }, { 0xffbc, G_UNICODE_NOT_PRESENT_OFFSET, 7309 }, { 0xffbd, G_UNICODE_NOT_PRESENT_OFFSET, 7313 }, { 0xffbe, G_UNICODE_NOT_PRESENT_OFFSET, 7317 }, { 0xffc2, G_UNICODE_NOT_PRESENT_OFFSET, 7321 }, { 0xffc3, G_UNICODE_NOT_PRESENT_OFFSET, 7325 }, { 0xffc4, G_UNICODE_NOT_PRESENT_OFFSET, 7329 }, { 0xffc5, G_UNICODE_NOT_PRESENT_OFFSET, 7333 }, { 0xffc6, G_UNICODE_NOT_PRESENT_OFFSET, 7337 }, { 0xffc7, G_UNICODE_NOT_PRESENT_OFFSET, 7341 }, { 0xffca, G_UNICODE_NOT_PRESENT_OFFSET, 7345 }, { 0xffcb, G_UNICODE_NOT_PRESENT_OFFSET, 7349 }, { 0xffcc, G_UNICODE_NOT_PRESENT_OFFSET, 7353 }, { 0xffcd, G_UNICODE_NOT_PRESENT_OFFSET, 7357 }, { 0xffce, G_UNICODE_NOT_PRESENT_OFFSET, 7361 }, { 0xffcf, G_UNICODE_NOT_PRESENT_OFFSET, 7365 }, { 0xffd2, G_UNICODE_NOT_PRESENT_OFFSET, 7369 }, { 0xffd3, G_UNICODE_NOT_PRESENT_OFFSET, 7373 }, { 0xffd4, G_UNICODE_NOT_PRESENT_OFFSET, 7377 }, { 0xffd5, G_UNICODE_NOT_PRESENT_OFFSET, 7381 }, { 0xffd6, G_UNICODE_NOT_PRESENT_OFFSET, 7385 }, { 0xffd7, G_UNICODE_NOT_PRESENT_OFFSET, 7389 }, { 0xffda, G_UNICODE_NOT_PRESENT_OFFSET, 7393 }, { 0xffdb, G_UNICODE_NOT_PRESENT_OFFSET, 7397 }, { 0xffdc, G_UNICODE_NOT_PRESENT_OFFSET, 7401 }, { 0xffe0, G_UNICODE_NOT_PRESENT_OFFSET, 14161 }, { 0xffe1, G_UNICODE_NOT_PRESENT_OFFSET, 14164 }, { 0xffe2, G_UNICODE_NOT_PRESENT_OFFSET, 14167 }, { 0xffe3, G_UNICODE_NOT_PRESENT_OFFSET, 8 }, { 0xffe4, G_UNICODE_NOT_PRESENT_OFFSET, 14170 }, { 0xffe5, G_UNICODE_NOT_PRESENT_OFFSET, 14173 }, { 0xffe6, G_UNICODE_NOT_PRESENT_OFFSET, 14176 }, { 0xffe8, G_UNICODE_NOT_PRESENT_OFFSET, 14180 }, { 0xffe9, G_UNICODE_NOT_PRESENT_OFFSET, 14184 }, { 0xffea, G_UNICODE_NOT_PRESENT_OFFSET, 14188 }, { 0xffeb, G_UNICODE_NOT_PRESENT_OFFSET, 14192 }, { 0xffec, G_UNICODE_NOT_PRESENT_OFFSET, 14196 }, { 0xffed, G_UNICODE_NOT_PRESENT_OFFSET, 14200 }, { 0xffee, G_UNICODE_NOT_PRESENT_OFFSET, 14204 }, { 0x1d15e, 14208, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d15f, 14217, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d160, 14226, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d161, 14239, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d162, 14252, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d163, 14265, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d164, 14278, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d1bb, 14291, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d1bc, 14300, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d1bd, 14309, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d1be, 14322, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d1bf, 14335, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d1c0, 14348, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x1d400, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d401, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d402, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d403, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d404, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d405, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d406, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d407, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d408, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d409, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d40a, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d40b, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d40c, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d40d, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d40e, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d40f, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d410, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d411, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d412, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d413, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d414, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d415, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d416, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d417, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d418, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d419, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d41a, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d41b, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d41c, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d41d, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d41e, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d41f, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d420, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d421, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d422, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d423, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d424, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d425, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d426, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d427, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d428, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d429, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d42a, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d42b, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d42c, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d42d, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d42e, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d42f, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d430, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d431, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d432, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d433, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d434, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d435, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d436, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d437, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d438, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d439, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d43a, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d43b, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d43c, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d43d, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d43e, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d43f, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d440, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d441, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d442, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d443, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d444, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d445, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d446, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d447, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d448, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d449, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d44a, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d44b, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d44c, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d44d, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d44e, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d44f, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d450, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d451, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d452, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d453, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d454, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d456, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d457, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d458, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d459, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d45a, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d45b, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d45c, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d45d, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d45e, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d45f, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d460, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d461, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d462, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d463, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d464, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d465, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d466, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d467, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d468, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d469, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d46a, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d46b, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d46c, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d46d, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d46e, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d46f, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d470, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d471, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d472, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d473, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d474, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d475, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d476, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d477, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d478, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d479, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d47a, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d47b, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d47c, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d47d, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d47e, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d47f, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d480, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d481, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d482, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d483, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d484, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d485, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d486, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d487, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d488, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d489, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d48a, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d48b, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d48c, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d48d, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d48e, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d48f, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d490, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d491, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d492, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d493, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d494, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d495, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d496, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d497, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d498, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d499, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d49a, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d49b, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d49c, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d49e, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d49f, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d4a2, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d4a5, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d4a6, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d4a9, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d4aa, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d4ab, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d4ac, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d4ae, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d4af, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d4b0, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d4b1, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d4b2, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d4b3, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d4b4, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d4b5, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d4b6, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d4b7, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d4b8, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d4b9, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d4bb, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d4bd, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d4be, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d4bf, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d4c0, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d4c2, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d4c3, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d4c5, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d4c6, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d4c7, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d4c8, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d4c9, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d4ca, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d4cb, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d4cc, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d4cd, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d4ce, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d4cf, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d4d0, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d4d1, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d4d2, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d4d3, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d4d4, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d4d5, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d4d6, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d4d7, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d4d8, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d4d9, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d4da, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d4db, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d4dc, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d4dd, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d4de, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d4df, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d4e0, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d4e1, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d4e2, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d4e3, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d4e4, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d4e5, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d4e6, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d4e7, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d4e8, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d4e9, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d4ea, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d4eb, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d4ec, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d4ed, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d4ee, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d4ef, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d4f0, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d4f1, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d4f2, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d4f3, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d4f4, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d4f5, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d4f6, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d4f7, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d4f8, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d4f9, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d4fa, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d4fb, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d4fc, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d4fd, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d4fe, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d4ff, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d500, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d501, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d502, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d503, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d504, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d505, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d507, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d508, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d509, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d50a, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d50d, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d50e, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d50f, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d510, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d511, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d512, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d513, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d514, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d516, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d517, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d518, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d519, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d51a, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d51b, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d51c, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d51e, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d51f, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d520, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d521, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d522, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d523, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d524, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d525, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d526, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d527, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d528, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d529, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d52a, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d52b, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d52c, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d52d, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d52e, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d52f, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d530, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d531, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d532, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d533, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d534, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d535, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d536, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d537, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d538, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d539, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d53b, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d53c, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d53d, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d53e, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d540, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d541, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d542, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d543, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d544, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d546, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d54a, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d54b, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d54c, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d54d, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d54e, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d54f, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d550, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d552, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d553, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d554, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d555, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d556, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d557, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d558, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d559, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d55a, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d55b, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d55c, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d55d, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d55e, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d55f, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d560, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d561, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d562, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d563, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d564, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d565, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d566, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d567, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d568, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d569, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d56a, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d56b, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d56c, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d56d, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d56e, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d56f, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d570, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d571, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d572, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d573, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d574, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d575, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d576, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d577, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d578, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d579, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d57a, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d57b, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d57c, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d57d, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d57e, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d57f, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d580, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d581, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d582, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d583, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d584, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d585, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d586, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d587, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d588, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d589, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d58a, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d58b, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d58c, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d58d, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d58e, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d58f, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d590, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d591, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d592, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d593, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d594, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d595, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d596, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d597, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d598, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d599, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d59a, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d59b, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d59c, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d59d, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d59e, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d59f, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d5a0, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d5a1, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d5a2, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d5a3, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d5a4, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d5a5, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d5a6, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d5a7, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d5a8, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d5a9, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d5aa, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d5ab, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d5ac, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d5ad, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d5ae, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d5af, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d5b0, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d5b1, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d5b2, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d5b3, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d5b4, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d5b5, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d5b6, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d5b7, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d5b8, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d5b9, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d5ba, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d5bb, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d5bc, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d5bd, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d5be, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d5bf, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d5c0, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d5c1, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d5c2, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d5c3, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d5c4, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d5c5, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d5c6, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d5c7, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d5c8, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d5c9, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d5ca, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d5cb, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d5cc, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d5cd, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d5ce, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d5cf, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d5d0, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d5d1, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d5d2, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d5d3, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d5d4, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d5d5, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d5d6, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d5d7, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d5d8, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d5d9, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d5da, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d5db, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d5dc, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d5dd, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d5de, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d5df, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d5e0, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d5e1, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d5e2, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d5e3, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d5e4, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d5e5, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d5e6, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d5e7, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d5e8, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d5e9, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d5ea, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d5eb, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d5ec, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d5ed, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d5ee, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d5ef, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d5f0, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d5f1, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d5f2, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d5f3, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d5f4, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d5f5, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d5f6, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d5f7, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d5f8, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d5f9, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d5fa, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d5fb, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d5fc, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d5fd, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d5fe, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d5ff, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d600, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d601, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d602, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d603, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d604, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d605, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d606, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d607, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d608, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d609, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d60a, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d60b, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d60c, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d60d, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d60e, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d60f, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d610, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d611, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d612, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d613, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d614, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d615, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d616, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d617, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d618, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d619, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d61a, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d61b, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d61c, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d61d, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d61e, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d61f, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d620, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d621, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d622, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d623, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d624, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d625, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d626, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d627, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d628, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d629, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d62a, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d62b, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d62c, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d62d, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d62e, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d62f, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d630, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d631, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d632, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d633, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d634, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d635, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d636, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d637, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d638, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d639, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d63a, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d63b, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d63c, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d63d, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d63e, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d63f, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d640, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d641, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d642, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d643, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d644, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d645, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d646, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d647, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d648, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d649, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d64a, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d64b, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d64c, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d64d, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d64e, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d64f, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d650, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d651, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d652, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d653, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d654, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d655, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d656, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d657, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d658, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d659, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d65a, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d65b, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d65c, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d65d, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d65e, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d65f, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d660, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d661, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d662, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d663, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d664, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d665, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d666, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d667, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d668, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d669, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d66a, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d66b, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d66c, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d66d, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d66e, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d66f, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d670, G_UNICODE_NOT_PRESENT_OFFSET, 5831 }, { 0x1d671, G_UNICODE_NOT_PRESENT_OFFSET, 5042 }, { 0x1d672, G_UNICODE_NOT_PRESENT_OFFSET, 4982 }, { 0x1d673, G_UNICODE_NOT_PRESENT_OFFSET, 5077 }, { 0x1d674, G_UNICODE_NOT_PRESENT_OFFSET, 5046 }, { 0x1d675, G_UNICODE_NOT_PRESENT_OFFSET, 5048 }, { 0x1d676, G_UNICODE_NOT_PRESENT_OFFSET, 5833 }, { 0x1d677, G_UNICODE_NOT_PRESENT_OFFSET, 5005 }, { 0x1d678, G_UNICODE_NOT_PRESENT_OFFSET, 5010 }, { 0x1d679, G_UNICODE_NOT_PRESENT_OFFSET, 5835 }, { 0x1d67a, G_UNICODE_NOT_PRESENT_OFFSET, 5040 }, { 0x1d67b, G_UNICODE_NOT_PRESENT_OFFSET, 5012 }, { 0x1d67c, G_UNICODE_NOT_PRESENT_OFFSET, 5050 }, { 0x1d67d, G_UNICODE_NOT_PRESENT_OFFSET, 5014 }, { 0x1d67e, G_UNICODE_NOT_PRESENT_OFFSET, 5837 }, { 0x1d67f, G_UNICODE_NOT_PRESENT_OFFSET, 5019 }, { 0x1d680, G_UNICODE_NOT_PRESENT_OFFSET, 5021 }, { 0x1d681, G_UNICODE_NOT_PRESENT_OFFSET, 5023 }, { 0x1d682, G_UNICODE_NOT_PRESENT_OFFSET, 5839 }, { 0x1d683, G_UNICODE_NOT_PRESENT_OFFSET, 5841 }, { 0x1d684, G_UNICODE_NOT_PRESENT_OFFSET, 5843 }, { 0x1d685, G_UNICODE_NOT_PRESENT_OFFSET, 5168 }, { 0x1d686, G_UNICODE_NOT_PRESENT_OFFSET, 5845 }, { 0x1d687, G_UNICODE_NOT_PRESENT_OFFSET, 5185 }, { 0x1d688, G_UNICODE_NOT_PRESENT_OFFSET, 5847 }, { 0x1d689, G_UNICODE_NOT_PRESENT_OFFSET, 5035 }, { 0x1d68a, G_UNICODE_NOT_PRESENT_OFFSET, 6 }, { 0x1d68b, G_UNICODE_NOT_PRESENT_OFFSET, 5849 }, { 0x1d68c, G_UNICODE_NOT_PRESENT_OFFSET, 5228 }, { 0x1d68d, G_UNICODE_NOT_PRESENT_OFFSET, 5079 }, { 0x1d68e, G_UNICODE_NOT_PRESENT_OFFSET, 5044 }, { 0x1d68f, G_UNICODE_NOT_PRESENT_OFFSET, 5851 }, { 0x1d690, G_UNICODE_NOT_PRESENT_OFFSET, 5003 }, { 0x1d691, G_UNICODE_NOT_PRESENT_OFFSET, 1171 }, { 0x1d692, G_UNICODE_NOT_PRESENT_OFFSET, 4943 }, { 0x1d693, G_UNICODE_NOT_PRESENT_OFFSET, 1176 }, { 0x1d694, G_UNICODE_NOT_PRESENT_OFFSET, 5853 }, { 0x1d695, G_UNICODE_NOT_PRESENT_OFFSET, 1220 }, { 0x1d696, G_UNICODE_NOT_PRESENT_OFFSET, 5230 }, { 0x1d697, G_UNICODE_NOT_PRESENT_OFFSET, 4969 }, { 0x1d698, G_UNICODE_NOT_PRESENT_OFFSET, 29 }, { 0x1d699, G_UNICODE_NOT_PRESENT_OFFSET, 5855 }, { 0x1d69a, G_UNICODE_NOT_PRESENT_OFFSET, 5857 }, { 0x1d69b, G_UNICODE_NOT_PRESENT_OFFSET, 1178 }, { 0x1d69c, G_UNICODE_NOT_PRESENT_OFFSET, 711 }, { 0x1d69d, G_UNICODE_NOT_PRESENT_OFFSET, 5859 }, { 0x1d69e, G_UNICODE_NOT_PRESENT_OFFSET, 5861 }, { 0x1d69f, G_UNICODE_NOT_PRESENT_OFFSET, 5204 }, { 0x1d6a0, G_UNICODE_NOT_PRESENT_OFFSET, 1189 }, { 0x1d6a1, G_UNICODE_NOT_PRESENT_OFFSET, 1222 }, { 0x1d6a2, G_UNICODE_NOT_PRESENT_OFFSET, 1191 }, { 0x1d6a3, G_UNICODE_NOT_PRESENT_OFFSET, 5863 }, { 0x1d6a8, G_UNICODE_NOT_PRESENT_OFFSET, 14361 }, { 0x1d6a9, G_UNICODE_NOT_PRESENT_OFFSET, 14364 }, { 0x1d6aa, G_UNICODE_NOT_PRESENT_OFFSET, 5067 }, { 0x1d6ab, G_UNICODE_NOT_PRESENT_OFFSET, 14367 }, { 0x1d6ac, G_UNICODE_NOT_PRESENT_OFFSET, 14370 }, { 0x1d6ad, G_UNICODE_NOT_PRESENT_OFFSET, 14373 }, { 0x1d6ae, G_UNICODE_NOT_PRESENT_OFFSET, 14376 }, { 0x1d6af, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d6b0, G_UNICODE_NOT_PRESENT_OFFSET, 14379 }, { 0x1d6b1, G_UNICODE_NOT_PRESENT_OFFSET, 14382 }, { 0x1d6b2, G_UNICODE_NOT_PRESENT_OFFSET, 14385 }, { 0x1d6b3, G_UNICODE_NOT_PRESENT_OFFSET, 14388 }, { 0x1d6b4, G_UNICODE_NOT_PRESENT_OFFSET, 14391 }, { 0x1d6b5, G_UNICODE_NOT_PRESENT_OFFSET, 14394 }, { 0x1d6b6, G_UNICODE_NOT_PRESENT_OFFSET, 14397 }, { 0x1d6b7, G_UNICODE_NOT_PRESENT_OFFSET, 5070 }, { 0x1d6b8, G_UNICODE_NOT_PRESENT_OFFSET, 14400 }, { 0x1d6b9, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d6ba, G_UNICODE_NOT_PRESENT_OFFSET, 14403 }, { 0x1d6bb, G_UNICODE_NOT_PRESENT_OFFSET, 14406 }, { 0x1d6bc, G_UNICODE_NOT_PRESENT_OFFSET, 1374 }, { 0x1d6bd, G_UNICODE_NOT_PRESENT_OFFSET, 14409 }, { 0x1d6be, G_UNICODE_NOT_PRESENT_OFFSET, 14412 }, { 0x1d6bf, G_UNICODE_NOT_PRESENT_OFFSET, 14415 }, { 0x1d6c0, G_UNICODE_NOT_PRESENT_OFFSET, 5037 }, { 0x1d6c1, G_UNICODE_NOT_PRESENT_OFFSET, 14418 }, { 0x1d6c2, G_UNICODE_NOT_PRESENT_OFFSET, 14422 }, { 0x1d6c3, G_UNICODE_NOT_PRESENT_OFFSET, 1368 }, { 0x1d6c4, G_UNICODE_NOT_PRESENT_OFFSET, 5064 }, { 0x1d6c5, G_UNICODE_NOT_PRESENT_OFFSET, 14425 }, { 0x1d6c6, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d6c7, G_UNICODE_NOT_PRESENT_OFFSET, 14428 }, { 0x1d6c8, G_UNICODE_NOT_PRESENT_OFFSET, 14431 }, { 0x1d6c9, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d6ca, G_UNICODE_NOT_PRESENT_OFFSET, 4548 }, { 0x1d6cb, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d6cc, G_UNICODE_NOT_PRESENT_OFFSET, 14434 }, { 0x1d6cd, G_UNICODE_NOT_PRESENT_OFFSET, 20 }, { 0x1d6ce, G_UNICODE_NOT_PRESENT_OFFSET, 14437 }, { 0x1d6cf, G_UNICODE_NOT_PRESENT_OFFSET, 14440 }, { 0x1d6d0, G_UNICODE_NOT_PRESENT_OFFSET, 14443 }, { 0x1d6d1, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d6d2, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d6d3, G_UNICODE_NOT_PRESENT_OFFSET, 1399 }, { 0x1d6d4, G_UNICODE_NOT_PRESENT_OFFSET, 14446 }, { 0x1d6d5, G_UNICODE_NOT_PRESENT_OFFSET, 14449 }, { 0x1d6d6, G_UNICODE_NOT_PRESENT_OFFSET, 14452 }, { 0x1d6d7, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d6d8, G_UNICODE_NOT_PRESENT_OFFSET, 14455 }, { 0x1d6d9, G_UNICODE_NOT_PRESENT_OFFSET, 14458 }, { 0x1d6da, G_UNICODE_NOT_PRESENT_OFFSET, 14461 }, { 0x1d6db, G_UNICODE_NOT_PRESENT_OFFSET, 14464 }, { 0x1d6dc, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d6dd, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d6de, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d6df, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d6e0, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d6e1, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d6e2, G_UNICODE_NOT_PRESENT_OFFSET, 14361 }, { 0x1d6e3, G_UNICODE_NOT_PRESENT_OFFSET, 14364 }, { 0x1d6e4, G_UNICODE_NOT_PRESENT_OFFSET, 5067 }, { 0x1d6e5, G_UNICODE_NOT_PRESENT_OFFSET, 14367 }, { 0x1d6e6, G_UNICODE_NOT_PRESENT_OFFSET, 14370 }, { 0x1d6e7, G_UNICODE_NOT_PRESENT_OFFSET, 14373 }, { 0x1d6e8, G_UNICODE_NOT_PRESENT_OFFSET, 14376 }, { 0x1d6e9, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d6ea, G_UNICODE_NOT_PRESENT_OFFSET, 14379 }, { 0x1d6eb, G_UNICODE_NOT_PRESENT_OFFSET, 14382 }, { 0x1d6ec, G_UNICODE_NOT_PRESENT_OFFSET, 14385 }, { 0x1d6ed, G_UNICODE_NOT_PRESENT_OFFSET, 14388 }, { 0x1d6ee, G_UNICODE_NOT_PRESENT_OFFSET, 14391 }, { 0x1d6ef, G_UNICODE_NOT_PRESENT_OFFSET, 14394 }, { 0x1d6f0, G_UNICODE_NOT_PRESENT_OFFSET, 14397 }, { 0x1d6f1, G_UNICODE_NOT_PRESENT_OFFSET, 5070 }, { 0x1d6f2, G_UNICODE_NOT_PRESENT_OFFSET, 14400 }, { 0x1d6f3, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d6f4, G_UNICODE_NOT_PRESENT_OFFSET, 14403 }, { 0x1d6f5, G_UNICODE_NOT_PRESENT_OFFSET, 14406 }, { 0x1d6f6, G_UNICODE_NOT_PRESENT_OFFSET, 1374 }, { 0x1d6f7, G_UNICODE_NOT_PRESENT_OFFSET, 14409 }, { 0x1d6f8, G_UNICODE_NOT_PRESENT_OFFSET, 14412 }, { 0x1d6f9, G_UNICODE_NOT_PRESENT_OFFSET, 14415 }, { 0x1d6fa, G_UNICODE_NOT_PRESENT_OFFSET, 5037 }, { 0x1d6fb, G_UNICODE_NOT_PRESENT_OFFSET, 14418 }, { 0x1d6fc, G_UNICODE_NOT_PRESENT_OFFSET, 14422 }, { 0x1d6fd, G_UNICODE_NOT_PRESENT_OFFSET, 1368 }, { 0x1d6fe, G_UNICODE_NOT_PRESENT_OFFSET, 5064 }, { 0x1d6ff, G_UNICODE_NOT_PRESENT_OFFSET, 14425 }, { 0x1d700, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d701, G_UNICODE_NOT_PRESENT_OFFSET, 14428 }, { 0x1d702, G_UNICODE_NOT_PRESENT_OFFSET, 14431 }, { 0x1d703, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d704, G_UNICODE_NOT_PRESENT_OFFSET, 4548 }, { 0x1d705, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d706, G_UNICODE_NOT_PRESENT_OFFSET, 14434 }, { 0x1d707, G_UNICODE_NOT_PRESENT_OFFSET, 20 }, { 0x1d708, G_UNICODE_NOT_PRESENT_OFFSET, 14437 }, { 0x1d709, G_UNICODE_NOT_PRESENT_OFFSET, 14440 }, { 0x1d70a, G_UNICODE_NOT_PRESENT_OFFSET, 14443 }, { 0x1d70b, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d70c, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d70d, G_UNICODE_NOT_PRESENT_OFFSET, 1399 }, { 0x1d70e, G_UNICODE_NOT_PRESENT_OFFSET, 14446 }, { 0x1d70f, G_UNICODE_NOT_PRESENT_OFFSET, 14449 }, { 0x1d710, G_UNICODE_NOT_PRESENT_OFFSET, 14452 }, { 0x1d711, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d712, G_UNICODE_NOT_PRESENT_OFFSET, 14455 }, { 0x1d713, G_UNICODE_NOT_PRESENT_OFFSET, 14458 }, { 0x1d714, G_UNICODE_NOT_PRESENT_OFFSET, 14461 }, { 0x1d715, G_UNICODE_NOT_PRESENT_OFFSET, 14464 }, { 0x1d716, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d717, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d718, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d719, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d71a, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d71b, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d71c, G_UNICODE_NOT_PRESENT_OFFSET, 14361 }, { 0x1d71d, G_UNICODE_NOT_PRESENT_OFFSET, 14364 }, { 0x1d71e, G_UNICODE_NOT_PRESENT_OFFSET, 5067 }, { 0x1d71f, G_UNICODE_NOT_PRESENT_OFFSET, 14367 }, { 0x1d720, G_UNICODE_NOT_PRESENT_OFFSET, 14370 }, { 0x1d721, G_UNICODE_NOT_PRESENT_OFFSET, 14373 }, { 0x1d722, G_UNICODE_NOT_PRESENT_OFFSET, 14376 }, { 0x1d723, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d724, G_UNICODE_NOT_PRESENT_OFFSET, 14379 }, { 0x1d725, G_UNICODE_NOT_PRESENT_OFFSET, 14382 }, { 0x1d726, G_UNICODE_NOT_PRESENT_OFFSET, 14385 }, { 0x1d727, G_UNICODE_NOT_PRESENT_OFFSET, 14388 }, { 0x1d728, G_UNICODE_NOT_PRESENT_OFFSET, 14391 }, { 0x1d729, G_UNICODE_NOT_PRESENT_OFFSET, 14394 }, { 0x1d72a, G_UNICODE_NOT_PRESENT_OFFSET, 14397 }, { 0x1d72b, G_UNICODE_NOT_PRESENT_OFFSET, 5070 }, { 0x1d72c, G_UNICODE_NOT_PRESENT_OFFSET, 14400 }, { 0x1d72d, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d72e, G_UNICODE_NOT_PRESENT_OFFSET, 14403 }, { 0x1d72f, G_UNICODE_NOT_PRESENT_OFFSET, 14406 }, { 0x1d730, G_UNICODE_NOT_PRESENT_OFFSET, 1374 }, { 0x1d731, G_UNICODE_NOT_PRESENT_OFFSET, 14409 }, { 0x1d732, G_UNICODE_NOT_PRESENT_OFFSET, 14412 }, { 0x1d733, G_UNICODE_NOT_PRESENT_OFFSET, 14415 }, { 0x1d734, G_UNICODE_NOT_PRESENT_OFFSET, 5037 }, { 0x1d735, G_UNICODE_NOT_PRESENT_OFFSET, 14418 }, { 0x1d736, G_UNICODE_NOT_PRESENT_OFFSET, 14422 }, { 0x1d737, G_UNICODE_NOT_PRESENT_OFFSET, 1368 }, { 0x1d738, G_UNICODE_NOT_PRESENT_OFFSET, 5064 }, { 0x1d739, G_UNICODE_NOT_PRESENT_OFFSET, 14425 }, { 0x1d73a, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d73b, G_UNICODE_NOT_PRESENT_OFFSET, 14428 }, { 0x1d73c, G_UNICODE_NOT_PRESENT_OFFSET, 14431 }, { 0x1d73d, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d73e, G_UNICODE_NOT_PRESENT_OFFSET, 4548 }, { 0x1d73f, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d740, G_UNICODE_NOT_PRESENT_OFFSET, 14434 }, { 0x1d741, G_UNICODE_NOT_PRESENT_OFFSET, 20 }, { 0x1d742, G_UNICODE_NOT_PRESENT_OFFSET, 14437 }, { 0x1d743, G_UNICODE_NOT_PRESENT_OFFSET, 14440 }, { 0x1d744, G_UNICODE_NOT_PRESENT_OFFSET, 14443 }, { 0x1d745, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d746, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d747, G_UNICODE_NOT_PRESENT_OFFSET, 1399 }, { 0x1d748, G_UNICODE_NOT_PRESENT_OFFSET, 14446 }, { 0x1d749, G_UNICODE_NOT_PRESENT_OFFSET, 14449 }, { 0x1d74a, G_UNICODE_NOT_PRESENT_OFFSET, 14452 }, { 0x1d74b, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d74c, G_UNICODE_NOT_PRESENT_OFFSET, 14455 }, { 0x1d74d, G_UNICODE_NOT_PRESENT_OFFSET, 14458 }, { 0x1d74e, G_UNICODE_NOT_PRESENT_OFFSET, 14461 }, { 0x1d74f, G_UNICODE_NOT_PRESENT_OFFSET, 14464 }, { 0x1d750, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d751, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d752, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d753, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d754, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d755, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d756, G_UNICODE_NOT_PRESENT_OFFSET, 14361 }, { 0x1d757, G_UNICODE_NOT_PRESENT_OFFSET, 14364 }, { 0x1d758, G_UNICODE_NOT_PRESENT_OFFSET, 5067 }, { 0x1d759, G_UNICODE_NOT_PRESENT_OFFSET, 14367 }, { 0x1d75a, G_UNICODE_NOT_PRESENT_OFFSET, 14370 }, { 0x1d75b, G_UNICODE_NOT_PRESENT_OFFSET, 14373 }, { 0x1d75c, G_UNICODE_NOT_PRESENT_OFFSET, 14376 }, { 0x1d75d, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d75e, G_UNICODE_NOT_PRESENT_OFFSET, 14379 }, { 0x1d75f, G_UNICODE_NOT_PRESENT_OFFSET, 14382 }, { 0x1d760, G_UNICODE_NOT_PRESENT_OFFSET, 14385 }, { 0x1d761, G_UNICODE_NOT_PRESENT_OFFSET, 14388 }, { 0x1d762, G_UNICODE_NOT_PRESENT_OFFSET, 14391 }, { 0x1d763, G_UNICODE_NOT_PRESENT_OFFSET, 14394 }, { 0x1d764, G_UNICODE_NOT_PRESENT_OFFSET, 14397 }, { 0x1d765, G_UNICODE_NOT_PRESENT_OFFSET, 5070 }, { 0x1d766, G_UNICODE_NOT_PRESENT_OFFSET, 14400 }, { 0x1d767, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d768, G_UNICODE_NOT_PRESENT_OFFSET, 14403 }, { 0x1d769, G_UNICODE_NOT_PRESENT_OFFSET, 14406 }, { 0x1d76a, G_UNICODE_NOT_PRESENT_OFFSET, 1374 }, { 0x1d76b, G_UNICODE_NOT_PRESENT_OFFSET, 14409 }, { 0x1d76c, G_UNICODE_NOT_PRESENT_OFFSET, 14412 }, { 0x1d76d, G_UNICODE_NOT_PRESENT_OFFSET, 14415 }, { 0x1d76e, G_UNICODE_NOT_PRESENT_OFFSET, 5037 }, { 0x1d76f, G_UNICODE_NOT_PRESENT_OFFSET, 14418 }, { 0x1d770, G_UNICODE_NOT_PRESENT_OFFSET, 14422 }, { 0x1d771, G_UNICODE_NOT_PRESENT_OFFSET, 1368 }, { 0x1d772, G_UNICODE_NOT_PRESENT_OFFSET, 5064 }, { 0x1d773, G_UNICODE_NOT_PRESENT_OFFSET, 14425 }, { 0x1d774, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d775, G_UNICODE_NOT_PRESENT_OFFSET, 14428 }, { 0x1d776, G_UNICODE_NOT_PRESENT_OFFSET, 14431 }, { 0x1d777, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d778, G_UNICODE_NOT_PRESENT_OFFSET, 4548 }, { 0x1d779, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d77a, G_UNICODE_NOT_PRESENT_OFFSET, 14434 }, { 0x1d77b, G_UNICODE_NOT_PRESENT_OFFSET, 20 }, { 0x1d77c, G_UNICODE_NOT_PRESENT_OFFSET, 14437 }, { 0x1d77d, G_UNICODE_NOT_PRESENT_OFFSET, 14440 }, { 0x1d77e, G_UNICODE_NOT_PRESENT_OFFSET, 14443 }, { 0x1d77f, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d780, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d781, G_UNICODE_NOT_PRESENT_OFFSET, 1399 }, { 0x1d782, G_UNICODE_NOT_PRESENT_OFFSET, 14446 }, { 0x1d783, G_UNICODE_NOT_PRESENT_OFFSET, 14449 }, { 0x1d784, G_UNICODE_NOT_PRESENT_OFFSET, 14452 }, { 0x1d785, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d786, G_UNICODE_NOT_PRESENT_OFFSET, 14455 }, { 0x1d787, G_UNICODE_NOT_PRESENT_OFFSET, 14458 }, { 0x1d788, G_UNICODE_NOT_PRESENT_OFFSET, 14461 }, { 0x1d789, G_UNICODE_NOT_PRESENT_OFFSET, 14464 }, { 0x1d78a, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d78b, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d78c, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d78d, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d78e, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d78f, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d790, G_UNICODE_NOT_PRESENT_OFFSET, 14361 }, { 0x1d791, G_UNICODE_NOT_PRESENT_OFFSET, 14364 }, { 0x1d792, G_UNICODE_NOT_PRESENT_OFFSET, 5067 }, { 0x1d793, G_UNICODE_NOT_PRESENT_OFFSET, 14367 }, { 0x1d794, G_UNICODE_NOT_PRESENT_OFFSET, 14370 }, { 0x1d795, G_UNICODE_NOT_PRESENT_OFFSET, 14373 }, { 0x1d796, G_UNICODE_NOT_PRESENT_OFFSET, 14376 }, { 0x1d797, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d798, G_UNICODE_NOT_PRESENT_OFFSET, 14379 }, { 0x1d799, G_UNICODE_NOT_PRESENT_OFFSET, 14382 }, { 0x1d79a, G_UNICODE_NOT_PRESENT_OFFSET, 14385 }, { 0x1d79b, G_UNICODE_NOT_PRESENT_OFFSET, 14388 }, { 0x1d79c, G_UNICODE_NOT_PRESENT_OFFSET, 14391 }, { 0x1d79d, G_UNICODE_NOT_PRESENT_OFFSET, 14394 }, { 0x1d79e, G_UNICODE_NOT_PRESENT_OFFSET, 14397 }, { 0x1d79f, G_UNICODE_NOT_PRESENT_OFFSET, 5070 }, { 0x1d7a0, G_UNICODE_NOT_PRESENT_OFFSET, 14400 }, { 0x1d7a1, G_UNICODE_NOT_PRESENT_OFFSET, 1402 }, { 0x1d7a2, G_UNICODE_NOT_PRESENT_OFFSET, 14403 }, { 0x1d7a3, G_UNICODE_NOT_PRESENT_OFFSET, 14406 }, { 0x1d7a4, G_UNICODE_NOT_PRESENT_OFFSET, 1374 }, { 0x1d7a5, G_UNICODE_NOT_PRESENT_OFFSET, 14409 }, { 0x1d7a6, G_UNICODE_NOT_PRESENT_OFFSET, 14412 }, { 0x1d7a7, G_UNICODE_NOT_PRESENT_OFFSET, 14415 }, { 0x1d7a8, G_UNICODE_NOT_PRESENT_OFFSET, 5037 }, { 0x1d7a9, G_UNICODE_NOT_PRESENT_OFFSET, 14418 }, { 0x1d7aa, G_UNICODE_NOT_PRESENT_OFFSET, 14422 }, { 0x1d7ab, G_UNICODE_NOT_PRESENT_OFFSET, 1368 }, { 0x1d7ac, G_UNICODE_NOT_PRESENT_OFFSET, 5064 }, { 0x1d7ad, G_UNICODE_NOT_PRESENT_OFFSET, 14425 }, { 0x1d7ae, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d7af, G_UNICODE_NOT_PRESENT_OFFSET, 14428 }, { 0x1d7b0, G_UNICODE_NOT_PRESENT_OFFSET, 14431 }, { 0x1d7b1, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d7b2, G_UNICODE_NOT_PRESENT_OFFSET, 4548 }, { 0x1d7b3, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d7b4, G_UNICODE_NOT_PRESENT_OFFSET, 14434 }, { 0x1d7b5, G_UNICODE_NOT_PRESENT_OFFSET, 20 }, { 0x1d7b6, G_UNICODE_NOT_PRESENT_OFFSET, 14437 }, { 0x1d7b7, G_UNICODE_NOT_PRESENT_OFFSET, 14440 }, { 0x1d7b8, G_UNICODE_NOT_PRESENT_OFFSET, 14443 }, { 0x1d7b9, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d7ba, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d7bb, G_UNICODE_NOT_PRESENT_OFFSET, 1399 }, { 0x1d7bc, G_UNICODE_NOT_PRESENT_OFFSET, 14446 }, { 0x1d7bd, G_UNICODE_NOT_PRESENT_OFFSET, 14449 }, { 0x1d7be, G_UNICODE_NOT_PRESENT_OFFSET, 14452 }, { 0x1d7bf, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d7c0, G_UNICODE_NOT_PRESENT_OFFSET, 14455 }, { 0x1d7c1, G_UNICODE_NOT_PRESENT_OFFSET, 14458 }, { 0x1d7c2, G_UNICODE_NOT_PRESENT_OFFSET, 14461 }, { 0x1d7c3, G_UNICODE_NOT_PRESENT_OFFSET, 14464 }, { 0x1d7c4, G_UNICODE_NOT_PRESENT_OFFSET, 1405 }, { 0x1d7c5, G_UNICODE_NOT_PRESENT_OFFSET, 1371 }, { 0x1d7c6, G_UNICODE_NOT_PRESENT_OFFSET, 1393 }, { 0x1d7c7, G_UNICODE_NOT_PRESENT_OFFSET, 1387 }, { 0x1d7c8, G_UNICODE_NOT_PRESENT_OFFSET, 1396 }, { 0x1d7c9, G_UNICODE_NOT_PRESENT_OFFSET, 1390 }, { 0x1d7ce, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x1d7cf, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x1d7d0, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x1d7d1, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x1d7d2, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x1d7d3, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x1d7d4, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x1d7d5, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x1d7d6, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x1d7d7, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x1d7d8, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x1d7d9, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x1d7da, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x1d7db, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x1d7dc, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x1d7dd, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x1d7de, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x1d7df, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x1d7e0, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x1d7e1, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x1d7e2, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x1d7e3, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x1d7e4, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x1d7e5, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x1d7e6, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x1d7e7, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x1d7e8, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x1d7e9, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x1d7ea, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x1d7eb, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x1d7ec, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x1d7ed, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x1d7ee, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x1d7ef, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x1d7f0, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x1d7f1, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x1d7f2, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x1d7f3, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x1d7f4, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x1d7f5, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x1d7f6, G_UNICODE_NOT_PRESENT_OFFSET, 4941 }, { 0x1d7f7, G_UNICODE_NOT_PRESENT_OFFSET, 27 }, { 0x1d7f8, G_UNICODE_NOT_PRESENT_OFFSET, 12 }, { 0x1d7f9, G_UNICODE_NOT_PRESENT_OFFSET, 14 }, { 0x1d7fa, G_UNICODE_NOT_PRESENT_OFFSET, 4945 }, { 0x1d7fb, G_UNICODE_NOT_PRESENT_OFFSET, 4947 }, { 0x1d7fc, G_UNICODE_NOT_PRESENT_OFFSET, 4949 }, { 0x1d7fd, G_UNICODE_NOT_PRESENT_OFFSET, 4951 }, { 0x1d7fe, G_UNICODE_NOT_PRESENT_OFFSET, 4953 }, { 0x1d7ff, G_UNICODE_NOT_PRESENT_OFFSET, 4955 }, { 0x2f800, 14468, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f801, 14472, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f802, 14476, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f803, 14480, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f804, 14485, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f805, 11545, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f806, 14489, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f807, 14493, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f808, 14497, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f809, 14501, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f80a, 11549, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f80b, 14505, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f80c, 14509, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f80d, 14513, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f80e, 11553, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f80f, 14518, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f810, 14522, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f811, 14526, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f812, 14530, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f813, 14535, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f814, 14539, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f815, 14543, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f816, 14547, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f817, 14552, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f818, 14556, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f819, 14560, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f81a, 14564, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f81b, 14568, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f81c, 14572, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f81d, 5967, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f81e, 14577, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f81f, 14581, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f820, 14585, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f821, 14589, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f822, 14593, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f823, 14597, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f824, 14601, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f825, 14605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f826, 11557, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f827, 11561, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f828, 14609, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f829, 14613, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f82a, 14617, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f82b, 10837, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f82c, 14621, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f82d, 11565, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f82e, 14625, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f82f, 14629, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f830, 14633, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f831, 14637, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f832, 14637, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f833, 14637, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f834, 14641, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f835, 14646, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f836, 14650, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f837, 14654, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f838, 14658, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f839, 14663, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f83a, 14667, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f83b, 14671, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f83c, 14675, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f83d, 14679, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f83e, 14683, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f83f, 14687, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f840, 14691, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f841, 14695, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f842, 14699, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f843, 14703, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f844, 14707, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f845, 14711, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f846, 14711, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f847, 14715, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f848, 14719, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f849, 14723, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f84a, 14727, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f84b, 14731, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f84c, 11573, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f84d, 14735, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f84e, 14739, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f84f, 14743, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f850, 11421, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f851, 14747, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f852, 14751, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f853, 14755, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f854, 14759, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f855, 14763, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f856, 14767, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f857, 14771, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f858, 14775, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f859, 14779, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f85a, 14784, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f85b, 14788, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f85c, 14792, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f85d, 14796, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f85e, 14800, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f85f, 14804, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f860, 14808, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f861, 14813, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f862, 14818, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f863, 14822, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f864, 14826, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f865, 14830, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f866, 14834, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f867, 14838, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f868, 14842, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f869, 14847, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f86a, 14851, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f86b, 14851, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f86c, 14855, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f86d, 14860, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f86e, 14864, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f86f, 10821, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f870, 14868, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f871, 14872, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f872, 14877, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f873, 14881, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f874, 14885, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f875, 6071, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f876, 14889, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f877, 14893, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f878, 6079, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f879, 14897, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f87a, 14901, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f87b, 14905, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f87c, 14910, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f87d, 14914, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f87e, 14919, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f87f, 14923, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f880, 14927, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f881, 14931, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f882, 14935, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f883, 14939, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f884, 14943, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f885, 14947, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f886, 14951, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f887, 14955, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f888, 14959, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f889, 14963, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f88a, 14968, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f88b, 14972, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f88c, 14976, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f88d, 14980, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f88e, 10613, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f88f, 14984, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f890, 6119, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f891, 14989, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f892, 14989, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f893, 14994, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f894, 14998, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f895, 14998, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f896, 15002, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f897, 15006, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f898, 15011, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f899, 15016, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f89a, 15020, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f89b, 15024, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f89c, 15028, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f89d, 15032, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f89e, 15036, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f89f, 15040, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a0, 15044, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a1, 15048, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a2, 15052, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a3, 11593, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a4, 15056, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a5, 15061, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a6, 15065, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a7, 15069, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a8, 15073, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8a9, 15069, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8aa, 15077, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ab, 11601, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ac, 15081, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ad, 15085, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ae, 15089, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8af, 15093, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b0, 11605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b1, 10505, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b2, 15097, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b3, 15101, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b4, 15105, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b5, 15109, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b6, 15113, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b7, 15117, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b8, 15121, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8b9, 15126, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ba, 15130, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8bb, 15134, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8bc, 15138, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8bd, 15142, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8be, 15146, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8bf, 15151, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c0, 15155, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c1, 15159, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c2, 15163, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c3, 15167, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c4, 15171, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c5, 15175, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c6, 15179, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c7, 15183, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c8, 11609, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8c9, 15187, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ca, 15191, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8cb, 15196, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8cc, 15200, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8cd, 15204, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ce, 15208, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8cf, 11617, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d0, 15212, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d1, 15216, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d2, 15220, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d3, 15224, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d4, 15228, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d5, 15232, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d6, 15236, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d7, 15240, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d8, 10617, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8d9, 15244, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8da, 15248, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8db, 15252, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8dc, 15256, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8dd, 15260, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8de, 15265, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8df, 15269, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e0, 15273, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e1, 15277, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e2, 11621, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e3, 15281, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e4, 15286, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e5, 15290, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e6, 15294, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e7, 15298, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e8, 15302, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8e9, 15306, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ea, 15310, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8eb, 15314, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ec, 15318, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ed, 15323, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ee, 15327, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ef, 15331, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f0, 15335, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f1, 15340, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f2, 15344, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f3, 15348, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f4, 15352, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f5, 10889, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f6, 15356, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f7, 15360, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f8, 15365, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8f9, 15370, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8fa, 15375, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8fb, 15379, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8fc, 15384, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8fd, 15388, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8fe, 15392, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f8ff, 15396, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f900, 15400, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f901, 11625, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f902, 11221, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f903, 15404, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f904, 15408, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f905, 15412, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f906, 15416, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f907, 15421, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f908, 15425, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f909, 15429, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f90a, 15433, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f90b, 15437, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f90c, 15441, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f90d, 15445, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f90e, 15450, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f90f, 15454, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f910, 15458, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f911, 15463, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f912, 15468, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f913, 15472, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f914, 15476, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f915, 15480, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f916, 15484, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f917, 15488, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f918, 15492, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f919, 15496, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f91a, 15500, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f91b, 15504, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f91c, 15509, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f91d, 15513, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f91e, 15518, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f91f, 15522, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f920, 15526, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f921, 15530, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f922, 15534, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f923, 15538, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f924, 15543, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f925, 15547, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f926, 15551, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f927, 15556, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f928, 15561, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f929, 15565, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f92a, 15569, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f92b, 15573, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f92c, 15577, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f92d, 15577, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f92e, 15581, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f92f, 15585, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f930, 15589, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f931, 15593, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f932, 15597, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f933, 15601, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f934, 15605, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f935, 15609, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f936, 15614, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f937, 15618, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f938, 10833, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f939, 15623, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f93a, 15628, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f93b, 15632, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f93c, 15637, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f93d, 15642, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f93e, 15647, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f93f, 15651, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f940, 15655, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f941, 15659, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f942, 15664, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f943, 15669, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f944, 15674, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f945, 15679, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f946, 15683, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f947, 15683, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f948, 15687, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f949, 15691, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f94a, 15695, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f94b, 15699, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f94c, 15703, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f94d, 15707, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f94e, 15712, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f94f, 10685, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f950, 15716, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f951, 15720, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f952, 15724, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f953, 11665, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f954, 15729, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f955, 15734, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f956, 11501, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f957, 15739, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f958, 15743, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f959, 11677, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f95a, 15747, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f95b, 15751, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f95c, 15755, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f95d, 15760, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f95e, 15760, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f95f, 15765, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f960, 15769, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f961, 15773, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f962, 15778, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f963, 15782, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f964, 15786, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f965, 15790, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f966, 15795, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f967, 15799, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f968, 15803, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f969, 15807, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f96a, 15811, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f96b, 15815, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f96c, 15820, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f96d, 15824, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f96e, 15828, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f96f, 15832, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f970, 15836, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f971, 15840, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f972, 15844, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f973, 15849, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f974, 15854, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f975, 15858, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f976, 15863, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f977, 15867, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f978, 15872, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f979, 15876, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f97a, 11701, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f97b, 15880, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f97c, 15885, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f97d, 15890, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f97e, 15894, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f97f, 15899, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f980, 15903, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f981, 15908, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f982, 15912, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f983, 15916, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f984, 15920, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f985, 15924, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f986, 15928, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f987, 15932, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f988, 15937, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f989, 15942, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f98a, 15947, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f98b, 14994, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f98c, 15952, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f98d, 15956, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f98e, 15960, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f98f, 15964, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f990, 15968, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f991, 15972, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f992, 15976, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f993, 15980, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f994, 15984, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f995, 15988, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f996, 15992, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f997, 15996, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f998, 10901, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f999, 16001, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f99a, 16005, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f99b, 16009, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f99c, 16013, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f99d, 16017, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f99e, 16021, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f99f, 11713, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a0, 16025, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a1, 16029, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a2, 16033, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a3, 16037, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a4, 16041, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a5, 16046, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a6, 16051, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a7, 16056, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a8, 16060, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9a9, 16064, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9aa, 16068, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ab, 16072, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ac, 16077, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ad, 16081, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ae, 16086, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9af, 16090, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b0, 16094, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b1, 16099, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b2, 16104, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b3, 16108, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b4, 10665, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b5, 16112, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b6, 16116, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b7, 16120, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b8, 16124, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9b9, 16128, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ba, 16132, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9bb, 16136, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9bc, 16140, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9bd, 16144, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9be, 16148, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9bf, 16152, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c0, 16156, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c1, 16160, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c2, 16164, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c3, 16168, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c4, 6479, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c5, 16172, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c6, 16177, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c7, 16181, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c8, 16185, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9c9, 16189, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ca, 16193, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9cb, 16197, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9cc, 16202, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9cd, 16207, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ce, 16211, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9cf, 16215, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d0, 16219, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d1, 16223, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d2, 6507, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d3, 16227, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d4, 16232, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d5, 16236, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d6, 16240, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d7, 16244, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d8, 16248, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9d9, 16253, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9da, 16258, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9db, 16262, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9dc, 16266, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9dd, 16270, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9de, 16275, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9df, 16279, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e0, 16283, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e1, 16288, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e2, 16293, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e3, 16297, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e4, 16301, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e5, 16305, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e6, 16310, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e7, 16314, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e8, 16318, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9e9, 16322, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ea, 16326, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9eb, 16330, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ec, 16334, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ed, 16338, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ee, 16343, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ef, 16347, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f0, 16351, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f1, 16355, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f2, 16360, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f3, 16364, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f4, 16368, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f5, 16372, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f6, 16376, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f7, 16381, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f8, 16386, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9f9, 16390, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9fa, 16394, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9fb, 16398, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9fc, 16403, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9fd, 16407, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9fe, 16412, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2f9ff, 16412, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa00, 16416, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa01, 16420, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa02, 16425, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa03, 16429, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa04, 16433, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa05, 16437, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa06, 16441, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa07, 16445, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa08, 16449, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa09, 16453, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa0a, 16458, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa0b, 16462, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa0c, 16466, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa0d, 16470, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa0e, 16474, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa0f, 16478, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa10, 16482, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa11, 16487, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa12, 16491, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa13, 16496, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa14, 16501, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa15, 6699, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa16, 16506, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa17, 6715, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa18, 16510, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa19, 16514, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa1a, 16518, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa1b, 16522, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa1c, 6735, G_UNICODE_NOT_PRESENT_OFFSET }, { 0x2fa1d, 16526, G_UNICODE_NOT_PRESENT_OFFSET } }; static const gchar decomp_expansion_string[] = "\x20\0" /* offset 0 */ "\x20\xcc\x88\0" /* offset 2 */ "\x61\0" /* offset 6 */ "\x20\xcc\x84\0" /* offset 8 */ "\x32\0" /* offset 12 */ "\x33\0" /* offset 14 */ "\x20\xcc\x81\0" /* offset 16 */ "\xce\xbc\0" /* offset 20 */ "\x20\xcc\xa7\0" /* offset 23 */ "\x31\0" /* offset 27 */ "\x6f\0" /* offset 29 */ "\x31\xe2\x81\x84\x34\0" /* offset 31 */ "\x31\xe2\x81\x84\x32\0" /* offset 37 */ "\x33\xe2\x81\x84\x34\0" /* offset 43 */ "\x41\xcc\x80\0" /* offset 49 */ "\x41\xcc\x81\0" /* offset 53 */ "\x41\xcc\x82\0" /* offset 57 */ "\x41\xcc\x83\0" /* offset 61 */ "\x41\xcc\x88\0" /* offset 65 */ "\x41\xcc\x8a\0" /* offset 69 */ "\x43\xcc\xa7\0" /* offset 73 */ "\x45\xcc\x80\0" /* offset 77 */ "\x45\xcc\x81\0" /* offset 81 */ "\x45\xcc\x82\0" /* offset 85 */ "\x45\xcc\x88\0" /* offset 89 */ "\x49\xcc\x80\0" /* offset 93 */ "\x49\xcc\x81\0" /* offset 97 */ "\x49\xcc\x82\0" /* offset 101 */ "\x49\xcc\x88\0" /* offset 105 */ "\x4e\xcc\x83\0" /* offset 109 */ "\x4f\xcc\x80\0" /* offset 113 */ "\x4f\xcc\x81\0" /* offset 117 */ "\x4f\xcc\x82\0" /* offset 121 */ "\x4f\xcc\x83\0" /* offset 125 */ "\x4f\xcc\x88\0" /* offset 129 */ "\x55\xcc\x80\0" /* offset 133 */ "\x55\xcc\x81\0" /* offset 137 */ "\x55\xcc\x82\0" /* offset 141 */ "\x55\xcc\x88\0" /* offset 145 */ "\x59\xcc\x81\0" /* offset 149 */ "\x61\xcc\x80\0" /* offset 153 */ "\x61\xcc\x81\0" /* offset 157 */ "\x61\xcc\x82\0" /* offset 161 */ "\x61\xcc\x83\0" /* offset 165 */ "\x61\xcc\x88\0" /* offset 169 */ "\x61\xcc\x8a\0" /* offset 173 */ "\x63\xcc\xa7\0" /* offset 177 */ "\x65\xcc\x80\0" /* offset 181 */ "\x65\xcc\x81\0" /* offset 185 */ "\x65\xcc\x82\0" /* offset 189 */ "\x65\xcc\x88\0" /* offset 193 */ "\x69\xcc\x80\0" /* offset 197 */ "\x69\xcc\x81\0" /* offset 201 */ "\x69\xcc\x82\0" /* offset 205 */ "\x69\xcc\x88\0" /* offset 209 */ "\x6e\xcc\x83\0" /* offset 213 */ "\x6f\xcc\x80\0" /* offset 217 */ "\x6f\xcc\x81\0" /* offset 221 */ "\x6f\xcc\x82\0" /* offset 225 */ "\x6f\xcc\x83\0" /* offset 229 */ "\x6f\xcc\x88\0" /* offset 233 */ "\x75\xcc\x80\0" /* offset 237 */ "\x75\xcc\x81\0" /* offset 241 */ "\x75\xcc\x82\0" /* offset 245 */ "\x75\xcc\x88\0" /* offset 249 */ "\x79\xcc\x81\0" /* offset 253 */ "\x79\xcc\x88\0" /* offset 257 */ "\x41\xcc\x84\0" /* offset 261 */ "\x61\xcc\x84\0" /* offset 265 */ "\x41\xcc\x86\0" /* offset 269 */ "\x61\xcc\x86\0" /* offset 273 */ "\x41\xcc\xa8\0" /* offset 277 */ "\x61\xcc\xa8\0" /* offset 281 */ "\x43\xcc\x81\0" /* offset 285 */ "\x63\xcc\x81\0" /* offset 289 */ "\x43\xcc\x82\0" /* offset 293 */ "\x63\xcc\x82\0" /* offset 297 */ "\x43\xcc\x87\0" /* offset 301 */ "\x63\xcc\x87\0" /* offset 305 */ "\x43\xcc\x8c\0" /* offset 309 */ "\x63\xcc\x8c\0" /* offset 313 */ "\x44\xcc\x8c\0" /* offset 317 */ "\x64\xcc\x8c\0" /* offset 321 */ "\x45\xcc\x84\0" /* offset 325 */ "\x65\xcc\x84\0" /* offset 329 */ "\x45\xcc\x86\0" /* offset 333 */ "\x65\xcc\x86\0" /* offset 337 */ "\x45\xcc\x87\0" /* offset 341 */ "\x65\xcc\x87\0" /* offset 345 */ "\x45\xcc\xa8\0" /* offset 349 */ "\x65\xcc\xa8\0" /* offset 353 */ "\x45\xcc\x8c\0" /* offset 357 */ "\x65\xcc\x8c\0" /* offset 361 */ "\x47\xcc\x82\0" /* offset 365 */ "\x67\xcc\x82\0" /* offset 369 */ "\x47\xcc\x86\0" /* offset 373 */ "\x67\xcc\x86\0" /* offset 377 */ "\x47\xcc\x87\0" /* offset 381 */ "\x67\xcc\x87\0" /* offset 385 */ "\x47\xcc\xa7\0" /* offset 389 */ "\x67\xcc\xa7\0" /* offset 393 */ "\x48\xcc\x82\0" /* offset 397 */ "\x68\xcc\x82\0" /* offset 401 */ "\x49\xcc\x83\0" /* offset 405 */ "\x69\xcc\x83\0" /* offset 409 */ "\x49\xcc\x84\0" /* offset 413 */ "\x69\xcc\x84\0" /* offset 417 */ "\x49\xcc\x86\0" /* offset 421 */ "\x69\xcc\x86\0" /* offset 425 */ "\x49\xcc\xa8\0" /* offset 429 */ "\x69\xcc\xa8\0" /* offset 433 */ "\x49\xcc\x87\0" /* offset 437 */ "\x49\x4a\0" /* offset 441 */ "\x69\x6a\0" /* offset 444 */ "\x4a\xcc\x82\0" /* offset 447 */ "\x6a\xcc\x82\0" /* offset 451 */ "\x4b\xcc\xa7\0" /* offset 455 */ "\x6b\xcc\xa7\0" /* offset 459 */ "\x4c\xcc\x81\0" /* offset 463 */ "\x6c\xcc\x81\0" /* offset 467 */ "\x4c\xcc\xa7\0" /* offset 471 */ "\x6c\xcc\xa7\0" /* offset 475 */ "\x4c\xcc\x8c\0" /* offset 479 */ "\x6c\xcc\x8c\0" /* offset 483 */ "\x4c\xc2\xb7\0" /* offset 487 */ "\x6c\xc2\xb7\0" /* offset 491 */ "\x4e\xcc\x81\0" /* offset 495 */ "\x6e\xcc\x81\0" /* offset 499 */ "\x4e\xcc\xa7\0" /* offset 503 */ "\x6e\xcc\xa7\0" /* offset 507 */ "\x4e\xcc\x8c\0" /* offset 511 */ "\x6e\xcc\x8c\0" /* offset 515 */ "\xca\xbc\x6e\0" /* offset 519 */ "\x4f\xcc\x84\0" /* offset 523 */ "\x6f\xcc\x84\0" /* offset 527 */ "\x4f\xcc\x86\0" /* offset 531 */ "\x6f\xcc\x86\0" /* offset 535 */ "\x4f\xcc\x8b\0" /* offset 539 */ "\x6f\xcc\x8b\0" /* offset 543 */ "\x52\xcc\x81\0" /* offset 547 */ "\x72\xcc\x81\0" /* offset 551 */ "\x52\xcc\xa7\0" /* offset 555 */ "\x72\xcc\xa7\0" /* offset 559 */ "\x52\xcc\x8c\0" /* offset 563 */ "\x72\xcc\x8c\0" /* offset 567 */ "\x53\xcc\x81\0" /* offset 571 */ "\x73\xcc\x81\0" /* offset 575 */ "\x53\xcc\x82\0" /* offset 579 */ "\x73\xcc\x82\0" /* offset 583 */ "\x53\xcc\xa7\0" /* offset 587 */ "\x73\xcc\xa7\0" /* offset 591 */ "\x53\xcc\x8c\0" /* offset 595 */ "\x73\xcc\x8c\0" /* offset 599 */ "\x54\xcc\xa7\0" /* offset 603 */ "\x74\xcc\xa7\0" /* offset 607 */ "\x54\xcc\x8c\0" /* offset 611 */ "\x74\xcc\x8c\0" /* offset 615 */ "\x55\xcc\x83\0" /* offset 619 */ "\x75\xcc\x83\0" /* offset 623 */ "\x55\xcc\x84\0" /* offset 627 */ "\x75\xcc\x84\0" /* offset 631 */ "\x55\xcc\x86\0" /* offset 635 */ "\x75\xcc\x86\0" /* offset 639 */ "\x55\xcc\x8a\0" /* offset 643 */ "\x75\xcc\x8a\0" /* offset 647 */ "\x55\xcc\x8b\0" /* offset 651 */ "\x75\xcc\x8b\0" /* offset 655 */ "\x55\xcc\xa8\0" /* offset 659 */ "\x75\xcc\xa8\0" /* offset 663 */ "\x57\xcc\x82\0" /* offset 667 */ "\x77\xcc\x82\0" /* offset 671 */ "\x59\xcc\x82\0" /* offset 675 */ "\x79\xcc\x82\0" /* offset 679 */ "\x59\xcc\x88\0" /* offset 683 */ "\x5a\xcc\x81\0" /* offset 687 */ "\x7a\xcc\x81\0" /* offset 691 */ "\x5a\xcc\x87\0" /* offset 695 */ "\x7a\xcc\x87\0" /* offset 699 */ "\x5a\xcc\x8c\0" /* offset 703 */ "\x7a\xcc\x8c\0" /* offset 707 */ "\x73\0" /* offset 711 */ "\x4f\xcc\x9b\0" /* offset 713 */ "\x6f\xcc\x9b\0" /* offset 717 */ "\x55\xcc\x9b\0" /* offset 721 */ "\x75\xcc\x9b\0" /* offset 725 */ "\x44\x5a\xcc\x8c\0" /* offset 729 */ "\x44\x7a\xcc\x8c\0" /* offset 734 */ "\x64\x7a\xcc\x8c\0" /* offset 739 */ "\x4c\x4a\0" /* offset 744 */ "\x4c\x6a\0" /* offset 747 */ "\x6c\x6a\0" /* offset 750 */ "\x4e\x4a\0" /* offset 753 */ "\x4e\x6a\0" /* offset 756 */ "\x6e\x6a\0" /* offset 759 */ "\x41\xcc\x8c\0" /* offset 762 */ "\x61\xcc\x8c\0" /* offset 766 */ "\x49\xcc\x8c\0" /* offset 770 */ "\x69\xcc\x8c\0" /* offset 774 */ "\x4f\xcc\x8c\0" /* offset 778 */ "\x6f\xcc\x8c\0" /* offset 782 */ "\x55\xcc\x8c\0" /* offset 786 */ "\x75\xcc\x8c\0" /* offset 790 */ "\x55\xcc\x88\xcc\x84\0" /* offset 794 */ "\x75\xcc\x88\xcc\x84\0" /* offset 800 */ "\x55\xcc\x88\xcc\x81\0" /* offset 806 */ "\x75\xcc\x88\xcc\x81\0" /* offset 812 */ "\x55\xcc\x88\xcc\x8c\0" /* offset 818 */ "\x75\xcc\x88\xcc\x8c\0" /* offset 824 */ "\x55\xcc\x88\xcc\x80\0" /* offset 830 */ "\x75\xcc\x88\xcc\x80\0" /* offset 836 */ "\x41\xcc\x88\xcc\x84\0" /* offset 842 */ "\x61\xcc\x88\xcc\x84\0" /* offset 848 */ "\x41\xcc\x87\xcc\x84\0" /* offset 854 */ "\x61\xcc\x87\xcc\x84\0" /* offset 860 */ "\xc3\x86\xcc\x84\0" /* offset 866 */ "\xc3\xa6\xcc\x84\0" /* offset 871 */ "\x47\xcc\x8c\0" /* offset 876 */ "\x67\xcc\x8c\0" /* offset 880 */ "\x4b\xcc\x8c\0" /* offset 884 */ "\x6b\xcc\x8c\0" /* offset 888 */ "\x4f\xcc\xa8\0" /* offset 892 */ "\x6f\xcc\xa8\0" /* offset 896 */ "\x4f\xcc\xa8\xcc\x84\0" /* offset 900 */ "\x6f\xcc\xa8\xcc\x84\0" /* offset 906 */ "\xc6\xb7\xcc\x8c\0" /* offset 912 */ "\xca\x92\xcc\x8c\0" /* offset 917 */ "\x6a\xcc\x8c\0" /* offset 922 */ "\x44\x5a\0" /* offset 926 */ "\x44\x7a\0" /* offset 929 */ "\x64\x7a\0" /* offset 932 */ "\x47\xcc\x81\0" /* offset 935 */ "\x67\xcc\x81\0" /* offset 939 */ "\x4e\xcc\x80\0" /* offset 943 */ "\x6e\xcc\x80\0" /* offset 947 */ "\x41\xcc\x8a\xcc\x81\0" /* offset 951 */ "\x61\xcc\x8a\xcc\x81\0" /* offset 957 */ "\xc3\x86\xcc\x81\0" /* offset 963 */ "\xc3\xa6\xcc\x81\0" /* offset 968 */ "\xc3\x98\xcc\x81\0" /* offset 973 */ "\xc3\xb8\xcc\x81\0" /* offset 978 */ "\x41\xcc\x8f\0" /* offset 983 */ "\x61\xcc\x8f\0" /* offset 987 */ "\x41\xcc\x91\0" /* offset 991 */ "\x61\xcc\x91\0" /* offset 995 */ "\x45\xcc\x8f\0" /* offset 999 */ "\x65\xcc\x8f\0" /* offset 1003 */ "\x45\xcc\x91\0" /* offset 1007 */ "\x65\xcc\x91\0" /* offset 1011 */ "\x49\xcc\x8f\0" /* offset 1015 */ "\x69\xcc\x8f\0" /* offset 1019 */ "\x49\xcc\x91\0" /* offset 1023 */ "\x69\xcc\x91\0" /* offset 1027 */ "\x4f\xcc\x8f\0" /* offset 1031 */ "\x6f\xcc\x8f\0" /* offset 1035 */ "\x4f\xcc\x91\0" /* offset 1039 */ "\x6f\xcc\x91\0" /* offset 1043 */ "\x52\xcc\x8f\0" /* offset 1047 */ "\x72\xcc\x8f\0" /* offset 1051 */ "\x52\xcc\x91\0" /* offset 1055 */ "\x72\xcc\x91\0" /* offset 1059 */ "\x55\xcc\x8f\0" /* offset 1063 */ "\x75\xcc\x8f\0" /* offset 1067 */ "\x55\xcc\x91\0" /* offset 1071 */ "\x75\xcc\x91\0" /* offset 1075 */ "\x53\xcc\xa6\0" /* offset 1079 */ "\x73\xcc\xa6\0" /* offset 1083 */ "\x54\xcc\xa6\0" /* offset 1087 */ "\x74\xcc\xa6\0" /* offset 1091 */ "\x48\xcc\x8c\0" /* offset 1095 */ "\x68\xcc\x8c\0" /* offset 1099 */ "\x41\xcc\x87\0" /* offset 1103 */ "\x61\xcc\x87\0" /* offset 1107 */ "\x45\xcc\xa7\0" /* offset 1111 */ "\x65\xcc\xa7\0" /* offset 1115 */ "\x4f\xcc\x88\xcc\x84\0" /* offset 1119 */ "\x6f\xcc\x88\xcc\x84\0" /* offset 1125 */ "\x4f\xcc\x83\xcc\x84\0" /* offset 1131 */ "\x6f\xcc\x83\xcc\x84\0" /* offset 1137 */ "\x4f\xcc\x87\0" /* offset 1143 */ "\x6f\xcc\x87\0" /* offset 1147 */ "\x4f\xcc\x87\xcc\x84\0" /* offset 1151 */ "\x6f\xcc\x87\xcc\x84\0" /* offset 1157 */ "\x59\xcc\x84\0" /* offset 1163 */ "\x79\xcc\x84\0" /* offset 1167 */ "\x68\0" /* offset 1171 */ "\xc9\xa6\0" /* offset 1173 */ "\x6a\0" /* offset 1176 */ "\x72\0" /* offset 1178 */ "\xc9\xb9\0" /* offset 1180 */ "\xc9\xbb\0" /* offset 1183 */ "\xca\x81\0" /* offset 1186 */ "\x77\0" /* offset 1189 */ "\x79\0" /* offset 1191 */ "\x20\xcc\x86\0" /* offset 1193 */ "\x20\xcc\x87\0" /* offset 1197 */ "\x20\xcc\x8a\0" /* offset 1201 */ "\x20\xcc\xa8\0" /* offset 1205 */ "\x20\xcc\x83\0" /* offset 1209 */ "\x20\xcc\x8b\0" /* offset 1213 */ "\xc9\xa3\0" /* offset 1217 */ "\x6c\0" /* offset 1220 */ "\x78\0" /* offset 1222 */ "\xca\x95\0" /* offset 1224 */ "\xcc\x80\0" /* offset 1227 */ "\xcc\x81\0" /* offset 1230 */ "\xcc\x93\0" /* offset 1233 */ "\xcc\x88\xcc\x81\0" /* offset 1236 */ "\xca\xb9\0" /* offset 1241 */ "\x20\xcd\x85\0" /* offset 1244 */ "\x3b\0" /* offset 1248 */ "\xc2\xa8\xcc\x81\0" /* offset 1250 */ "\x20\xcc\x88\xcc\x81\0" /* offset 1255 */ "\xce\x91\xcc\x81\0" /* offset 1261 */ "\xc2\xb7\0" /* offset 1266 */ "\xce\x95\xcc\x81\0" /* offset 1269 */ "\xce\x97\xcc\x81\0" /* offset 1274 */ "\xce\x99\xcc\x81\0" /* offset 1279 */ "\xce\x9f\xcc\x81\0" /* offset 1284 */ "\xce\xa5\xcc\x81\0" /* offset 1289 */ "\xce\xa9\xcc\x81\0" /* offset 1294 */ "\xce\xb9\xcc\x88\xcc\x81\0" /* offset 1299 */ "\xce\x99\xcc\x88\0" /* offset 1306 */ "\xce\xa5\xcc\x88\0" /* offset 1311 */ "\xce\xb1\xcc\x81\0" /* offset 1316 */ "\xce\xb5\xcc\x81\0" /* offset 1321 */ "\xce\xb7\xcc\x81\0" /* offset 1326 */ "\xce\xb9\xcc\x81\0" /* offset 1331 */ "\xcf\x85\xcc\x88\xcc\x81\0" /* offset 1336 */ "\xce\xb9\xcc\x88\0" /* offset 1343 */ "\xcf\x85\xcc\x88\0" /* offset 1348 */ "\xce\xbf\xcc\x81\0" /* offset 1353 */ "\xcf\x85\xcc\x81\0" /* offset 1358 */ "\xcf\x89\xcc\x81\0" /* offset 1363 */ "\xce\xb2\0" /* offset 1368 */ "\xce\xb8\0" /* offset 1371 */ "\xce\xa5\0" /* offset 1374 */ "\xcf\x92\xcc\x81\0" /* offset 1377 */ "\xcf\x92\xcc\x88\0" /* offset 1382 */ "\xcf\x86\0" /* offset 1387 */ "\xcf\x80\0" /* offset 1390 */ "\xce\xba\0" /* offset 1393 */ "\xcf\x81\0" /* offset 1396 */ "\xcf\x82\0" /* offset 1399 */ "\xce\x98\0" /* offset 1402 */ "\xce\xb5\0" /* offset 1405 */ "\xd0\x95\xcc\x80\0" /* offset 1408 */ "\xd0\x95\xcc\x88\0" /* offset 1413 */ "\xd0\x93\xcc\x81\0" /* offset 1418 */ "\xd0\x86\xcc\x88\0" /* offset 1423 */ "\xd0\x9a\xcc\x81\0" /* offset 1428 */ "\xd0\x98\xcc\x80\0" /* offset 1433 */ "\xd0\xa3\xcc\x86\0" /* offset 1438 */ "\xd0\x98\xcc\x86\0" /* offset 1443 */ "\xd0\xb8\xcc\x86\0" /* offset 1448 */ "\xd0\xb5\xcc\x80\0" /* offset 1453 */ "\xd0\xb5\xcc\x88\0" /* offset 1458 */ "\xd0\xb3\xcc\x81\0" /* offset 1463 */ "\xd1\x96\xcc\x88\0" /* offset 1468 */ "\xd0\xba\xcc\x81\0" /* offset 1473 */ "\xd0\xb8\xcc\x80\0" /* offset 1478 */ "\xd1\x83\xcc\x86\0" /* offset 1483 */ "\xd1\xb4\xcc\x8f\0" /* offset 1488 */ "\xd1\xb5\xcc\x8f\0" /* offset 1493 */ "\xd0\x96\xcc\x86\0" /* offset 1498 */ "\xd0\xb6\xcc\x86\0" /* offset 1503 */ "\xd0\x90\xcc\x86\0" /* offset 1508 */ "\xd0\xb0\xcc\x86\0" /* offset 1513 */ "\xd0\x90\xcc\x88\0" /* offset 1518 */ "\xd0\xb0\xcc\x88\0" /* offset 1523 */ "\xd0\x95\xcc\x86\0" /* offset 1528 */ "\xd0\xb5\xcc\x86\0" /* offset 1533 */ "\xd3\x98\xcc\x88\0" /* offset 1538 */ "\xd3\x99\xcc\x88\0" /* offset 1543 */ "\xd0\x96\xcc\x88\0" /* offset 1548 */ "\xd0\xb6\xcc\x88\0" /* offset 1553 */ "\xd0\x97\xcc\x88\0" /* offset 1558 */ "\xd0\xb7\xcc\x88\0" /* offset 1563 */ "\xd0\x98\xcc\x84\0" /* offset 1568 */ "\xd0\xb8\xcc\x84\0" /* offset 1573 */ "\xd0\x98\xcc\x88\0" /* offset 1578 */ "\xd0\xb8\xcc\x88\0" /* offset 1583 */ "\xd0\x9e\xcc\x88\0" /* offset 1588 */ "\xd0\xbe\xcc\x88\0" /* offset 1593 */ "\xd3\xa8\xcc\x88\0" /* offset 1598 */ "\xd3\xa9\xcc\x88\0" /* offset 1603 */ "\xd0\xad\xcc\x88\0" /* offset 1608 */ "\xd1\x8d\xcc\x88\0" /* offset 1613 */ "\xd0\xa3\xcc\x84\0" /* offset 1618 */ "\xd1\x83\xcc\x84\0" /* offset 1623 */ "\xd0\xa3\xcc\x88\0" /* offset 1628 */ "\xd1\x83\xcc\x88\0" /* offset 1633 */ "\xd0\xa3\xcc\x8b\0" /* offset 1638 */ "\xd1\x83\xcc\x8b\0" /* offset 1643 */ "\xd0\xa7\xcc\x88\0" /* offset 1648 */ "\xd1\x87\xcc\x88\0" /* offset 1653 */ "\xd0\xab\xcc\x88\0" /* offset 1658 */ "\xd1\x8b\xcc\x88\0" /* offset 1663 */ "\xd5\xa5\xd6\x82\0" /* offset 1668 */ "\xd8\xa7\xd9\x93\0" /* offset 1673 */ "\xd8\xa7\xd9\x94\0" /* offset 1678 */ "\xd9\x88\xd9\x94\0" /* offset 1683 */ "\xd8\xa7\xd9\x95\0" /* offset 1688 */ "\xd9\x8a\xd9\x94\0" /* offset 1693 */ "\xd8\xa7\xd9\xb4\0" /* offset 1698 */ "\xd9\x88\xd9\xb4\0" /* offset 1703 */ "\xdb\x87\xd9\xb4\0" /* offset 1708 */ "\xd9\x8a\xd9\xb4\0" /* offset 1713 */ "\xdb\x95\xd9\x94\0" /* offset 1718 */ "\xdb\x81\xd9\x94\0" /* offset 1723 */ "\xdb\x92\xd9\x94\0" /* offset 1728 */ "\xe0\xa4\xa8\xe0\xa4\xbc\0" /* offset 1733 */ "\xe0\xa4\xb0\xe0\xa4\xbc\0" /* offset 1740 */ "\xe0\xa4\xb3\xe0\xa4\xbc\0" /* offset 1747 */ "\xe0\xa4\x95\xe0\xa4\xbc\0" /* offset 1754 */ "\xe0\xa4\x96\xe0\xa4\xbc\0" /* offset 1761 */ "\xe0\xa4\x97\xe0\xa4\xbc\0" /* offset 1768 */ "\xe0\xa4\x9c\xe0\xa4\xbc\0" /* offset 1775 */ "\xe0\xa4\xa1\xe0\xa4\xbc\0" /* offset 1782 */ "\xe0\xa4\xa2\xe0\xa4\xbc\0" /* offset 1789 */ "\xe0\xa4\xab\xe0\xa4\xbc\0" /* offset 1796 */ "\xe0\xa4\xaf\xe0\xa4\xbc\0" /* offset 1803 */ "\xe0\xa7\x87\xe0\xa6\xbe\0" /* offset 1810 */ "\xe0\xa7\x87\xe0\xa7\x97\0" /* offset 1817 */ "\xe0\xa6\xa1\xe0\xa6\xbc\0" /* offset 1824 */ "\xe0\xa6\xa2\xe0\xa6\xbc\0" /* offset 1831 */ "\xe0\xa6\xaf\xe0\xa6\xbc\0" /* offset 1838 */ "\xe0\xa8\xb2\xe0\xa8\xbc\0" /* offset 1845 */ "\xe0\xa8\xb8\xe0\xa8\xbc\0" /* offset 1852 */ "\xe0\xa8\x96\xe0\xa8\xbc\0" /* offset 1859 */ "\xe0\xa8\x97\xe0\xa8\xbc\0" /* offset 1866 */ "\xe0\xa8\x9c\xe0\xa8\xbc\0" /* offset 1873 */ "\xe0\xa8\xab\xe0\xa8\xbc\0" /* offset 1880 */ "\xe0\xad\x87\xe0\xad\x96\0" /* offset 1887 */ "\xe0\xad\x87\xe0\xac\xbe\0" /* offset 1894 */ "\xe0\xad\x87\xe0\xad\x97\0" /* offset 1901 */ "\xe0\xac\xa1\xe0\xac\xbc\0" /* offset 1908 */ "\xe0\xac\xa2\xe0\xac\xbc\0" /* offset 1915 */ "\xe0\xae\x92\xe0\xaf\x97\0" /* offset 1922 */ "\xe0\xaf\x86\xe0\xae\xbe\0" /* offset 1929 */ "\xe0\xaf\x87\xe0\xae\xbe\0" /* offset 1936 */ "\xe0\xaf\x86\xe0\xaf\x97\0" /* offset 1943 */ "\xe0\xb1\x86\xe0\xb1\x96\0" /* offset 1950 */ "\xe0\xb2\xbf\xe0\xb3\x95\0" /* offset 1957 */ "\xe0\xb3\x86\xe0\xb3\x95\0" /* offset 1964 */ "\xe0\xb3\x86\xe0\xb3\x96\0" /* offset 1971 */ "\xe0\xb3\x86\xe0\xb3\x82\0" /* offset 1978 */ "\xe0\xb3\x86\xe0\xb3\x82\xe0\xb3\x95\0" /* offset 1985 */ "\xe0\xb5\x86\xe0\xb4\xbe\0" /* offset 1995 */ "\xe0\xb5\x87\xe0\xb4\xbe\0" /* offset 2002 */ "\xe0\xb5\x86\xe0\xb5\x97\0" /* offset 2009 */ "\xe0\xb7\x99\xe0\xb7\x8a\0" /* offset 2016 */ "\xe0\xb7\x99\xe0\xb7\x8f\0" /* offset 2023 */ "\xe0\xb7\x99\xe0\xb7\x8f\xe0\xb7\x8a\0" /* offset 2030 */ "\xe0\xb7\x99\xe0\xb7\x9f\0" /* offset 2040 */ "\xe0\xb9\x8d\xe0\xb8\xb2\0" /* offset 2047 */ "\xe0\xbb\x8d\xe0\xba\xb2\0" /* offset 2054 */ "\xe0\xba\xab\xe0\xba\x99\0" /* offset 2061 */ "\xe0\xba\xab\xe0\xba\xa1\0" /* offset 2068 */ "\xe0\xbc\x8b\0" /* offset 2075 */ "\xe0\xbd\x82\xe0\xbe\xb7\0" /* offset 2079 */ "\xe0\xbd\x8c\xe0\xbe\xb7\0" /* offset 2086 */ "\xe0\xbd\x91\xe0\xbe\xb7\0" /* offset 2093 */ "\xe0\xbd\x96\xe0\xbe\xb7\0" /* offset 2100 */ "\xe0\xbd\x9b\xe0\xbe\xb7\0" /* offset 2107 */ "\xe0\xbd\x80\xe0\xbe\xb5\0" /* offset 2114 */ "\xe0\xbd\xb1\xe0\xbd\xb2\0" /* offset 2121 */ "\xe0\xbd\xb1\xe0\xbd\xb4\0" /* offset 2128 */ "\xe0\xbe\xb2\xe0\xbe\x80\0" /* offset 2135 */ "\xe0\xbe\xb2\xe0\xbd\xb1\xe0\xbe\x80\0" /* offset 2142 */ "\xe0\xbe\xb3\xe0\xbe\x80\0" /* offset 2152 */ "\xe0\xbe\xb3\xe0\xbd\xb1\xe0\xbe\x80\0" /* offset 2159 */ "\xe0\xbd\xb1\xe0\xbe\x80\0" /* offset 2169 */ "\xe0\xbe\x92\xe0\xbe\xb7\0" /* offset 2176 */ "\xe0\xbe\x9c\xe0\xbe\xb7\0" /* offset 2183 */ "\xe0\xbe\xa1\xe0\xbe\xb7\0" /* offset 2190 */ "\xe0\xbe\xa6\xe0\xbe\xb7\0" /* offset 2197 */ "\xe0\xbe\xab\xe0\xbe\xb7\0" /* offset 2204 */ "\xe0\xbe\x90\xe0\xbe\xb5\0" /* offset 2211 */ "\xe1\x80\xa5\xe1\x80\xae\0" /* offset 2218 */ "\x41\xcc\xa5\0" /* offset 2225 */ "\x61\xcc\xa5\0" /* offset 2229 */ "\x42\xcc\x87\0" /* offset 2233 */ "\x62\xcc\x87\0" /* offset 2237 */ "\x42\xcc\xa3\0" /* offset 2241 */ "\x62\xcc\xa3\0" /* offset 2245 */ "\x42\xcc\xb1\0" /* offset 2249 */ "\x62\xcc\xb1\0" /* offset 2253 */ "\x43\xcc\xa7\xcc\x81\0" /* offset 2257 */ "\x63\xcc\xa7\xcc\x81\0" /* offset 2263 */ "\x44\xcc\x87\0" /* offset 2269 */ "\x64\xcc\x87\0" /* offset 2273 */ "\x44\xcc\xa3\0" /* offset 2277 */ "\x64\xcc\xa3\0" /* offset 2281 */ "\x44\xcc\xb1\0" /* offset 2285 */ "\x64\xcc\xb1\0" /* offset 2289 */ "\x44\xcc\xa7\0" /* offset 2293 */ "\x64\xcc\xa7\0" /* offset 2297 */ "\x44\xcc\xad\0" /* offset 2301 */ "\x64\xcc\xad\0" /* offset 2305 */ "\x45\xcc\x84\xcc\x80\0" /* offset 2309 */ "\x65\xcc\x84\xcc\x80\0" /* offset 2315 */ "\x45\xcc\x84\xcc\x81\0" /* offset 2321 */ "\x65\xcc\x84\xcc\x81\0" /* offset 2327 */ "\x45\xcc\xad\0" /* offset 2333 */ "\x65\xcc\xad\0" /* offset 2337 */ "\x45\xcc\xb0\0" /* offset 2341 */ "\x65\xcc\xb0\0" /* offset 2345 */ "\x45\xcc\xa7\xcc\x86\0" /* offset 2349 */ "\x65\xcc\xa7\xcc\x86\0" /* offset 2355 */ "\x46\xcc\x87\0" /* offset 2361 */ "\x66\xcc\x87\0" /* offset 2365 */ "\x47\xcc\x84\0" /* offset 2369 */ "\x67\xcc\x84\0" /* offset 2373 */ "\x48\xcc\x87\0" /* offset 2377 */ "\x68\xcc\x87\0" /* offset 2381 */ "\x48\xcc\xa3\0" /* offset 2385 */ "\x68\xcc\xa3\0" /* offset 2389 */ "\x48\xcc\x88\0" /* offset 2393 */ "\x68\xcc\x88\0" /* offset 2397 */ "\x48\xcc\xa7\0" /* offset 2401 */ "\x68\xcc\xa7\0" /* offset 2405 */ "\x48\xcc\xae\0" /* offset 2409 */ "\x68\xcc\xae\0" /* offset 2413 */ "\x49\xcc\xb0\0" /* offset 2417 */ "\x69\xcc\xb0\0" /* offset 2421 */ "\x49\xcc\x88\xcc\x81\0" /* offset 2425 */ "\x69\xcc\x88\xcc\x81\0" /* offset 2431 */ "\x4b\xcc\x81\0" /* offset 2437 */ "\x6b\xcc\x81\0" /* offset 2441 */ "\x4b\xcc\xa3\0" /* offset 2445 */ "\x6b\xcc\xa3\0" /* offset 2449 */ "\x4b\xcc\xb1\0" /* offset 2453 */ "\x6b\xcc\xb1\0" /* offset 2457 */ "\x4c\xcc\xa3\0" /* offset 2461 */ "\x6c\xcc\xa3\0" /* offset 2465 */ "\x4c\xcc\xa3\xcc\x84\0" /* offset 2469 */ "\x6c\xcc\xa3\xcc\x84\0" /* offset 2475 */ "\x4c\xcc\xb1\0" /* offset 2481 */ "\x6c\xcc\xb1\0" /* offset 2485 */ "\x4c\xcc\xad\0" /* offset 2489 */ "\x6c\xcc\xad\0" /* offset 2493 */ "\x4d\xcc\x81\0" /* offset 2497 */ "\x6d\xcc\x81\0" /* offset 2501 */ "\x4d\xcc\x87\0" /* offset 2505 */ "\x6d\xcc\x87\0" /* offset 2509 */ "\x4d\xcc\xa3\0" /* offset 2513 */ "\x6d\xcc\xa3\0" /* offset 2517 */ "\x4e\xcc\x87\0" /* offset 2521 */ "\x6e\xcc\x87\0" /* offset 2525 */ "\x4e\xcc\xa3\0" /* offset 2529 */ "\x6e\xcc\xa3\0" /* offset 2533 */ "\x4e\xcc\xb1\0" /* offset 2537 */ "\x6e\xcc\xb1\0" /* offset 2541 */ "\x4e\xcc\xad\0" /* offset 2545 */ "\x6e\xcc\xad\0" /* offset 2549 */ "\x4f\xcc\x83\xcc\x81\0" /* offset 2553 */ "\x6f\xcc\x83\xcc\x81\0" /* offset 2559 */ "\x4f\xcc\x83\xcc\x88\0" /* offset 2565 */ "\x6f\xcc\x83\xcc\x88\0" /* offset 2571 */ "\x4f\xcc\x84\xcc\x80\0" /* offset 2577 */ "\x6f\xcc\x84\xcc\x80\0" /* offset 2583 */ "\x4f\xcc\x84\xcc\x81\0" /* offset 2589 */ "\x6f\xcc\x84\xcc\x81\0" /* offset 2595 */ "\x50\xcc\x81\0" /* offset 2601 */ "\x70\xcc\x81\0" /* offset 2605 */ "\x50\xcc\x87\0" /* offset 2609 */ "\x70\xcc\x87\0" /* offset 2613 */ "\x52\xcc\x87\0" /* offset 2617 */ "\x72\xcc\x87\0" /* offset 2621 */ "\x52\xcc\xa3\0" /* offset 2625 */ "\x72\xcc\xa3\0" /* offset 2629 */ "\x52\xcc\xa3\xcc\x84\0" /* offset 2633 */ "\x72\xcc\xa3\xcc\x84\0" /* offset 2639 */ "\x52\xcc\xb1\0" /* offset 2645 */ "\x72\xcc\xb1\0" /* offset 2649 */ "\x53\xcc\x87\0" /* offset 2653 */ "\x73\xcc\x87\0" /* offset 2657 */ "\x53\xcc\xa3\0" /* offset 2661 */ "\x73\xcc\xa3\0" /* offset 2665 */ "\x53\xcc\x81\xcc\x87\0" /* offset 2669 */ "\x73\xcc\x81\xcc\x87\0" /* offset 2675 */ "\x53\xcc\x8c\xcc\x87\0" /* offset 2681 */ "\x73\xcc\x8c\xcc\x87\0" /* offset 2687 */ "\x53\xcc\xa3\xcc\x87\0" /* offset 2693 */ "\x73\xcc\xa3\xcc\x87\0" /* offset 2699 */ "\x54\xcc\x87\0" /* offset 2705 */ "\x74\xcc\x87\0" /* offset 2709 */ "\x54\xcc\xa3\0" /* offset 2713 */ "\x74\xcc\xa3\0" /* offset 2717 */ "\x54\xcc\xb1\0" /* offset 2721 */ "\x74\xcc\xb1\0" /* offset 2725 */ "\x54\xcc\xad\0" /* offset 2729 */ "\x74\xcc\xad\0" /* offset 2733 */ "\x55\xcc\xa4\0" /* offset 2737 */ "\x75\xcc\xa4\0" /* offset 2741 */ "\x55\xcc\xb0\0" /* offset 2745 */ "\x75\xcc\xb0\0" /* offset 2749 */ "\x55\xcc\xad\0" /* offset 2753 */ "\x75\xcc\xad\0" /* offset 2757 */ "\x55\xcc\x83\xcc\x81\0" /* offset 2761 */ "\x75\xcc\x83\xcc\x81\0" /* offset 2767 */ "\x55\xcc\x84\xcc\x88\0" /* offset 2773 */ "\x75\xcc\x84\xcc\x88\0" /* offset 2779 */ "\x56\xcc\x83\0" /* offset 2785 */ "\x76\xcc\x83\0" /* offset 2789 */ "\x56\xcc\xa3\0" /* offset 2793 */ "\x76\xcc\xa3\0" /* offset 2797 */ "\x57\xcc\x80\0" /* offset 2801 */ "\x77\xcc\x80\0" /* offset 2805 */ "\x57\xcc\x81\0" /* offset 2809 */ "\x77\xcc\x81\0" /* offset 2813 */ "\x57\xcc\x88\0" /* offset 2817 */ "\x77\xcc\x88\0" /* offset 2821 */ "\x57\xcc\x87\0" /* offset 2825 */ "\x77\xcc\x87\0" /* offset 2829 */ "\x57\xcc\xa3\0" /* offset 2833 */ "\x77\xcc\xa3\0" /* offset 2837 */ "\x58\xcc\x87\0" /* offset 2841 */ "\x78\xcc\x87\0" /* offset 2845 */ "\x58\xcc\x88\0" /* offset 2849 */ "\x78\xcc\x88\0" /* offset 2853 */ "\x59\xcc\x87\0" /* offset 2857 */ "\x79\xcc\x87\0" /* offset 2861 */ "\x5a\xcc\x82\0" /* offset 2865 */ "\x7a\xcc\x82\0" /* offset 2869 */ "\x5a\xcc\xa3\0" /* offset 2873 */ "\x7a\xcc\xa3\0" /* offset 2877 */ "\x5a\xcc\xb1\0" /* offset 2881 */ "\x7a\xcc\xb1\0" /* offset 2885 */ "\x68\xcc\xb1\0" /* offset 2889 */ "\x74\xcc\x88\0" /* offset 2893 */ "\x77\xcc\x8a\0" /* offset 2897 */ "\x79\xcc\x8a\0" /* offset 2901 */ "\x61\xca\xbe\0" /* offset 2905 */ "\xc5\xbf\xcc\x87\0" /* offset 2909 */ "\x41\xcc\xa3\0" /* offset 2914 */ "\x61\xcc\xa3\0" /* offset 2918 */ "\x41\xcc\x89\0" /* offset 2922 */ "\x61\xcc\x89\0" /* offset 2926 */ "\x41\xcc\x82\xcc\x81\0" /* offset 2930 */ "\x61\xcc\x82\xcc\x81\0" /* offset 2936 */ "\x41\xcc\x82\xcc\x80\0" /* offset 2942 */ "\x61\xcc\x82\xcc\x80\0" /* offset 2948 */ "\x41\xcc\x82\xcc\x89\0" /* offset 2954 */ "\x61\xcc\x82\xcc\x89\0" /* offset 2960 */ "\x41\xcc\x82\xcc\x83\0" /* offset 2966 */ "\x61\xcc\x82\xcc\x83\0" /* offset 2972 */ "\x41\xcc\xa3\xcc\x82\0" /* offset 2978 */ "\x61\xcc\xa3\xcc\x82\0" /* offset 2984 */ "\x41\xcc\x86\xcc\x81\0" /* offset 2990 */ "\x61\xcc\x86\xcc\x81\0" /* offset 2996 */ "\x41\xcc\x86\xcc\x80\0" /* offset 3002 */ "\x61\xcc\x86\xcc\x80\0" /* offset 3008 */ "\x41\xcc\x86\xcc\x89\0" /* offset 3014 */ "\x61\xcc\x86\xcc\x89\0" /* offset 3020 */ "\x41\xcc\x86\xcc\x83\0" /* offset 3026 */ "\x61\xcc\x86\xcc\x83\0" /* offset 3032 */ "\x41\xcc\xa3\xcc\x86\0" /* offset 3038 */ "\x61\xcc\xa3\xcc\x86\0" /* offset 3044 */ "\x45\xcc\xa3\0" /* offset 3050 */ "\x65\xcc\xa3\0" /* offset 3054 */ "\x45\xcc\x89\0" /* offset 3058 */ "\x65\xcc\x89\0" /* offset 3062 */ "\x45\xcc\x83\0" /* offset 3066 */ "\x65\xcc\x83\0" /* offset 3070 */ "\x45\xcc\x82\xcc\x81\0" /* offset 3074 */ "\x65\xcc\x82\xcc\x81\0" /* offset 3080 */ "\x45\xcc\x82\xcc\x80\0" /* offset 3086 */ "\x65\xcc\x82\xcc\x80\0" /* offset 3092 */ "\x45\xcc\x82\xcc\x89\0" /* offset 3098 */ "\x65\xcc\x82\xcc\x89\0" /* offset 3104 */ "\x45\xcc\x82\xcc\x83\0" /* offset 3110 */ "\x65\xcc\x82\xcc\x83\0" /* offset 3116 */ "\x45\xcc\xa3\xcc\x82\0" /* offset 3122 */ "\x65\xcc\xa3\xcc\x82\0" /* offset 3128 */ "\x49\xcc\x89\0" /* offset 3134 */ "\x69\xcc\x89\0" /* offset 3138 */ "\x49\xcc\xa3\0" /* offset 3142 */ "\x69\xcc\xa3\0" /* offset 3146 */ "\x4f\xcc\xa3\0" /* offset 3150 */ "\x6f\xcc\xa3\0" /* offset 3154 */ "\x4f\xcc\x89\0" /* offset 3158 */ "\x6f\xcc\x89\0" /* offset 3162 */ "\x4f\xcc\x82\xcc\x81\0" /* offset 3166 */ "\x6f\xcc\x82\xcc\x81\0" /* offset 3172 */ "\x4f\xcc\x82\xcc\x80\0" /* offset 3178 */ "\x6f\xcc\x82\xcc\x80\0" /* offset 3184 */ "\x4f\xcc\x82\xcc\x89\0" /* offset 3190 */ "\x6f\xcc\x82\xcc\x89\0" /* offset 3196 */ "\x4f\xcc\x82\xcc\x83\0" /* offset 3202 */ "\x6f\xcc\x82\xcc\x83\0" /* offset 3208 */ "\x4f\xcc\xa3\xcc\x82\0" /* offset 3214 */ "\x6f\xcc\xa3\xcc\x82\0" /* offset 3220 */ "\x4f\xcc\x9b\xcc\x81\0" /* offset 3226 */ "\x6f\xcc\x9b\xcc\x81\0" /* offset 3232 */ "\x4f\xcc\x9b\xcc\x80\0" /* offset 3238 */ "\x6f\xcc\x9b\xcc\x80\0" /* offset 3244 */ "\x4f\xcc\x9b\xcc\x89\0" /* offset 3250 */ "\x6f\xcc\x9b\xcc\x89\0" /* offset 3256 */ "\x4f\xcc\x9b\xcc\x83\0" /* offset 3262 */ "\x6f\xcc\x9b\xcc\x83\0" /* offset 3268 */ "\x4f\xcc\x9b\xcc\xa3\0" /* offset 3274 */ "\x6f\xcc\x9b\xcc\xa3\0" /* offset 3280 */ "\x55\xcc\xa3\0" /* offset 3286 */ "\x75\xcc\xa3\0" /* offset 3290 */ "\x55\xcc\x89\0" /* offset 3294 */ "\x75\xcc\x89\0" /* offset 3298 */ "\x55\xcc\x9b\xcc\x81\0" /* offset 3302 */ "\x75\xcc\x9b\xcc\x81\0" /* offset 3308 */ "\x55\xcc\x9b\xcc\x80\0" /* offset 3314 */ "\x75\xcc\x9b\xcc\x80\0" /* offset 3320 */ "\x55\xcc\x9b\xcc\x89\0" /* offset 3326 */ "\x75\xcc\x9b\xcc\x89\0" /* offset 3332 */ "\x55\xcc\x9b\xcc\x83\0" /* offset 3338 */ "\x75\xcc\x9b\xcc\x83\0" /* offset 3344 */ "\x55\xcc\x9b\xcc\xa3\0" /* offset 3350 */ "\x75\xcc\x9b\xcc\xa3\0" /* offset 3356 */ "\x59\xcc\x80\0" /* offset 3362 */ "\x79\xcc\x80\0" /* offset 3366 */ "\x59\xcc\xa3\0" /* offset 3370 */ "\x79\xcc\xa3\0" /* offset 3374 */ "\x59\xcc\x89\0" /* offset 3378 */ "\x79\xcc\x89\0" /* offset 3382 */ "\x59\xcc\x83\0" /* offset 3386 */ "\x79\xcc\x83\0" /* offset 3390 */ "\xce\xb1\xcc\x93\0" /* offset 3394 */ "\xce\xb1\xcc\x94\0" /* offset 3399 */ "\xce\xb1\xcc\x93\xcc\x80\0" /* offset 3404 */ "\xce\xb1\xcc\x94\xcc\x80\0" /* offset 3411 */ "\xce\xb1\xcc\x93\xcc\x81\0" /* offset 3418 */ "\xce\xb1\xcc\x94\xcc\x81\0" /* offset 3425 */ "\xce\xb1\xcc\x93\xcd\x82\0" /* offset 3432 */ "\xce\xb1\xcc\x94\xcd\x82\0" /* offset 3439 */ "\xce\x91\xcc\x93\0" /* offset 3446 */ "\xce\x91\xcc\x94\0" /* offset 3451 */ "\xce\x91\xcc\x93\xcc\x80\0" /* offset 3456 */ "\xce\x91\xcc\x94\xcc\x80\0" /* offset 3463 */ "\xce\x91\xcc\x93\xcc\x81\0" /* offset 3470 */ "\xce\x91\xcc\x94\xcc\x81\0" /* offset 3477 */ "\xce\x91\xcc\x93\xcd\x82\0" /* offset 3484 */ "\xce\x91\xcc\x94\xcd\x82\0" /* offset 3491 */ "\xce\xb5\xcc\x93\0" /* offset 3498 */ "\xce\xb5\xcc\x94\0" /* offset 3503 */ "\xce\xb5\xcc\x93\xcc\x80\0" /* offset 3508 */ "\xce\xb5\xcc\x94\xcc\x80\0" /* offset 3515 */ "\xce\xb5\xcc\x93\xcc\x81\0" /* offset 3522 */ "\xce\xb5\xcc\x94\xcc\x81\0" /* offset 3529 */ "\xce\x95\xcc\x93\0" /* offset 3536 */ "\xce\x95\xcc\x94\0" /* offset 3541 */ "\xce\x95\xcc\x93\xcc\x80\0" /* offset 3546 */ "\xce\x95\xcc\x94\xcc\x80\0" /* offset 3553 */ "\xce\x95\xcc\x93\xcc\x81\0" /* offset 3560 */ "\xce\x95\xcc\x94\xcc\x81\0" /* offset 3567 */ "\xce\xb7\xcc\x93\0" /* offset 3574 */ "\xce\xb7\xcc\x94\0" /* offset 3579 */ "\xce\xb7\xcc\x93\xcc\x80\0" /* offset 3584 */ "\xce\xb7\xcc\x94\xcc\x80\0" /* offset 3591 */ "\xce\xb7\xcc\x93\xcc\x81\0" /* offset 3598 */ "\xce\xb7\xcc\x94\xcc\x81\0" /* offset 3605 */ "\xce\xb7\xcc\x93\xcd\x82\0" /* offset 3612 */ "\xce\xb7\xcc\x94\xcd\x82\0" /* offset 3619 */ "\xce\x97\xcc\x93\0" /* offset 3626 */ "\xce\x97\xcc\x94\0" /* offset 3631 */ "\xce\x97\xcc\x93\xcc\x80\0" /* offset 3636 */ "\xce\x97\xcc\x94\xcc\x80\0" /* offset 3643 */ "\xce\x97\xcc\x93\xcc\x81\0" /* offset 3650 */ "\xce\x97\xcc\x94\xcc\x81\0" /* offset 3657 */ "\xce\x97\xcc\x93\xcd\x82\0" /* offset 3664 */ "\xce\x97\xcc\x94\xcd\x82\0" /* offset 3671 */ "\xce\xb9\xcc\x93\0" /* offset 3678 */ "\xce\xb9\xcc\x94\0" /* offset 3683 */ "\xce\xb9\xcc\x93\xcc\x80\0" /* offset 3688 */ "\xce\xb9\xcc\x94\xcc\x80\0" /* offset 3695 */ "\xce\xb9\xcc\x93\xcc\x81\0" /* offset 3702 */ "\xce\xb9\xcc\x94\xcc\x81\0" /* offset 3709 */ "\xce\xb9\xcc\x93\xcd\x82\0" /* offset 3716 */ "\xce\xb9\xcc\x94\xcd\x82\0" /* offset 3723 */ "\xce\x99\xcc\x93\0" /* offset 3730 */ "\xce\x99\xcc\x94\0" /* offset 3735 */ "\xce\x99\xcc\x93\xcc\x80\0" /* offset 3740 */ "\xce\x99\xcc\x94\xcc\x80\0" /* offset 3747 */ "\xce\x99\xcc\x93\xcc\x81\0" /* offset 3754 */ "\xce\x99\xcc\x94\xcc\x81\0" /* offset 3761 */ "\xce\x99\xcc\x93\xcd\x82\0" /* offset 3768 */ "\xce\x99\xcc\x94\xcd\x82\0" /* offset 3775 */ "\xce\xbf\xcc\x93\0" /* offset 3782 */ "\xce\xbf\xcc\x94\0" /* offset 3787 */ "\xce\xbf\xcc\x93\xcc\x80\0" /* offset 3792 */ "\xce\xbf\xcc\x94\xcc\x80\0" /* offset 3799 */ "\xce\xbf\xcc\x93\xcc\x81\0" /* offset 3806 */ "\xce\xbf\xcc\x94\xcc\x81\0" /* offset 3813 */ "\xce\x9f\xcc\x93\0" /* offset 3820 */ "\xce\x9f\xcc\x94\0" /* offset 3825 */ "\xce\x9f\xcc\x93\xcc\x80\0" /* offset 3830 */ "\xce\x9f\xcc\x94\xcc\x80\0" /* offset 3837 */ "\xce\x9f\xcc\x93\xcc\x81\0" /* offset 3844 */ "\xce\x9f\xcc\x94\xcc\x81\0" /* offset 3851 */ "\xcf\x85\xcc\x93\0" /* offset 3858 */ "\xcf\x85\xcc\x94\0" /* offset 3863 */ "\xcf\x85\xcc\x93\xcc\x80\0" /* offset 3868 */ "\xcf\x85\xcc\x94\xcc\x80\0" /* offset 3875 */ "\xcf\x85\xcc\x93\xcc\x81\0" /* offset 3882 */ "\xcf\x85\xcc\x94\xcc\x81\0" /* offset 3889 */ "\xcf\x85\xcc\x93\xcd\x82\0" /* offset 3896 */ "\xcf\x85\xcc\x94\xcd\x82\0" /* offset 3903 */ "\xce\xa5\xcc\x94\0" /* offset 3910 */ "\xce\xa5\xcc\x94\xcc\x80\0" /* offset 3915 */ "\xce\xa5\xcc\x94\xcc\x81\0" /* offset 3922 */ "\xce\xa5\xcc\x94\xcd\x82\0" /* offset 3929 */ "\xcf\x89\xcc\x93\0" /* offset 3936 */ "\xcf\x89\xcc\x94\0" /* offset 3941 */ "\xcf\x89\xcc\x93\xcc\x80\0" /* offset 3946 */ "\xcf\x89\xcc\x94\xcc\x80\0" /* offset 3953 */ "\xcf\x89\xcc\x93\xcc\x81\0" /* offset 3960 */ "\xcf\x89\xcc\x94\xcc\x81\0" /* offset 3967 */ "\xcf\x89\xcc\x93\xcd\x82\0" /* offset 3974 */ "\xcf\x89\xcc\x94\xcd\x82\0" /* offset 3981 */ "\xce\xa9\xcc\x93\0" /* offset 3988 */ "\xce\xa9\xcc\x94\0" /* offset 3993 */ "\xce\xa9\xcc\x93\xcc\x80\0" /* offset 3998 */ "\xce\xa9\xcc\x94\xcc\x80\0" /* offset 4005 */ "\xce\xa9\xcc\x93\xcc\x81\0" /* offset 4012 */ "\xce\xa9\xcc\x94\xcc\x81\0" /* offset 4019 */ "\xce\xa9\xcc\x93\xcd\x82\0" /* offset 4026 */ "\xce\xa9\xcc\x94\xcd\x82\0" /* offset 4033 */ "\xce\xb1\xcc\x80\0" /* offset 4040 */ "\xce\xb5\xcc\x80\0" /* offset 4045 */ "\xce\xb7\xcc\x80\0" /* offset 4050 */ "\xce\xb9\xcc\x80\0" /* offset 4055 */ "\xce\xbf\xcc\x80\0" /* offset 4060 */ "\xcf\x85\xcc\x80\0" /* offset 4065 */ "\xcf\x89\xcc\x80\0" /* offset 4070 */ "\xce\xb1\xcc\x93\xcd\x85\0" /* offset 4075 */ "\xce\xb1\xcc\x94\xcd\x85\0" /* offset 4082 */ "\xce\xb1\xcc\x93\xcc\x80\xcd\x85\0" /* offset 4089 */ "\xce\xb1\xcc\x94\xcc\x80\xcd\x85\0" /* offset 4098 */ "\xce\xb1\xcc\x93\xcc\x81\xcd\x85\0" /* offset 4107 */ "\xce\xb1\xcc\x94\xcc\x81\xcd\x85\0" /* offset 4116 */ "\xce\xb1\xcc\x93\xcd\x82\xcd\x85\0" /* offset 4125 */ "\xce\xb1\xcc\x94\xcd\x82\xcd\x85\0" /* offset 4134 */ "\xce\x91\xcc\x93\xcd\x85\0" /* offset 4143 */ "\xce\x91\xcc\x94\xcd\x85\0" /* offset 4150 */ "\xce\x91\xcc\x93\xcc\x80\xcd\x85\0" /* offset 4157 */ "\xce\x91\xcc\x94\xcc\x80\xcd\x85\0" /* offset 4166 */ "\xce\x91\xcc\x93\xcc\x81\xcd\x85\0" /* offset 4175 */ "\xce\x91\xcc\x94\xcc\x81\xcd\x85\0" /* offset 4184 */ "\xce\x91\xcc\x93\xcd\x82\xcd\x85\0" /* offset 4193 */ "\xce\x91\xcc\x94\xcd\x82\xcd\x85\0" /* offset 4202 */ "\xce\xb7\xcc\x93\xcd\x85\0" /* offset 4211 */ "\xce\xb7\xcc\x94\xcd\x85\0" /* offset 4218 */ "\xce\xb7\xcc\x93\xcc\x80\xcd\x85\0" /* offset 4225 */ "\xce\xb7\xcc\x94\xcc\x80\xcd\x85\0" /* offset 4234 */ "\xce\xb7\xcc\x93\xcc\x81\xcd\x85\0" /* offset 4243 */ "\xce\xb7\xcc\x94\xcc\x81\xcd\x85\0" /* offset 4252 */ "\xce\xb7\xcc\x93\xcd\x82\xcd\x85\0" /* offset 4261 */ "\xce\xb7\xcc\x94\xcd\x82\xcd\x85\0" /* offset 4270 */ "\xce\x97\xcc\x93\xcd\x85\0" /* offset 4279 */ "\xce\x97\xcc\x94\xcd\x85\0" /* offset 4286 */ "\xce\x97\xcc\x93\xcc\x80\xcd\x85\0" /* offset 4293 */ "\xce\x97\xcc\x94\xcc\x80\xcd\x85\0" /* offset 4302 */ "\xce\x97\xcc\x93\xcc\x81\xcd\x85\0" /* offset 4311 */ "\xce\x97\xcc\x94\xcc\x81\xcd\x85\0" /* offset 4320 */ "\xce\x97\xcc\x93\xcd\x82\xcd\x85\0" /* offset 4329 */ "\xce\x97\xcc\x94\xcd\x82\xcd\x85\0" /* offset 4338 */ "\xcf\x89\xcc\x93\xcd\x85\0" /* offset 4347 */ "\xcf\x89\xcc\x94\xcd\x85\0" /* offset 4354 */ "\xcf\x89\xcc\x93\xcc\x80\xcd\x85\0" /* offset 4361 */ "\xcf\x89\xcc\x94\xcc\x80\xcd\x85\0" /* offset 4370 */ "\xcf\x89\xcc\x93\xcc\x81\xcd\x85\0" /* offset 4379 */ "\xcf\x89\xcc\x94\xcc\x81\xcd\x85\0" /* offset 4388 */ "\xcf\x89\xcc\x93\xcd\x82\xcd\x85\0" /* offset 4397 */ "\xcf\x89\xcc\x94\xcd\x82\xcd\x85\0" /* offset 4406 */ "\xce\xa9\xcc\x93\xcd\x85\0" /* offset 4415 */ "\xce\xa9\xcc\x94\xcd\x85\0" /* offset 4422 */ "\xce\xa9\xcc\x93\xcc\x80\xcd\x85\0" /* offset 4429 */ "\xce\xa9\xcc\x94\xcc\x80\xcd\x85\0" /* offset 4438 */ "\xce\xa9\xcc\x93\xcc\x81\xcd\x85\0" /* offset 4447 */ "\xce\xa9\xcc\x94\xcc\x81\xcd\x85\0" /* offset 4456 */ "\xce\xa9\xcc\x93\xcd\x82\xcd\x85\0" /* offset 4465 */ "\xce\xa9\xcc\x94\xcd\x82\xcd\x85\0" /* offset 4474 */ "\xce\xb1\xcc\x86\0" /* offset 4483 */ "\xce\xb1\xcc\x84\0" /* offset 4488 */ "\xce\xb1\xcc\x80\xcd\x85\0" /* offset 4493 */ "\xce\xb1\xcd\x85\0" /* offset 4500 */ "\xce\xb1\xcc\x81\xcd\x85\0" /* offset 4505 */ "\xce\xb1\xcd\x82\0" /* offset 4512 */ "\xce\xb1\xcd\x82\xcd\x85\0" /* offset 4517 */ "\xce\x91\xcc\x86\0" /* offset 4524 */ "\xce\x91\xcc\x84\0" /* offset 4529 */ "\xce\x91\xcc\x80\0" /* offset 4534 */ "\xce\x91\xcd\x85\0" /* offset 4539 */ "\x20\xcc\x93\0" /* offset 4544 */ "\xce\xb9\0" /* offset 4548 */ "\x20\xcd\x82\0" /* offset 4551 */ "\xc2\xa8\xcd\x82\0" /* offset 4555 */ "\x20\xcc\x88\xcd\x82\0" /* offset 4560 */ "\xce\xb7\xcc\x80\xcd\x85\0" /* offset 4566 */ "\xce\xb7\xcd\x85\0" /* offset 4573 */ "\xce\xb7\xcc\x81\xcd\x85\0" /* offset 4578 */ "\xce\xb7\xcd\x82\0" /* offset 4585 */ "\xce\xb7\xcd\x82\xcd\x85\0" /* offset 4590 */ "\xce\x95\xcc\x80\0" /* offset 4597 */ "\xce\x97\xcc\x80\0" /* offset 4602 */ "\xce\x97\xcd\x85\0" /* offset 4607 */ "\xe1\xbe\xbf\xcc\x80\0" /* offset 4612 */ "\x20\xcc\x93\xcc\x80\0" /* offset 4618 */ "\xe1\xbe\xbf\xcc\x81\0" /* offset 4624 */ "\x20\xcc\x93\xcc\x81\0" /* offset 4630 */ "\xe1\xbe\xbf\xcd\x82\0" /* offset 4636 */ "\x20\xcc\x93\xcd\x82\0" /* offset 4642 */ "\xce\xb9\xcc\x86\0" /* offset 4648 */ "\xce\xb9\xcc\x84\0" /* offset 4653 */ "\xce\xb9\xcc\x88\xcc\x80\0" /* offset 4658 */ "\xce\xb9\xcd\x82\0" /* offset 4665 */ "\xce\xb9\xcc\x88\xcd\x82\0" /* offset 4670 */ "\xce\x99\xcc\x86\0" /* offset 4677 */ "\xce\x99\xcc\x84\0" /* offset 4682 */ "\xce\x99\xcc\x80\0" /* offset 4687 */ "\xe1\xbf\xbe\xcc\x80\0" /* offset 4692 */ "\x20\xcc\x94\xcc\x80\0" /* offset 4698 */ "\xe1\xbf\xbe\xcc\x81\0" /* offset 4704 */ "\x20\xcc\x94\xcc\x81\0" /* offset 4710 */ "\xe1\xbf\xbe\xcd\x82\0" /* offset 4716 */ "\x20\xcc\x94\xcd\x82\0" /* offset 4722 */ "\xcf\x85\xcc\x86\0" /* offset 4728 */ "\xcf\x85\xcc\x84\0" /* offset 4733 */ "\xcf\x85\xcc\x88\xcc\x80\0" /* offset 4738 */ "\xcf\x81\xcc\x93\0" /* offset 4745 */ "\xcf\x81\xcc\x94\0" /* offset 4750 */ "\xcf\x85\xcd\x82\0" /* offset 4755 */ "\xcf\x85\xcc\x88\xcd\x82\0" /* offset 4760 */ "\xce\xa5\xcc\x86\0" /* offset 4767 */ "\xce\xa5\xcc\x84\0" /* offset 4772 */ "\xce\xa5\xcc\x80\0" /* offset 4777 */ "\xce\xa1\xcc\x94\0" /* offset 4782 */ "\xc2\xa8\xcc\x80\0" /* offset 4787 */ "\x20\xcc\x88\xcc\x80\0" /* offset 4792 */ "\x60\0" /* offset 4798 */ "\xcf\x89\xcc\x80\xcd\x85\0" /* offset 4800 */ "\xcf\x89\xcd\x85\0" /* offset 4807 */ "\xcf\x89\xcc\x81\xcd\x85\0" /* offset 4812 */ "\xcf\x89\xcd\x82\0" /* offset 4819 */ "\xcf\x89\xcd\x82\xcd\x85\0" /* offset 4824 */ "\xce\x9f\xcc\x80\0" /* offset 4831 */ "\xce\xa9\xcc\x80\0" /* offset 4836 */ "\xce\xa9\xcd\x85\0" /* offset 4841 */ "\xc2\xb4\0" /* offset 4846 */ "\x20\xcc\x94\0" /* offset 4849 */ "\xe2\x80\x82\0" /* offset 4853 */ "\xe2\x80\x83\0" /* offset 4857 */ "\xe2\x80\x90\0" /* offset 4861 */ "\x20\xcc\xb3\0" /* offset 4865 */ "\x2e\0" /* offset 4869 */ "\x2e\x2e\0" /* offset 4871 */ "\x2e\x2e\x2e\0" /* offset 4874 */ "\xe2\x80\xb2\xe2\x80\xb2\0" /* offset 4878 */ "\xe2\x80\xb2\xe2\x80\xb2\xe2\x80\xb2\0" /* offset 4885 */ "\xe2\x80\xb5\xe2\x80\xb5\0" /* offset 4895 */ "\xe2\x80\xb5\xe2\x80\xb5\xe2\x80\xb5\0" /* offset 4902 */ "\x21\x21\0" /* offset 4912 */ "\x20\xcc\x85\0" /* offset 4915 */ "\x3f\x3f\0" /* offset 4919 */ "\x3f\x21\0" /* offset 4922 */ "\x21\x3f\0" /* offset 4925 */ "\xe2\x80\xb2\xe2\x80\xb2\xe2\x80\xb2\xe2\x80\xb2\0" /* offset 4928 */ "\x30\0" /* offset 4941 */ "\x69\0" /* offset 4943 */ "\x34\0" /* offset 4945 */ "\x35\0" /* offset 4947 */ "\x36\0" /* offset 4949 */ "\x37\0" /* offset 4951 */ "\x38\0" /* offset 4953 */ "\x39\0" /* offset 4955 */ "\x2b\0" /* offset 4957 */ "\xe2\x88\x92\0" /* offset 4959 */ "\x3d\0" /* offset 4963 */ "\x28\0" /* offset 4965 */ "\x29\0" /* offset 4967 */ "\x6e\0" /* offset 4969 */ "\x52\x73\0" /* offset 4971 */ "\x61\x2f\x63\0" /* offset 4974 */ "\x61\x2f\x73\0" /* offset 4978 */ "\x43\0" /* offset 4982 */ "\xc2\xb0\x43\0" /* offset 4984 */ "\x63\x2f\x6f\0" /* offset 4988 */ "\x63\x2f\x75\0" /* offset 4992 */ "\xc6\x90\0" /* offset 4996 */ "\xc2\xb0\x46\0" /* offset 4999 */ "\x67\0" /* offset 5003 */ "\x48\0" /* offset 5005 */ "\xc4\xa7\0" /* offset 5007 */ "\x49\0" /* offset 5010 */ "\x4c\0" /* offset 5012 */ "\x4e\0" /* offset 5014 */ "\x4e\x6f\0" /* offset 5016 */ "\x50\0" /* offset 5019 */ "\x51\0" /* offset 5021 */ "\x52\0" /* offset 5023 */ "\x53\x4d\0" /* offset 5025 */ "\x54\x45\x4c\0" /* offset 5028 */ "\x54\x4d\0" /* offset 5032 */ "\x5a\0" /* offset 5035 */ "\xce\xa9\0" /* offset 5037 */ "\x4b\0" /* offset 5040 */ "\x42\0" /* offset 5042 */ "\x65\0" /* offset 5044 */ "\x45\0" /* offset 5046 */ "\x46\0" /* offset 5048 */ "\x4d\0" /* offset 5050 */ "\xd7\x90\0" /* offset 5052 */ "\xd7\x91\0" /* offset 5055 */ "\xd7\x92\0" /* offset 5058 */ "\xd7\x93\0" /* offset 5061 */ "\xce\xb3\0" /* offset 5064 */ "\xce\x93\0" /* offset 5067 */ "\xce\xa0\0" /* offset 5070 */ "\xe2\x88\x91\0" /* offset 5073 */ "\x44\0" /* offset 5077 */ "\x64\0" /* offset 5079 */ "\x31\xe2\x81\x84\x33\0" /* offset 5081 */ "\x32\xe2\x81\x84\x33\0" /* offset 5087 */ "\x31\xe2\x81\x84\x35\0" /* offset 5093 */ "\x32\xe2\x81\x84\x35\0" /* offset 5099 */ "\x33\xe2\x81\x84\x35\0" /* offset 5105 */ "\x34\xe2\x81\x84\x35\0" /* offset 5111 */ "\x31\xe2\x81\x84\x36\0" /* offset 5117 */ "\x35\xe2\x81\x84\x36\0" /* offset 5123 */ "\x31\xe2\x81\x84\x38\0" /* offset 5129 */ "\x33\xe2\x81\x84\x38\0" /* offset 5135 */ "\x35\xe2\x81\x84\x38\0" /* offset 5141 */ "\x37\xe2\x81\x84\x38\0" /* offset 5147 */ "\x31\xe2\x81\x84\0" /* offset 5153 */ "\x49\x49\0" /* offset 5158 */ "\x49\x49\x49\0" /* offset 5161 */ "\x49\x56\0" /* offset 5165 */ "\x56\0" /* offset 5168 */ "\x56\x49\0" /* offset 5170 */ "\x56\x49\x49\0" /* offset 5173 */ "\x56\x49\x49\x49\0" /* offset 5177 */ "\x49\x58\0" /* offset 5182 */ "\x58\0" /* offset 5185 */ "\x58\x49\0" /* offset 5187 */ "\x58\x49\x49\0" /* offset 5190 */ "\x69\x69\0" /* offset 5194 */ "\x69\x69\x69\0" /* offset 5197 */ "\x69\x76\0" /* offset 5201 */ "\x76\0" /* offset 5204 */ "\x76\x69\0" /* offset 5206 */ "\x76\x69\x69\0" /* offset 5209 */ "\x76\x69\x69\x69\0" /* offset 5213 */ "\x69\x78\0" /* offset 5218 */ "\x78\x69\0" /* offset 5221 */ "\x78\x69\x69\0" /* offset 5224 */ "\x63\0" /* offset 5228 */ "\x6d\0" /* offset 5230 */ "\xe2\x86\x90\xcc\xb8\0" /* offset 5232 */ "\xe2\x86\x92\xcc\xb8\0" /* offset 5238 */ "\xe2\x86\x94\xcc\xb8\0" /* offset 5244 */ "\xe2\x87\x90\xcc\xb8\0" /* offset 5250 */ "\xe2\x87\x94\xcc\xb8\0" /* offset 5256 */ "\xe2\x87\x92\xcc\xb8\0" /* offset 5262 */ "\xe2\x88\x83\xcc\xb8\0" /* offset 5268 */ "\xe2\x88\x88\xcc\xb8\0" /* offset 5274 */ "\xe2\x88\x8b\xcc\xb8\0" /* offset 5280 */ "\xe2\x88\xa3\xcc\xb8\0" /* offset 5286 */ "\xe2\x88\xa5\xcc\xb8\0" /* offset 5292 */ "\xe2\x88\xab\xe2\x88\xab\0" /* offset 5298 */ "\xe2\x88\xab\xe2\x88\xab\xe2\x88\xab\0" /* offset 5305 */ "\xe2\x88\xae\xe2\x88\xae\0" /* offset 5315 */ "\xe2\x88\xae\xe2\x88\xae\xe2\x88\xae\0" /* offset 5322 */ "\xe2\x88\xbc\xcc\xb8\0" /* offset 5332 */ "\xe2\x89\x83\xcc\xb8\0" /* offset 5338 */ "\xe2\x89\x85\xcc\xb8\0" /* offset 5344 */ "\xe2\x89\x88\xcc\xb8\0" /* offset 5350 */ "\x3d\xcc\xb8\0" /* offset 5356 */ "\xe2\x89\xa1\xcc\xb8\0" /* offset 5360 */ "\xe2\x89\x8d\xcc\xb8\0" /* offset 5366 */ "\x3c\xcc\xb8\0" /* offset 5372 */ "\x3e\xcc\xb8\0" /* offset 5376 */ "\xe2\x89\xa4\xcc\xb8\0" /* offset 5380 */ "\xe2\x89\xa5\xcc\xb8\0" /* offset 5386 */ "\xe2\x89\xb2\xcc\xb8\0" /* offset 5392 */ "\xe2\x89\xb3\xcc\xb8\0" /* offset 5398 */ "\xe2\x89\xb6\xcc\xb8\0" /* offset 5404 */ "\xe2\x89\xb7\xcc\xb8\0" /* offset 5410 */ "\xe2\x89\xba\xcc\xb8\0" /* offset 5416 */ "\xe2\x89\xbb\xcc\xb8\0" /* offset 5422 */ "\xe2\x8a\x82\xcc\xb8\0" /* offset 5428 */ "\xe2\x8a\x83\xcc\xb8\0" /* offset 5434 */ "\xe2\x8a\x86\xcc\xb8\0" /* offset 5440 */ "\xe2\x8a\x87\xcc\xb8\0" /* offset 5446 */ "\xe2\x8a\xa2\xcc\xb8\0" /* offset 5452 */ "\xe2\x8a\xa8\xcc\xb8\0" /* offset 5458 */ "\xe2\x8a\xa9\xcc\xb8\0" /* offset 5464 */ "\xe2\x8a\xab\xcc\xb8\0" /* offset 5470 */ "\xe2\x89\xbc\xcc\xb8\0" /* offset 5476 */ "\xe2\x89\xbd\xcc\xb8\0" /* offset 5482 */ "\xe2\x8a\x91\xcc\xb8\0" /* offset 5488 */ "\xe2\x8a\x92\xcc\xb8\0" /* offset 5494 */ "\xe2\x8a\xb2\xcc\xb8\0" /* offset 5500 */ "\xe2\x8a\xb3\xcc\xb8\0" /* offset 5506 */ "\xe2\x8a\xb4\xcc\xb8\0" /* offset 5512 */ "\xe2\x8a\xb5\xcc\xb8\0" /* offset 5518 */ "\xe3\x80\x88\0" /* offset 5524 */ "\xe3\x80\x89\0" /* offset 5528 */ "\x31\x30\0" /* offset 5532 */ "\x31\x31\0" /* offset 5535 */ "\x31\x32\0" /* offset 5538 */ "\x31\x33\0" /* offset 5541 */ "\x31\x34\0" /* offset 5544 */ "\x31\x35\0" /* offset 5547 */ "\x31\x36\0" /* offset 5550 */ "\x31\x37\0" /* offset 5553 */ "\x31\x38\0" /* offset 5556 */ "\x31\x39\0" /* offset 5559 */ "\x32\x30\0" /* offset 5562 */ "\x28\x31\x29\0" /* offset 5565 */ "\x28\x32\x29\0" /* offset 5569 */ "\x28\x33\x29\0" /* offset 5573 */ "\x28\x34\x29\0" /* offset 5577 */ "\x28\x35\x29\0" /* offset 5581 */ "\x28\x36\x29\0" /* offset 5585 */ "\x28\x37\x29\0" /* offset 5589 */ "\x28\x38\x29\0" /* offset 5593 */ "\x28\x39\x29\0" /* offset 5597 */ "\x28\x31\x30\x29\0" /* offset 5601 */ "\x28\x31\x31\x29\0" /* offset 5606 */ "\x28\x31\x32\x29\0" /* offset 5611 */ "\x28\x31\x33\x29\0" /* offset 5616 */ "\x28\x31\x34\x29\0" /* offset 5621 */ "\x28\x31\x35\x29\0" /* offset 5626 */ "\x28\x31\x36\x29\0" /* offset 5631 */ "\x28\x31\x37\x29\0" /* offset 5636 */ "\x28\x31\x38\x29\0" /* offset 5641 */ "\x28\x31\x39\x29\0" /* offset 5646 */ "\x28\x32\x30\x29\0" /* offset 5651 */ "\x31\x2e\0" /* offset 5656 */ "\x32\x2e\0" /* offset 5659 */ "\x33\x2e\0" /* offset 5662 */ "\x34\x2e\0" /* offset 5665 */ "\x35\x2e\0" /* offset 5668 */ "\x36\x2e\0" /* offset 5671 */ "\x37\x2e\0" /* offset 5674 */ "\x38\x2e\0" /* offset 5677 */ "\x39\x2e\0" /* offset 5680 */ "\x31\x30\x2e\0" /* offset 5683 */ "\x31\x31\x2e\0" /* offset 5687 */ "\x31\x32\x2e\0" /* offset 5691 */ "\x31\x33\x2e\0" /* offset 5695 */ "\x31\x34\x2e\0" /* offset 5699 */ "\x31\x35\x2e\0" /* offset 5703 */ "\x31\x36\x2e\0" /* offset 5707 */ "\x31\x37\x2e\0" /* offset 5711 */ "\x31\x38\x2e\0" /* offset 5715 */ "\x31\x39\x2e\0" /* offset 5719 */ "\x32\x30\x2e\0" /* offset 5723 */ "\x28\x61\x29\0" /* offset 5727 */ "\x28\x62\x29\0" /* offset 5731 */ "\x28\x63\x29\0" /* offset 5735 */ "\x28\x64\x29\0" /* offset 5739 */ "\x28\x65\x29\0" /* offset 5743 */ "\x28\x66\x29\0" /* offset 5747 */ "\x28\x67\x29\0" /* offset 5751 */ "\x28\x68\x29\0" /* offset 5755 */ "\x28\x69\x29\0" /* offset 5759 */ "\x28\x6a\x29\0" /* offset 5763 */ "\x28\x6b\x29\0" /* offset 5767 */ "\x28\x6c\x29\0" /* offset 5771 */ "\x28\x6d\x29\0" /* offset 5775 */ "\x28\x6e\x29\0" /* offset 5779 */ "\x28\x6f\x29\0" /* offset 5783 */ "\x28\x70\x29\0" /* offset 5787 */ "\x28\x71\x29\0" /* offset 5791 */ "\x28\x72\x29\0" /* offset 5795 */ "\x28\x73\x29\0" /* offset 5799 */ "\x28\x74\x29\0" /* offset 5803 */ "\x28\x75\x29\0" /* offset 5807 */ "\x28\x76\x29\0" /* offset 5811 */ "\x28\x77\x29\0" /* offset 5815 */ "\x28\x78\x29\0" /* offset 5819 */ "\x28\x79\x29\0" /* offset 5823 */ "\x28\x7a\x29\0" /* offset 5827 */ "\x41\0" /* offset 5831 */ "\x47\0" /* offset 5833 */ "\x4a\0" /* offset 5835 */ "\x4f\0" /* offset 5837 */ "\x53\0" /* offset 5839 */ "\x54\0" /* offset 5841 */ "\x55\0" /* offset 5843 */ "\x57\0" /* offset 5845 */ "\x59\0" /* offset 5847 */ "\x62\0" /* offset 5849 */ "\x66\0" /* offset 5851 */ "\x6b\0" /* offset 5853 */ "\x70\0" /* offset 5855 */ "\x71\0" /* offset 5857 */ "\x74\0" /* offset 5859 */ "\x75\0" /* offset 5861 */ "\x7a\0" /* offset 5863 */ "\xe2\x88\xab\xe2\x88\xab\xe2\x88\xab\xe2\x88\xab\0" /* offset 5865 */ "\x3a\x3a\x3d\0" /* offset 5878 */ "\x3d\x3d\0" /* offset 5882 */ "\x3d\x3d\x3d\0" /* offset 5885 */ "\xe2\xab\x9d\xcc\xb8\0" /* offset 5889 */ "\xe6\xaf\x8d\0" /* offset 5895 */ "\xe9\xbe\x9f\0" /* offset 5899 */ "\xe4\xb8\x80\0" /* offset 5903 */ "\xe4\xb8\xa8\0" /* offset 5907 */ "\xe4\xb8\xb6\0" /* offset 5911 */ "\xe4\xb8\xbf\0" /* offset 5915 */ "\xe4\xb9\x99\0" /* offset 5919 */ "\xe4\xba\x85\0" /* offset 5923 */ "\xe4\xba\x8c\0" /* offset 5927 */ "\xe4\xba\xa0\0" /* offset 5931 */ "\xe4\xba\xba\0" /* offset 5935 */ "\xe5\x84\xbf\0" /* offset 5939 */ "\xe5\x85\xa5\0" /* offset 5943 */ "\xe5\x85\xab\0" /* offset 5947 */ "\xe5\x86\x82\0" /* offset 5951 */ "\xe5\x86\x96\0" /* offset 5955 */ "\xe5\x86\xab\0" /* offset 5959 */ "\xe5\x87\xa0\0" /* offset 5963 */ "\xe5\x87\xb5\0" /* offset 5967 */ "\xe5\x88\x80\0" /* offset 5971 */ "\xe5\x8a\x9b\0" /* offset 5975 */ "\xe5\x8b\xb9\0" /* offset 5979 */ "\xe5\x8c\x95\0" /* offset 5983 */ "\xe5\x8c\x9a\0" /* offset 5987 */ "\xe5\x8c\xb8\0" /* offset 5991 */ "\xe5\x8d\x81\0" /* offset 5995 */ "\xe5\x8d\x9c\0" /* offset 5999 */ "\xe5\x8d\xa9\0" /* offset 6003 */ "\xe5\x8e\x82\0" /* offset 6007 */ "\xe5\x8e\xb6\0" /* offset 6011 */ "\xe5\x8f\x88\0" /* offset 6015 */ "\xe5\x8f\xa3\0" /* offset 6019 */ "\xe5\x9b\x97\0" /* offset 6023 */ "\xe5\x9c\x9f\0" /* offset 6027 */ "\xe5\xa3\xab\0" /* offset 6031 */ "\xe5\xa4\x82\0" /* offset 6035 */ "\xe5\xa4\x8a\0" /* offset 6039 */ "\xe5\xa4\x95\0" /* offset 6043 */ "\xe5\xa4\xa7\0" /* offset 6047 */ "\xe5\xa5\xb3\0" /* offset 6051 */ "\xe5\xad\x90\0" /* offset 6055 */ "\xe5\xae\x80\0" /* offset 6059 */ "\xe5\xaf\xb8\0" /* offset 6063 */ "\xe5\xb0\x8f\0" /* offset 6067 */ "\xe5\xb0\xa2\0" /* offset 6071 */ "\xe5\xb0\xb8\0" /* offset 6075 */ "\xe5\xb1\xae\0" /* offset 6079 */ "\xe5\xb1\xb1\0" /* offset 6083 */ "\xe5\xb7\x9b\0" /* offset 6087 */ "\xe5\xb7\xa5\0" /* offset 6091 */ "\xe5\xb7\xb1\0" /* offset 6095 */ "\xe5\xb7\xbe\0" /* offset 6099 */ "\xe5\xb9\xb2\0" /* offset 6103 */ "\xe5\xb9\xba\0" /* offset 6107 */ "\xe5\xb9\xbf\0" /* offset 6111 */ "\xe5\xbb\xb4\0" /* offset 6115 */ "\xe5\xbb\xbe\0" /* offset 6119 */ "\xe5\xbc\x8b\0" /* offset 6123 */ "\xe5\xbc\x93\0" /* offset 6127 */ "\xe5\xbd\x90\0" /* offset 6131 */ "\xe5\xbd\xa1\0" /* offset 6135 */ "\xe5\xbd\xb3\0" /* offset 6139 */ "\xe5\xbf\x83\0" /* offset 6143 */ "\xe6\x88\x88\0" /* offset 6147 */ "\xe6\x88\xb6\0" /* offset 6151 */ "\xe6\x89\x8b\0" /* offset 6155 */ "\xe6\x94\xaf\0" /* offset 6159 */ "\xe6\x94\xb4\0" /* offset 6163 */ "\xe6\x96\x87\0" /* offset 6167 */ "\xe6\x96\x97\0" /* offset 6171 */ "\xe6\x96\xa4\0" /* offset 6175 */ "\xe6\x96\xb9\0" /* offset 6179 */ "\xe6\x97\xa0\0" /* offset 6183 */ "\xe6\x97\xa5\0" /* offset 6187 */ "\xe6\x9b\xb0\0" /* offset 6191 */ "\xe6\x9c\x88\0" /* offset 6195 */ "\xe6\x9c\xa8\0" /* offset 6199 */ "\xe6\xac\xa0\0" /* offset 6203 */ "\xe6\xad\xa2\0" /* offset 6207 */ "\xe6\xad\xb9\0" /* offset 6211 */ "\xe6\xae\xb3\0" /* offset 6215 */ "\xe6\xaf\x8b\0" /* offset 6219 */ "\xe6\xaf\x94\0" /* offset 6223 */ "\xe6\xaf\x9b\0" /* offset 6227 */ "\xe6\xb0\x8f\0" /* offset 6231 */ "\xe6\xb0\x94\0" /* offset 6235 */ "\xe6\xb0\xb4\0" /* offset 6239 */ "\xe7\x81\xab\0" /* offset 6243 */ "\xe7\x88\xaa\0" /* offset 6247 */ "\xe7\x88\xb6\0" /* offset 6251 */ "\xe7\x88\xbb\0" /* offset 6255 */ "\xe7\x88\xbf\0" /* offset 6259 */ "\xe7\x89\x87\0" /* offset 6263 */ "\xe7\x89\x99\0" /* offset 6267 */ "\xe7\x89\x9b\0" /* offset 6271 */ "\xe7\x8a\xac\0" /* offset 6275 */ "\xe7\x8e\x84\0" /* offset 6279 */ "\xe7\x8e\x89\0" /* offset 6283 */ "\xe7\x93\x9c\0" /* offset 6287 */ "\xe7\x93\xa6\0" /* offset 6291 */ "\xe7\x94\x98\0" /* offset 6295 */ "\xe7\x94\x9f\0" /* offset 6299 */ "\xe7\x94\xa8\0" /* offset 6303 */ "\xe7\x94\xb0\0" /* offset 6307 */ "\xe7\x96\x8b\0" /* offset 6311 */ "\xe7\x96\x92\0" /* offset 6315 */ "\xe7\x99\xb6\0" /* offset 6319 */ "\xe7\x99\xbd\0" /* offset 6323 */ "\xe7\x9a\xae\0" /* offset 6327 */ "\xe7\x9a\xbf\0" /* offset 6331 */ "\xe7\x9b\xae\0" /* offset 6335 */ "\xe7\x9f\x9b\0" /* offset 6339 */ "\xe7\x9f\xa2\0" /* offset 6343 */ "\xe7\x9f\xb3\0" /* offset 6347 */ "\xe7\xa4\xba\0" /* offset 6351 */ "\xe7\xa6\xb8\0" /* offset 6355 */ "\xe7\xa6\xbe\0" /* offset 6359 */ "\xe7\xa9\xb4\0" /* offset 6363 */ "\xe7\xab\x8b\0" /* offset 6367 */ "\xe7\xab\xb9\0" /* offset 6371 */ "\xe7\xb1\xb3\0" /* offset 6375 */ "\xe7\xb3\xb8\0" /* offset 6379 */ "\xe7\xbc\xb6\0" /* offset 6383 */ "\xe7\xbd\x91\0" /* offset 6387 */ "\xe7\xbe\x8a\0" /* offset 6391 */ "\xe7\xbe\xbd\0" /* offset 6395 */ "\xe8\x80\x81\0" /* offset 6399 */ "\xe8\x80\x8c\0" /* offset 6403 */ "\xe8\x80\x92\0" /* offset 6407 */ "\xe8\x80\xb3\0" /* offset 6411 */ "\xe8\x81\xbf\0" /* offset 6415 */ "\xe8\x82\x89\0" /* offset 6419 */ "\xe8\x87\xa3\0" /* offset 6423 */ "\xe8\x87\xaa\0" /* offset 6427 */ "\xe8\x87\xb3\0" /* offset 6431 */ "\xe8\x87\xbc\0" /* offset 6435 */ "\xe8\x88\x8c\0" /* offset 6439 */ "\xe8\x88\x9b\0" /* offset 6443 */ "\xe8\x88\x9f\0" /* offset 6447 */ "\xe8\x89\xae\0" /* offset 6451 */ "\xe8\x89\xb2\0" /* offset 6455 */ "\xe8\x89\xb8\0" /* offset 6459 */ "\xe8\x99\x8d\0" /* offset 6463 */ "\xe8\x99\xab\0" /* offset 6467 */ "\xe8\xa1\x80\0" /* offset 6471 */ "\xe8\xa1\x8c\0" /* offset 6475 */ "\xe8\xa1\xa3\0" /* offset 6479 */ "\xe8\xa5\xbe\0" /* offset 6483 */ "\xe8\xa6\x8b\0" /* offset 6487 */ "\xe8\xa7\x92\0" /* offset 6491 */ "\xe8\xa8\x80\0" /* offset 6495 */ "\xe8\xb0\xb7\0" /* offset 6499 */ "\xe8\xb1\x86\0" /* offset 6503 */ "\xe8\xb1\x95\0" /* offset 6507 */ "\xe8\xb1\xb8\0" /* offset 6511 */ "\xe8\xb2\x9d\0" /* offset 6515 */ "\xe8\xb5\xa4\0" /* offset 6519 */ "\xe8\xb5\xb0\0" /* offset 6523 */ "\xe8\xb6\xb3\0" /* offset 6527 */ "\xe8\xba\xab\0" /* offset 6531 */ "\xe8\xbb\x8a\0" /* offset 6535 */ "\xe8\xbe\x9b\0" /* offset 6539 */ "\xe8\xbe\xb0\0" /* offset 6543 */ "\xe8\xbe\xb5\0" /* offset 6547 */ "\xe9\x82\x91\0" /* offset 6551 */ "\xe9\x85\x89\0" /* offset 6555 */ "\xe9\x87\x86\0" /* offset 6559 */ "\xe9\x87\x8c\0" /* offset 6563 */ "\xe9\x87\x91\0" /* offset 6567 */ "\xe9\x95\xb7\0" /* offset 6571 */ "\xe9\x96\x80\0" /* offset 6575 */ "\xe9\x98\x9c\0" /* offset 6579 */ "\xe9\x9a\xb6\0" /* offset 6583 */ "\xe9\x9a\xb9\0" /* offset 6587 */ "\xe9\x9b\xa8\0" /* offset 6591 */ "\xe9\x9d\x91\0" /* offset 6595 */ "\xe9\x9d\x9e\0" /* offset 6599 */ "\xe9\x9d\xa2\0" /* offset 6603 */ "\xe9\x9d\xa9\0" /* offset 6607 */ "\xe9\x9f\x8b\0" /* offset 6611 */ "\xe9\x9f\xad\0" /* offset 6615 */ "\xe9\x9f\xb3\0" /* offset 6619 */ "\xe9\xa0\x81\0" /* offset 6623 */ "\xe9\xa2\xa8\0" /* offset 6627 */ "\xe9\xa3\x9b\0" /* offset 6631 */ "\xe9\xa3\x9f\0" /* offset 6635 */ "\xe9\xa6\x96\0" /* offset 6639 */ "\xe9\xa6\x99\0" /* offset 6643 */ "\xe9\xa6\xac\0" /* offset 6647 */ "\xe9\xaa\xa8\0" /* offset 6651 */ "\xe9\xab\x98\0" /* offset 6655 */ "\xe9\xab\x9f\0" /* offset 6659 */ "\xe9\xac\xa5\0" /* offset 6663 */ "\xe9\xac\xaf\0" /* offset 6667 */ "\xe9\xac\xb2\0" /* offset 6671 */ "\xe9\xac\xbc\0" /* offset 6675 */ "\xe9\xad\x9a\0" /* offset 6679 */ "\xe9\xb3\xa5\0" /* offset 6683 */ "\xe9\xb9\xb5\0" /* offset 6687 */ "\xe9\xb9\xbf\0" /* offset 6691 */ "\xe9\xba\xa5\0" /* offset 6695 */ "\xe9\xba\xbb\0" /* offset 6699 */ "\xe9\xbb\x83\0" /* offset 6703 */ "\xe9\xbb\x8d\0" /* offset 6707 */ "\xe9\xbb\x91\0" /* offset 6711 */ "\xe9\xbb\xb9\0" /* offset 6715 */ "\xe9\xbb\xbd\0" /* offset 6719 */ "\xe9\xbc\x8e\0" /* offset 6723 */ "\xe9\xbc\x93\0" /* offset 6727 */ "\xe9\xbc\xa0\0" /* offset 6731 */ "\xe9\xbc\xbb\0" /* offset 6735 */ "\xe9\xbd\x8a\0" /* offset 6739 */ "\xe9\xbd\x92\0" /* offset 6743 */ "\xe9\xbe\x8d\0" /* offset 6747 */ "\xe9\xbe\x9c\0" /* offset 6751 */ "\xe9\xbe\xa0\0" /* offset 6755 */ "\xe3\x80\x92\0" /* offset 6759 */ "\xe5\x8d\x84\0" /* offset 6763 */ "\xe5\x8d\x85\0" /* offset 6767 */ "\xe3\x81\x8b\xe3\x82\x99\0" /* offset 6771 */ "\xe3\x81\x8d\xe3\x82\x99\0" /* offset 6778 */ "\xe3\x81\x8f\xe3\x82\x99\0" /* offset 6785 */ "\xe3\x81\x91\xe3\x82\x99\0" /* offset 6792 */ "\xe3\x81\x93\xe3\x82\x99\0" /* offset 6799 */ "\xe3\x81\x95\xe3\x82\x99\0" /* offset 6806 */ "\xe3\x81\x97\xe3\x82\x99\0" /* offset 6813 */ "\xe3\x81\x99\xe3\x82\x99\0" /* offset 6820 */ "\xe3\x81\x9b\xe3\x82\x99\0" /* offset 6827 */ "\xe3\x81\x9d\xe3\x82\x99\0" /* offset 6834 */ "\xe3\x81\x9f\xe3\x82\x99\0" /* offset 6841 */ "\xe3\x81\xa1\xe3\x82\x99\0" /* offset 6848 */ "\xe3\x81\xa4\xe3\x82\x99\0" /* offset 6855 */ "\xe3\x81\xa6\xe3\x82\x99\0" /* offset 6862 */ "\xe3\x81\xa8\xe3\x82\x99\0" /* offset 6869 */ "\xe3\x81\xaf\xe3\x82\x99\0" /* offset 6876 */ "\xe3\x81\xaf\xe3\x82\x9a\0" /* offset 6883 */ "\xe3\x81\xb2\xe3\x82\x99\0" /* offset 6890 */ "\xe3\x81\xb2\xe3\x82\x9a\0" /* offset 6897 */ "\xe3\x81\xb5\xe3\x82\x99\0" /* offset 6904 */ "\xe3\x81\xb5\xe3\x82\x9a\0" /* offset 6911 */ "\xe3\x81\xb8\xe3\x82\x99\0" /* offset 6918 */ "\xe3\x81\xb8\xe3\x82\x9a\0" /* offset 6925 */ "\xe3\x81\xbb\xe3\x82\x99\0" /* offset 6932 */ "\xe3\x81\xbb\xe3\x82\x9a\0" /* offset 6939 */ "\xe3\x81\x86\xe3\x82\x99\0" /* offset 6946 */ "\x20\xe3\x82\x99\0" /* offset 6953 */ "\x20\xe3\x82\x9a\0" /* offset 6958 */ "\xe3\x82\x9d\xe3\x82\x99\0" /* offset 6963 */ "\xe3\x82\x88\xe3\x82\x8a\0" /* offset 6970 */ "\xe3\x82\xab\xe3\x82\x99\0" /* offset 6977 */ "\xe3\x82\xad\xe3\x82\x99\0" /* offset 6984 */ "\xe3\x82\xaf\xe3\x82\x99\0" /* offset 6991 */ "\xe3\x82\xb1\xe3\x82\x99\0" /* offset 6998 */ "\xe3\x82\xb3\xe3\x82\x99\0" /* offset 7005 */ "\xe3\x82\xb5\xe3\x82\x99\0" /* offset 7012 */ "\xe3\x82\xb7\xe3\x82\x99\0" /* offset 7019 */ "\xe3\x82\xb9\xe3\x82\x99\0" /* offset 7026 */ "\xe3\x82\xbb\xe3\x82\x99\0" /* offset 7033 */ "\xe3\x82\xbd\xe3\x82\x99\0" /* offset 7040 */ "\xe3\x82\xbf\xe3\x82\x99\0" /* offset 7047 */ "\xe3\x83\x81\xe3\x82\x99\0" /* offset 7054 */ "\xe3\x83\x84\xe3\x82\x99\0" /* offset 7061 */ "\xe3\x83\x86\xe3\x82\x99\0" /* offset 7068 */ "\xe3\x83\x88\xe3\x82\x99\0" /* offset 7075 */ "\xe3\x83\x8f\xe3\x82\x99\0" /* offset 7082 */ "\xe3\x83\x8f\xe3\x82\x9a\0" /* offset 7089 */ "\xe3\x83\x92\xe3\x82\x99\0" /* offset 7096 */ "\xe3\x83\x92\xe3\x82\x9a\0" /* offset 7103 */ "\xe3\x83\x95\xe3\x82\x99\0" /* offset 7110 */ "\xe3\x83\x95\xe3\x82\x9a\0" /* offset 7117 */ "\xe3\x83\x98\xe3\x82\x99\0" /* offset 7124 */ "\xe3\x83\x98\xe3\x82\x9a\0" /* offset 7131 */ "\xe3\x83\x9b\xe3\x82\x99\0" /* offset 7138 */ "\xe3\x83\x9b\xe3\x82\x9a\0" /* offset 7145 */ "\xe3\x82\xa6\xe3\x82\x99\0" /* offset 7152 */ "\xe3\x83\xaf\xe3\x82\x99\0" /* offset 7159 */ "\xe3\x83\xb0\xe3\x82\x99\0" /* offset 7166 */ "\xe3\x83\xb1\xe3\x82\x99\0" /* offset 7173 */ "\xe3\x83\xb2\xe3\x82\x99\0" /* offset 7180 */ "\xe3\x83\xbd\xe3\x82\x99\0" /* offset 7187 */ "\xe3\x82\xb3\xe3\x83\x88\0" /* offset 7194 */ "\xe1\x84\x80\0" /* offset 7201 */ "\xe1\x84\x81\0" /* offset 7205 */ "\xe1\x86\xaa\0" /* offset 7209 */ "\xe1\x84\x82\0" /* offset 7213 */ "\xe1\x86\xac\0" /* offset 7217 */ "\xe1\x86\xad\0" /* offset 7221 */ "\xe1\x84\x83\0" /* offset 7225 */ "\xe1\x84\x84\0" /* offset 7229 */ "\xe1\x84\x85\0" /* offset 7233 */ "\xe1\x86\xb0\0" /* offset 7237 */ "\xe1\x86\xb1\0" /* offset 7241 */ "\xe1\x86\xb2\0" /* offset 7245 */ "\xe1\x86\xb3\0" /* offset 7249 */ "\xe1\x86\xb4\0" /* offset 7253 */ "\xe1\x86\xb5\0" /* offset 7257 */ "\xe1\x84\x9a\0" /* offset 7261 */ "\xe1\x84\x86\0" /* offset 7265 */ "\xe1\x84\x87\0" /* offset 7269 */ "\xe1\x84\x88\0" /* offset 7273 */ "\xe1\x84\xa1\0" /* offset 7277 */ "\xe1\x84\x89\0" /* offset 7281 */ "\xe1\x84\x8a\0" /* offset 7285 */ "\xe1\x84\x8b\0" /* offset 7289 */ "\xe1\x84\x8c\0" /* offset 7293 */ "\xe1\x84\x8d\0" /* offset 7297 */ "\xe1\x84\x8e\0" /* offset 7301 */ "\xe1\x84\x8f\0" /* offset 7305 */ "\xe1\x84\x90\0" /* offset 7309 */ "\xe1\x84\x91\0" /* offset 7313 */ "\xe1\x84\x92\0" /* offset 7317 */ "\xe1\x85\xa1\0" /* offset 7321 */ "\xe1\x85\xa2\0" /* offset 7325 */ "\xe1\x85\xa3\0" /* offset 7329 */ "\xe1\x85\xa4\0" /* offset 7333 */ "\xe1\x85\xa5\0" /* offset 7337 */ "\xe1\x85\xa6\0" /* offset 7341 */ "\xe1\x85\xa7\0" /* offset 7345 */ "\xe1\x85\xa8\0" /* offset 7349 */ "\xe1\x85\xa9\0" /* offset 7353 */ "\xe1\x85\xaa\0" /* offset 7357 */ "\xe1\x85\xab\0" /* offset 7361 */ "\xe1\x85\xac\0" /* offset 7365 */ "\xe1\x85\xad\0" /* offset 7369 */ "\xe1\x85\xae\0" /* offset 7373 */ "\xe1\x85\xaf\0" /* offset 7377 */ "\xe1\x85\xb0\0" /* offset 7381 */ "\xe1\x85\xb1\0" /* offset 7385 */ "\xe1\x85\xb2\0" /* offset 7389 */ "\xe1\x85\xb3\0" /* offset 7393 */ "\xe1\x85\xb4\0" /* offset 7397 */ "\xe1\x85\xb5\0" /* offset 7401 */ "\xe1\x85\xa0\0" /* offset 7405 */ "\xe1\x84\x94\0" /* offset 7409 */ "\xe1\x84\x95\0" /* offset 7413 */ "\xe1\x87\x87\0" /* offset 7417 */ "\xe1\x87\x88\0" /* offset 7421 */ "\xe1\x87\x8c\0" /* offset 7425 */ "\xe1\x87\x8e\0" /* offset 7429 */ "\xe1\x87\x93\0" /* offset 7433 */ "\xe1\x87\x97\0" /* offset 7437 */ "\xe1\x87\x99\0" /* offset 7441 */ "\xe1\x84\x9c\0" /* offset 7445 */ "\xe1\x87\x9d\0" /* offset 7449 */ "\xe1\x87\x9f\0" /* offset 7453 */ "\xe1\x84\x9d\0" /* offset 7457 */ "\xe1\x84\x9e\0" /* offset 7461 */ "\xe1\x84\xa0\0" /* offset 7465 */ "\xe1\x84\xa2\0" /* offset 7469 */ "\xe1\x84\xa3\0" /* offset 7473 */ "\xe1\x84\xa7\0" /* offset 7477 */ "\xe1\x84\xa9\0" /* offset 7481 */ "\xe1\x84\xab\0" /* offset 7485 */ "\xe1\x84\xac\0" /* offset 7489 */ "\xe1\x84\xad\0" /* offset 7493 */ "\xe1\x84\xae\0" /* offset 7497 */ "\xe1\x84\xaf\0" /* offset 7501 */ "\xe1\x84\xb2\0" /* offset 7505 */ "\xe1\x84\xb6\0" /* offset 7509 */ "\xe1\x85\x80\0" /* offset 7513 */ "\xe1\x85\x87\0" /* offset 7517 */ "\xe1\x85\x8c\0" /* offset 7521 */ "\xe1\x87\xb1\0" /* offset 7525 */ "\xe1\x87\xb2\0" /* offset 7529 */ "\xe1\x85\x97\0" /* offset 7533 */ "\xe1\x85\x98\0" /* offset 7537 */ "\xe1\x85\x99\0" /* offset 7541 */ "\xe1\x86\x84\0" /* offset 7545 */ "\xe1\x86\x85\0" /* offset 7549 */ "\xe1\x86\x88\0" /* offset 7553 */ "\xe1\x86\x91\0" /* offset 7557 */ "\xe1\x86\x92\0" /* offset 7561 */ "\xe1\x86\x94\0" /* offset 7565 */ "\xe1\x86\x9e\0" /* offset 7569 */ "\xe1\x86\xa1\0" /* offset 7573 */ "\xe4\xb8\x89\0" /* offset 7577 */ "\xe5\x9b\x9b\0" /* offset 7581 */ "\xe4\xb8\x8a\0" /* offset 7585 */ "\xe4\xb8\xad\0" /* offset 7589 */ "\xe4\xb8\x8b\0" /* offset 7593 */ "\xe7\x94\xb2\0" /* offset 7597 */ "\xe4\xb8\x99\0" /* offset 7601 */ "\xe4\xb8\x81\0" /* offset 7605 */ "\xe5\xa4\xa9\0" /* offset 7609 */ "\xe5\x9c\xb0\0" /* offset 7613 */ "\x28\xe1\x84\x80\x29\0" /* offset 7617 */ "\x28\xe1\x84\x82\x29\0" /* offset 7623 */ "\x28\xe1\x84\x83\x29\0" /* offset 7629 */ "\x28\xe1\x84\x85\x29\0" /* offset 7635 */ "\x28\xe1\x84\x86\x29\0" /* offset 7641 */ "\x28\xe1\x84\x87\x29\0" /* offset 7647 */ "\x28\xe1\x84\x89\x29\0" /* offset 7653 */ "\x28\xe1\x84\x8b\x29\0" /* offset 7659 */ "\x28\xe1\x84\x8c\x29\0" /* offset 7665 */ "\x28\xe1\x84\x8e\x29\0" /* offset 7671 */ "\x28\xe1\x84\x8f\x29\0" /* offset 7677 */ "\x28\xe1\x84\x90\x29\0" /* offset 7683 */ "\x28\xe1\x84\x91\x29\0" /* offset 7689 */ "\x28\xe1\x84\x92\x29\0" /* offset 7695 */ "\x28\xe1\x84\x80\xe1\x85\xa1\x29\0" /* offset 7701 */ "\x28\xe1\x84\x82\xe1\x85\xa1\x29\0" /* offset 7710 */ "\x28\xe1\x84\x83\xe1\x85\xa1\x29\0" /* offset 7719 */ "\x28\xe1\x84\x85\xe1\x85\xa1\x29\0" /* offset 7728 */ "\x28\xe1\x84\x86\xe1\x85\xa1\x29\0" /* offset 7737 */ "\x28\xe1\x84\x87\xe1\x85\xa1\x29\0" /* offset 7746 */ "\x28\xe1\x84\x89\xe1\x85\xa1\x29\0" /* offset 7755 */ "\x28\xe1\x84\x8b\xe1\x85\xa1\x29\0" /* offset 7764 */ "\x28\xe1\x84\x8c\xe1\x85\xa1\x29\0" /* offset 7773 */ "\x28\xe1\x84\x8e\xe1\x85\xa1\x29\0" /* offset 7782 */ "\x28\xe1\x84\x8f\xe1\x85\xa1\x29\0" /* offset 7791 */ "\x28\xe1\x84\x90\xe1\x85\xa1\x29\0" /* offset 7800 */ "\x28\xe1\x84\x91\xe1\x85\xa1\x29\0" /* offset 7809 */ "\x28\xe1\x84\x92\xe1\x85\xa1\x29\0" /* offset 7818 */ "\x28\xe1\x84\x8c\xe1\x85\xae\x29\0" /* offset 7827 */ "\x28\xe4\xb8\x80\x29\0" /* offset 7836 */ "\x28\xe4\xba\x8c\x29\0" /* offset 7842 */ "\x28\xe4\xb8\x89\x29\0" /* offset 7848 */ "\x28\xe5\x9b\x9b\x29\0" /* offset 7854 */ "\x28\xe4\xba\x94\x29\0" /* offset 7860 */ "\x28\xe5\x85\xad\x29\0" /* offset 7866 */ "\x28\xe4\xb8\x83\x29\0" /* offset 7872 */ "\x28\xe5\x85\xab\x29\0" /* offset 7878 */ "\x28\xe4\xb9\x9d\x29\0" /* offset 7884 */ "\x28\xe5\x8d\x81\x29\0" /* offset 7890 */ "\x28\xe6\x9c\x88\x29\0" /* offset 7896 */ "\x28\xe7\x81\xab\x29\0" /* offset 7902 */ "\x28\xe6\xb0\xb4\x29\0" /* offset 7908 */ "\x28\xe6\x9c\xa8\x29\0" /* offset 7914 */ "\x28\xe9\x87\x91\x29\0" /* offset 7920 */ "\x28\xe5\x9c\x9f\x29\0" /* offset 7926 */ "\x28\xe6\x97\xa5\x29\0" /* offset 7932 */ "\x28\xe6\xa0\xaa\x29\0" /* offset 7938 */ "\x28\xe6\x9c\x89\x29\0" /* offset 7944 */ "\x28\xe7\xa4\xbe\x29\0" /* offset 7950 */ "\x28\xe5\x90\x8d\x29\0" /* offset 7956 */ "\x28\xe7\x89\xb9\x29\0" /* offset 7962 */ "\x28\xe8\xb2\xa1\x29\0" /* offset 7968 */ "\x28\xe7\xa5\x9d\x29\0" /* offset 7974 */ "\x28\xe5\x8a\xb4\x29\0" /* offset 7980 */ "\x28\xe4\xbb\xa3\x29\0" /* offset 7986 */ "\x28\xe5\x91\xbc\x29\0" /* offset 7992 */ "\x28\xe5\xad\xa6\x29\0" /* offset 7998 */ "\x28\xe7\x9b\xa3\x29\0" /* offset 8004 */ "\x28\xe4\xbc\x81\x29\0" /* offset 8010 */ "\x28\xe8\xb3\x87\x29\0" /* offset 8016 */ "\x28\xe5\x8d\x94\x29\0" /* offset 8022 */ "\x28\xe7\xa5\xad\x29\0" /* offset 8028 */ "\x28\xe4\xbc\x91\x29\0" /* offset 8034 */ "\x28\xe8\x87\xaa\x29\0" /* offset 8040 */ "\x28\xe8\x87\xb3\x29\0" /* offset 8046 */ "\x32\x31\0" /* offset 8052 */ "\x32\x32\0" /* offset 8055 */ "\x32\x33\0" /* offset 8058 */ "\x32\x34\0" /* offset 8061 */ "\x32\x35\0" /* offset 8064 */ "\x32\x36\0" /* offset 8067 */ "\x32\x37\0" /* offset 8070 */ "\x32\x38\0" /* offset 8073 */ "\x32\x39\0" /* offset 8076 */ "\x33\x30\0" /* offset 8079 */ "\x33\x31\0" /* offset 8082 */ "\x33\x32\0" /* offset 8085 */ "\x33\x33\0" /* offset 8088 */ "\x33\x34\0" /* offset 8091 */ "\x33\x35\0" /* offset 8094 */ "\xe1\x84\x80\xe1\x85\xa1\0" /* offset 8097 */ "\xe1\x84\x82\xe1\x85\xa1\0" /* offset 8104 */ "\xe1\x84\x83\xe1\x85\xa1\0" /* offset 8111 */ "\xe1\x84\x85\xe1\x85\xa1\0" /* offset 8118 */ "\xe1\x84\x86\xe1\x85\xa1\0" /* offset 8125 */ "\xe1\x84\x87\xe1\x85\xa1\0" /* offset 8132 */ "\xe1\x84\x89\xe1\x85\xa1\0" /* offset 8139 */ "\xe1\x84\x8b\xe1\x85\xa1\0" /* offset 8146 */ "\xe1\x84\x8c\xe1\x85\xa1\0" /* offset 8153 */ "\xe1\x84\x8e\xe1\x85\xa1\0" /* offset 8160 */ "\xe1\x84\x8f\xe1\x85\xa1\0" /* offset 8167 */ "\xe1\x84\x90\xe1\x85\xa1\0" /* offset 8174 */ "\xe1\x84\x91\xe1\x85\xa1\0" /* offset 8181 */ "\xe1\x84\x92\xe1\x85\xa1\0" /* offset 8188 */ "\xe4\xba\x94\0" /* offset 8195 */ "\xe5\x85\xad\0" /* offset 8199 */ "\xe4\xb8\x83\0" /* offset 8203 */ "\xe4\xb9\x9d\0" /* offset 8207 */ "\xe6\xa0\xaa\0" /* offset 8211 */ "\xe6\x9c\x89\0" /* offset 8215 */ "\xe7\xa4\xbe\0" /* offset 8219 */ "\xe5\x90\x8d\0" /* offset 8223 */ "\xe7\x89\xb9\0" /* offset 8227 */ "\xe8\xb2\xa1\0" /* offset 8231 */ "\xe7\xa5\x9d\0" /* offset 8235 */ "\xe5\x8a\xb4\0" /* offset 8239 */ "\xe7\xa7\x98\0" /* offset 8243 */ "\xe7\x94\xb7\0" /* offset 8247 */ "\xe9\x81\xa9\0" /* offset 8251 */ "\xe5\x84\xaa\0" /* offset 8255 */ "\xe5\x8d\xb0\0" /* offset 8259 */ "\xe6\xb3\xa8\0" /* offset 8263 */ "\xe9\xa0\x85\0" /* offset 8267 */ "\xe4\xbc\x91\0" /* offset 8271 */ "\xe5\x86\x99\0" /* offset 8275 */ "\xe6\xad\xa3\0" /* offset 8279 */ "\xe5\xb7\xa6\0" /* offset 8283 */ "\xe5\x8f\xb3\0" /* offset 8287 */ "\xe5\x8c\xbb\0" /* offset 8291 */ "\xe5\xae\x97\0" /* offset 8295 */ "\xe5\xad\xa6\0" /* offset 8299 */ "\xe7\x9b\xa3\0" /* offset 8303 */ "\xe4\xbc\x81\0" /* offset 8307 */ "\xe8\xb3\x87\0" /* offset 8311 */ "\xe5\x8d\x94\0" /* offset 8315 */ "\xe5\xa4\x9c\0" /* offset 8319 */ "\x33\x36\0" /* offset 8323 */ "\x33\x37\0" /* offset 8326 */ "\x33\x38\0" /* offset 8329 */ "\x33\x39\0" /* offset 8332 */ "\x34\x30\0" /* offset 8335 */ "\x34\x31\0" /* offset 8338 */ "\x34\x32\0" /* offset 8341 */ "\x34\x33\0" /* offset 8344 */ "\x34\x34\0" /* offset 8347 */ "\x34\x35\0" /* offset 8350 */ "\x34\x36\0" /* offset 8353 */ "\x34\x37\0" /* offset 8356 */ "\x34\x38\0" /* offset 8359 */ "\x34\x39\0" /* offset 8362 */ "\x35\x30\0" /* offset 8365 */ "\x31\xe6\x9c\x88\0" /* offset 8368 */ "\x32\xe6\x9c\x88\0" /* offset 8373 */ "\x33\xe6\x9c\x88\0" /* offset 8378 */ "\x34\xe6\x9c\x88\0" /* offset 8383 */ "\x35\xe6\x9c\x88\0" /* offset 8388 */ "\x36\xe6\x9c\x88\0" /* offset 8393 */ "\x37\xe6\x9c\x88\0" /* offset 8398 */ "\x38\xe6\x9c\x88\0" /* offset 8403 */ "\x39\xe6\x9c\x88\0" /* offset 8408 */ "\x31\x30\xe6\x9c\x88\0" /* offset 8413 */ "\x31\x31\xe6\x9c\x88\0" /* offset 8419 */ "\x31\x32\xe6\x9c\x88\0" /* offset 8425 */ "\xe3\x82\xa2\0" /* offset 8431 */ "\xe3\x82\xa4\0" /* offset 8435 */ "\xe3\x82\xa6\0" /* offset 8439 */ "\xe3\x82\xa8\0" /* offset 8443 */ "\xe3\x82\xaa\0" /* offset 8447 */ "\xe3\x82\xab\0" /* offset 8451 */ "\xe3\x82\xad\0" /* offset 8455 */ "\xe3\x82\xaf\0" /* offset 8459 */ "\xe3\x82\xb1\0" /* offset 8463 */ "\xe3\x82\xb3\0" /* offset 8467 */ "\xe3\x82\xb5\0" /* offset 8471 */ "\xe3\x82\xb7\0" /* offset 8475 */ "\xe3\x82\xb9\0" /* offset 8479 */ "\xe3\x82\xbb\0" /* offset 8483 */ "\xe3\x82\xbd\0" /* offset 8487 */ "\xe3\x82\xbf\0" /* offset 8491 */ "\xe3\x83\x81\0" /* offset 8495 */ "\xe3\x83\x84\0" /* offset 8499 */ "\xe3\x83\x86\0" /* offset 8503 */ "\xe3\x83\x88\0" /* offset 8507 */ "\xe3\x83\x8a\0" /* offset 8511 */ "\xe3\x83\x8b\0" /* offset 8515 */ "\xe3\x83\x8c\0" /* offset 8519 */ "\xe3\x83\x8d\0" /* offset 8523 */ "\xe3\x83\x8e\0" /* offset 8527 */ "\xe3\x83\x8f\0" /* offset 8531 */ "\xe3\x83\x92\0" /* offset 8535 */ "\xe3\x83\x95\0" /* offset 8539 */ "\xe3\x83\x98\0" /* offset 8543 */ "\xe3\x83\x9b\0" /* offset 8547 */ "\xe3\x83\x9e\0" /* offset 8551 */ "\xe3\x83\x9f\0" /* offset 8555 */ "\xe3\x83\xa0\0" /* offset 8559 */ "\xe3\x83\xa1\0" /* offset 8563 */ "\xe3\x83\xa2\0" /* offset 8567 */ "\xe3\x83\xa4\0" /* offset 8571 */ "\xe3\x83\xa6\0" /* offset 8575 */ "\xe3\x83\xa8\0" /* offset 8579 */ "\xe3\x83\xa9\0" /* offset 8583 */ "\xe3\x83\xaa\0" /* offset 8587 */ "\xe3\x83\xab\0" /* offset 8591 */ "\xe3\x83\xac\0" /* offset 8595 */ "\xe3\x83\xad\0" /* offset 8599 */ "\xe3\x83\xaf\0" /* offset 8603 */ "\xe3\x83\xb0\0" /* offset 8607 */ "\xe3\x83\xb1\0" /* offset 8611 */ "\xe3\x83\xb2\0" /* offset 8615 */ "\xe3\x82\xa2\xe3\x83\x8f\xe3\x82\x9a\xe3\x83\xbc\xe3\x83\x88\0" /* offset 8619 */ "\xe3\x82\xa2\xe3\x83\xab\xe3\x83\x95\xe3\x82\xa1\0" /* offset 8635 */ "\xe3\x82\xa2\xe3\x83\xb3\xe3\x83\x98\xe3\x82\x9a\xe3\x82\xa2\0" /* offset 8648 */ "\xe3\x82\xa2\xe3\x83\xbc\xe3\x83\xab\0" /* offset 8664 */ "\xe3\x82\xa4\xe3\x83\x8b\xe3\x83\xb3\xe3\x82\xaf\xe3\x82\x99\0" /* offset 8674 */ "\xe3\x82\xa4\xe3\x83\xb3\xe3\x83\x81\0" /* offset 8690 */ "\xe3\x82\xa6\xe3\x82\xa9\xe3\x83\xb3\0" /* offset 8700 */ "\xe3\x82\xa8\xe3\x82\xb9\xe3\x82\xaf\xe3\x83\xbc\xe3\x83\x88\xe3\x82\x99\0" /* offset 8710 */ "\xe3\x82\xa8\xe3\x83\xbc\xe3\x82\xab\xe3\x83\xbc\0" /* offset 8729 */ "\xe3\x82\xaa\xe3\x83\xb3\xe3\x82\xb9\0" /* offset 8742 */ "\xe3\x82\xaa\xe3\x83\xbc\xe3\x83\xa0\0" /* offset 8752 */ "\xe3\x82\xab\xe3\x82\xa4\xe3\x83\xaa\0" /* offset 8762 */ "\xe3\x82\xab\xe3\x83\xa9\xe3\x83\x83\xe3\x83\x88\0" /* offset 8772 */ "\xe3\x82\xab\xe3\x83\xad\xe3\x83\xaa\xe3\x83\xbc\0" /* offset 8785 */ "\xe3\x82\xab\xe3\x82\x99\xe3\x83\xad\xe3\x83\xb3\0" /* offset 8798 */ "\xe3\x82\xab\xe3\x82\x99\xe3\x83\xb3\xe3\x83\x9e\0" /* offset 8811 */ "\xe3\x82\xad\xe3\x82\x99\xe3\x82\xab\xe3\x82\x99\0" /* offset 8824 */ "\xe3\x82\xad\xe3\x82\x99\xe3\x83\x8b\xe3\x83\xbc\0" /* offset 8837 */ "\xe3\x82\xad\xe3\x83\xa5\xe3\x83\xaa\xe3\x83\xbc\0" /* offset 8850 */ "\xe3\x82\xad\xe3\x82\x99\xe3\x83\xab\xe3\x82\xbf\xe3\x82\x99\xe3\x83\xbc\0" /* offset 8863 */ "\xe3\x82\xad\xe3\x83\xad\0" /* offset 8882 */ "\xe3\x82\xad\xe3\x83\xad\xe3\x82\xaf\xe3\x82\x99\xe3\x83\xa9\xe3\x83\xa0\0" /* offset 8889 */ "\xe3\x82\xad\xe3\x83\xad\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\x88\xe3\x83\xab\0" /* offset 8908 */ "\xe3\x82\xad\xe3\x83\xad\xe3\x83\xaf\xe3\x83\x83\xe3\x83\x88\0" /* offset 8927 */ "\xe3\x82\xaf\xe3\x82\x99\xe3\x83\xa9\xe3\x83\xa0\0" /* offset 8943 */ "\xe3\x82\xaf\xe3\x82\x99\xe3\x83\xa9\xe3\x83\xa0\xe3\x83\x88\xe3\x83\xb3\0" /* offset 8956 */ "\xe3\x82\xaf\xe3\x83\xab\xe3\x82\xbb\xe3\x82\x99\xe3\x82\xa4\xe3\x83\xad\0" /* offset 8975 */ "\xe3\x82\xaf\xe3\x83\xad\xe3\x83\xbc\xe3\x83\x8d\0" /* offset 8994 */ "\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb9\0" /* offset 9007 */ "\xe3\x82\xb3\xe3\x83\xab\xe3\x83\x8a\0" /* offset 9017 */ "\xe3\x82\xb3\xe3\x83\xbc\xe3\x83\x9b\xe3\x82\x9a\0" /* offset 9027 */ "\xe3\x82\xb5\xe3\x82\xa4\xe3\x82\xaf\xe3\x83\xab\0" /* offset 9040 */ "\xe3\x82\xb5\xe3\x83\xb3\xe3\x83\x81\xe3\x83\xbc\xe3\x83\xa0\0" /* offset 9053 */ "\xe3\x82\xb7\xe3\x83\xaa\xe3\x83\xb3\xe3\x82\xaf\xe3\x82\x99\0" /* offset 9069 */ "\xe3\x82\xbb\xe3\x83\xb3\xe3\x83\x81\0" /* offset 9085 */ "\xe3\x82\xbb\xe3\x83\xb3\xe3\x83\x88\0" /* offset 9095 */ "\xe3\x82\xbf\xe3\x82\x99\xe3\x83\xbc\xe3\x82\xb9\0" /* offset 9105 */ "\xe3\x83\x86\xe3\x82\x99\xe3\x82\xb7\0" /* offset 9118 */ "\xe3\x83\x88\xe3\x82\x99\xe3\x83\xab\0" /* offset 9128 */ "\xe3\x83\x88\xe3\x83\xb3\0" /* offset 9138 */ "\xe3\x83\x8a\xe3\x83\x8e\0" /* offset 9145 */ "\xe3\x83\x8e\xe3\x83\x83\xe3\x83\x88\0" /* offset 9152 */ "\xe3\x83\x8f\xe3\x82\xa4\xe3\x83\x84\0" /* offset 9162 */ "\xe3\x83\x8f\xe3\x82\x9a\xe3\x83\xbc\xe3\x82\xbb\xe3\x83\xb3\xe3\x83\x88\0" /* offset 9172 */ "\xe3\x83\x8f\xe3\x82\x9a\xe3\x83\xbc\xe3\x83\x84\0" /* offset 9191 */ "\xe3\x83\x8f\xe3\x82\x99\xe3\x83\xbc\xe3\x83\xac\xe3\x83\xab\0" /* offset 9204 */ "\xe3\x83\x92\xe3\x82\x9a\xe3\x82\xa2\xe3\x82\xb9\xe3\x83\x88\xe3\x83\xab\0" /* offset 9220 */ "\xe3\x83\x92\xe3\x82\x9a\xe3\x82\xaf\xe3\x83\xab\0" /* offset 9239 */ "\xe3\x83\x92\xe3\x82\x9a\xe3\x82\xb3\0" /* offset 9252 */ "\xe3\x83\x92\xe3\x82\x99\xe3\x83\xab\0" /* offset 9262 */ "\xe3\x83\x95\xe3\x82\xa1\xe3\x83\xa9\xe3\x83\x83\xe3\x83\x88\xe3\x82\x99\0" /* offset 9272 */ "\xe3\x83\x95\xe3\x82\xa3\xe3\x83\xbc\xe3\x83\x88\0" /* offset 9291 */ "\xe3\x83\x95\xe3\x82\x99\xe3\x83\x83\xe3\x82\xb7\xe3\x82\xa7\xe3\x83\xab\0" /* offset 9304 */ "\xe3\x83\x95\xe3\x83\xa9\xe3\x83\xb3\0" /* offset 9323 */ "\xe3\x83\x98\xe3\x82\xaf\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\xab\0" /* offset 9333 */ "\xe3\x83\x98\xe3\x82\x9a\xe3\x82\xbd\0" /* offset 9349 */ "\xe3\x83\x98\xe3\x82\x9a\xe3\x83\x8b\xe3\x83\x92\0" /* offset 9359 */ "\xe3\x83\x98\xe3\x83\xab\xe3\x83\x84\0" /* offset 9372 */ "\xe3\x83\x98\xe3\x82\x9a\xe3\x83\xb3\xe3\x82\xb9\0" /* offset 9382 */ "\xe3\x83\x98\xe3\x82\x9a\xe3\x83\xbc\xe3\x82\xb7\xe3\x82\x99\0" /* offset 9395 */ "\xe3\x83\x98\xe3\x82\x99\xe3\x83\xbc\xe3\x82\xbf\0" /* offset 9411 */ "\xe3\x83\x9b\xe3\x82\x9a\xe3\x82\xa4\xe3\x83\xb3\xe3\x83\x88\0" /* offset 9424 */ "\xe3\x83\x9b\xe3\x82\x99\xe3\x83\xab\xe3\x83\x88\0" /* offset 9440 */ "\xe3\x83\x9b\xe3\x83\xb3\0" /* offset 9453 */ "\xe3\x83\x9b\xe3\x82\x9a\xe3\x83\xb3\xe3\x83\x88\xe3\x82\x99\0" /* offset 9460 */ "\xe3\x83\x9b\xe3\x83\xbc\xe3\x83\xab\0" /* offset 9476 */ "\xe3\x83\x9b\xe3\x83\xbc\xe3\x83\xb3\0" /* offset 9486 */ "\xe3\x83\x9e\xe3\x82\xa4\xe3\x82\xaf\xe3\x83\xad\0" /* offset 9496 */ "\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xab\0" /* offset 9509 */ "\xe3\x83\x9e\xe3\x83\x83\xe3\x83\x8f\0" /* offset 9519 */ "\xe3\x83\x9e\xe3\x83\xab\xe3\x82\xaf\0" /* offset 9529 */ "\xe3\x83\x9e\xe3\x83\xb3\xe3\x82\xb7\xe3\x83\xa7\xe3\x83\xb3\0" /* offset 9539 */ "\xe3\x83\x9f\xe3\x82\xaf\xe3\x83\xad\xe3\x83\xb3\0" /* offset 9555 */ "\xe3\x83\x9f\xe3\x83\xaa\0" /* offset 9568 */ "\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\x8f\xe3\x82\x99\xe3\x83\xbc\xe3\x83\xab\0" /* offset 9575 */ "\xe3\x83\xa1\xe3\x82\xab\xe3\x82\x99\0" /* offset 9594 */ "\xe3\x83\xa1\xe3\x82\xab\xe3\x82\x99\xe3\x83\x88\xe3\x83\xb3\0" /* offset 9604 */ "\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\x88\xe3\x83\xab\0" /* offset 9620 */ "\xe3\x83\xa4\xe3\x83\xbc\xe3\x83\x88\xe3\x82\x99\0" /* offset 9633 */ "\xe3\x83\xa4\xe3\x83\xbc\xe3\x83\xab\0" /* offset 9646 */ "\xe3\x83\xa6\xe3\x82\xa2\xe3\x83\xb3\0" /* offset 9656 */ "\xe3\x83\xaa\xe3\x83\x83\xe3\x83\x88\xe3\x83\xab\0" /* offset 9666 */ "\xe3\x83\xaa\xe3\x83\xa9\0" /* offset 9679 */ "\xe3\x83\xab\xe3\x83\x92\xe3\x82\x9a\xe3\x83\xbc\0" /* offset 9686 */ "\xe3\x83\xab\xe3\x83\xbc\xe3\x83\x95\xe3\x82\x99\xe3\x83\xab\0" /* offset 9699 */ "\xe3\x83\xac\xe3\x83\xa0\0" /* offset 9715 */ "\xe3\x83\xac\xe3\x83\xb3\xe3\x83\x88\xe3\x82\xb1\xe3\x82\x99\xe3\x83\xb3\0" /* offset 9722 */ "\xe3\x83\xaf\xe3\x83\x83\xe3\x83\x88\0" /* offset 9741 */ "\x30\xe7\x82\xb9\0" /* offset 9751 */ "\x31\xe7\x82\xb9\0" /* offset 9756 */ "\x32\xe7\x82\xb9\0" /* offset 9761 */ "\x33\xe7\x82\xb9\0" /* offset 9766 */ "\x34\xe7\x82\xb9\0" /* offset 9771 */ "\x35\xe7\x82\xb9\0" /* offset 9776 */ "\x36\xe7\x82\xb9\0" /* offset 9781 */ "\x37\xe7\x82\xb9\0" /* offset 9786 */ "\x38\xe7\x82\xb9\0" /* offset 9791 */ "\x39\xe7\x82\xb9\0" /* offset 9796 */ "\x31\x30\xe7\x82\xb9\0" /* offset 9801 */ "\x31\x31\xe7\x82\xb9\0" /* offset 9807 */ "\x31\x32\xe7\x82\xb9\0" /* offset 9813 */ "\x31\x33\xe7\x82\xb9\0" /* offset 9819 */ "\x31\x34\xe7\x82\xb9\0" /* offset 9825 */ "\x31\x35\xe7\x82\xb9\0" /* offset 9831 */ "\x31\x36\xe7\x82\xb9\0" /* offset 9837 */ "\x31\x37\xe7\x82\xb9\0" /* offset 9843 */ "\x31\x38\xe7\x82\xb9\0" /* offset 9849 */ "\x31\x39\xe7\x82\xb9\0" /* offset 9855 */ "\x32\x30\xe7\x82\xb9\0" /* offset 9861 */ "\x32\x31\xe7\x82\xb9\0" /* offset 9867 */ "\x32\x32\xe7\x82\xb9\0" /* offset 9873 */ "\x32\x33\xe7\x82\xb9\0" /* offset 9879 */ "\x32\x34\xe7\x82\xb9\0" /* offset 9885 */ "\x68\x50\x61\0" /* offset 9891 */ "\x64\x61\0" /* offset 9895 */ "\x41\x55\0" /* offset 9898 */ "\x62\x61\x72\0" /* offset 9901 */ "\x6f\x56\0" /* offset 9905 */ "\x70\x63\0" /* offset 9908 */ "\xe5\xb9\xb3\xe6\x88\x90\0" /* offset 9911 */ "\xe6\x98\xad\xe5\x92\x8c\0" /* offset 9918 */ "\xe5\xa4\xa7\xe6\xad\xa3\0" /* offset 9925 */ "\xe6\x98\x8e\xe6\xb2\xbb\0" /* offset 9932 */ "\xe6\xa0\xaa\xe5\xbc\x8f\xe4\xbc\x9a\xe7\xa4\xbe\0" /* offset 9939 */ "\x70\x41\0" /* offset 9952 */ "\x6e\x41\0" /* offset 9955 */ "\xce\xbc\x41\0" /* offset 9958 */ "\x6d\x41\0" /* offset 9962 */ "\x6b\x41\0" /* offset 9965 */ "\x4b\x42\0" /* offset 9968 */ "\x4d\x42\0" /* offset 9971 */ "\x47\x42\0" /* offset 9974 */ "\x63\x61\x6c\0" /* offset 9977 */ "\x6b\x63\x61\x6c\0" /* offset 9981 */ "\x70\x46\0" /* offset 9986 */ "\x6e\x46\0" /* offset 9989 */ "\xce\xbc\x46\0" /* offset 9992 */ "\xce\xbc\x67\0" /* offset 9996 */ "\x6d\x67\0" /* offset 10000 */ "\x6b\x67\0" /* offset 10003 */ "\x48\x7a\0" /* offset 10006 */ "\x6b\x48\x7a\0" /* offset 10009 */ "\x4d\x48\x7a\0" /* offset 10013 */ "\x47\x48\x7a\0" /* offset 10017 */ "\x54\x48\x7a\0" /* offset 10021 */ "\xce\xbc\x6c\0" /* offset 10025 */ "\x6d\x6c\0" /* offset 10029 */ "\x64\x6c\0" /* offset 10032 */ "\x6b\x6c\0" /* offset 10035 */ "\x66\x6d\0" /* offset 10038 */ "\x6e\x6d\0" /* offset 10041 */ "\xce\xbc\x6d\0" /* offset 10044 */ "\x6d\x6d\0" /* offset 10048 */ "\x63\x6d\0" /* offset 10051 */ "\x6b\x6d\0" /* offset 10054 */ "\x6d\x6d\x32\0" /* offset 10057 */ "\x63\x6d\x32\0" /* offset 10061 */ "\x6d\x32\0" /* offset 10065 */ "\x6b\x6d\x32\0" /* offset 10068 */ "\x6d\x6d\x33\0" /* offset 10072 */ "\x63\x6d\x33\0" /* offset 10076 */ "\x6d\x33\0" /* offset 10080 */ "\x6b\x6d\x33\0" /* offset 10083 */ "\x6d\xe2\x88\x95\x73\0" /* offset 10087 */ "\x6d\xe2\x88\x95\x73\x32\0" /* offset 10093 */ "\x50\x61\0" /* offset 10100 */ "\x6b\x50\x61\0" /* offset 10103 */ "\x4d\x50\x61\0" /* offset 10107 */ "\x47\x50\x61\0" /* offset 10111 */ "\x72\x61\x64\0" /* offset 10115 */ "\x72\x61\x64\xe2\x88\x95\x73\0" /* offset 10119 */ "\x72\x61\x64\xe2\x88\x95\x73\x32\0" /* offset 10127 */ "\x70\x73\0" /* offset 10136 */ "\x6e\x73\0" /* offset 10139 */ "\xce\xbc\x73\0" /* offset 10142 */ "\x6d\x73\0" /* offset 10146 */ "\x70\x56\0" /* offset 10149 */ "\x6e\x56\0" /* offset 10152 */ "\xce\xbc\x56\0" /* offset 10155 */ "\x6d\x56\0" /* offset 10159 */ "\x6b\x56\0" /* offset 10162 */ "\x4d\x56\0" /* offset 10165 */ "\x70\x57\0" /* offset 10168 */ "\x6e\x57\0" /* offset 10171 */ "\xce\xbc\x57\0" /* offset 10174 */ "\x6d\x57\0" /* offset 10178 */ "\x6b\x57\0" /* offset 10181 */ "\x4d\x57\0" /* offset 10184 */ "\x6b\xce\xa9\0" /* offset 10187 */ "\x4d\xce\xa9\0" /* offset 10191 */ "\x61\x2e\x6d\x2e\0" /* offset 10195 */ "\x42\x71\0" /* offset 10200 */ "\x63\x63\0" /* offset 10203 */ "\x63\x64\0" /* offset 10206 */ "\x43\xe2\x88\x95\x6b\x67\0" /* offset 10209 */ "\x43\x6f\x2e\0" /* offset 10216 */ "\x64\x42\0" /* offset 10220 */ "\x47\x79\0" /* offset 10223 */ "\x68\x61\0" /* offset 10226 */ "\x48\x50\0" /* offset 10229 */ "\x69\x6e\0" /* offset 10232 */ "\x4b\x4b\0" /* offset 10235 */ "\x4b\x4d\0" /* offset 10238 */ "\x6b\x74\0" /* offset 10241 */ "\x6c\x6d\0" /* offset 10244 */ "\x6c\x6e\0" /* offset 10247 */ "\x6c\x6f\x67\0" /* offset 10250 */ "\x6c\x78\0" /* offset 10254 */ "\x6d\x62\0" /* offset 10257 */ "\x6d\x69\x6c\0" /* offset 10260 */ "\x6d\x6f\x6c\0" /* offset 10264 */ "\x50\x48\0" /* offset 10268 */ "\x70\x2e\x6d\x2e\0" /* offset 10271 */ "\x50\x50\x4d\0" /* offset 10276 */ "\x50\x52\0" /* offset 10280 */ "\x73\x72\0" /* offset 10283 */ "\x53\x76\0" /* offset 10286 */ "\x57\x62\0" /* offset 10289 */ "\x31\xe6\x97\xa5\0" /* offset 10292 */ "\x32\xe6\x97\xa5\0" /* offset 10297 */ "\x33\xe6\x97\xa5\0" /* offset 10302 */ "\x34\xe6\x97\xa5\0" /* offset 10307 */ "\x35\xe6\x97\xa5\0" /* offset 10312 */ "\x36\xe6\x97\xa5\0" /* offset 10317 */ "\x37\xe6\x97\xa5\0" /* offset 10322 */ "\x38\xe6\x97\xa5\0" /* offset 10327 */ "\x39\xe6\x97\xa5\0" /* offset 10332 */ "\x31\x30\xe6\x97\xa5\0" /* offset 10337 */ "\x31\x31\xe6\x97\xa5\0" /* offset 10343 */ "\x31\x32\xe6\x97\xa5\0" /* offset 10349 */ "\x31\x33\xe6\x97\xa5\0" /* offset 10355 */ "\x31\x34\xe6\x97\xa5\0" /* offset 10361 */ "\x31\x35\xe6\x97\xa5\0" /* offset 10367 */ "\x31\x36\xe6\x97\xa5\0" /* offset 10373 */ "\x31\x37\xe6\x97\xa5\0" /* offset 10379 */ "\x31\x38\xe6\x97\xa5\0" /* offset 10385 */ "\x31\x39\xe6\x97\xa5\0" /* offset 10391 */ "\x32\x30\xe6\x97\xa5\0" /* offset 10397 */ "\x32\x31\xe6\x97\xa5\0" /* offset 10403 */ "\x32\x32\xe6\x97\xa5\0" /* offset 10409 */ "\x32\x33\xe6\x97\xa5\0" /* offset 10415 */ "\x32\x34\xe6\x97\xa5\0" /* offset 10421 */ "\x32\x35\xe6\x97\xa5\0" /* offset 10427 */ "\x32\x36\xe6\x97\xa5\0" /* offset 10433 */ "\x32\x37\xe6\x97\xa5\0" /* offset 10439 */ "\x32\x38\xe6\x97\xa5\0" /* offset 10445 */ "\x32\x39\xe6\x97\xa5\0" /* offset 10451 */ "\x33\x30\xe6\x97\xa5\0" /* offset 10457 */ "\x33\x31\xe6\x97\xa5\0" /* offset 10463 */ "\xe8\xb1\x88\0" /* offset 10469 */ "\xe6\x9b\xb4\0" /* offset 10473 */ "\xe8\xb3\x88\0" /* offset 10477 */ "\xe6\xbb\x91\0" /* offset 10481 */ "\xe4\xb8\xb2\0" /* offset 10485 */ "\xe5\x8f\xa5\0" /* offset 10489 */ "\xe5\xa5\x91\0" /* offset 10493 */ "\xe5\x96\x87\0" /* offset 10497 */ "\xe5\xa5\x88\0" /* offset 10501 */ "\xe6\x87\xb6\0" /* offset 10505 */ "\xe7\x99\xa9\0" /* offset 10509 */ "\xe7\xbe\x85\0" /* offset 10513 */ "\xe8\x98\xbf\0" /* offset 10517 */ "\xe8\x9e\xba\0" /* offset 10521 */ "\xe8\xa3\xb8\0" /* offset 10525 */ "\xe9\x82\x8f\0" /* offset 10529 */ "\xe6\xa8\x82\0" /* offset 10533 */ "\xe6\xb4\x9b\0" /* offset 10537 */ "\xe7\x83\x99\0" /* offset 10541 */ "\xe7\x8f\x9e\0" /* offset 10545 */ "\xe8\x90\xbd\0" /* offset 10549 */ "\xe9\x85\xaa\0" /* offset 10553 */ "\xe9\xa7\xb1\0" /* offset 10557 */ "\xe4\xba\x82\0" /* offset 10561 */ "\xe5\x8d\xb5\0" /* offset 10565 */ "\xe6\xac\x84\0" /* offset 10569 */ "\xe7\x88\x9b\0" /* offset 10573 */ "\xe8\x98\xad\0" /* offset 10577 */ "\xe9\xb8\x9e\0" /* offset 10581 */ "\xe5\xb5\x90\0" /* offset 10585 */ "\xe6\xbf\xab\0" /* offset 10589 */ "\xe8\x97\x8d\0" /* offset 10593 */ "\xe8\xa5\xa4\0" /* offset 10597 */ "\xe6\x8b\x89\0" /* offset 10601 */ "\xe8\x87\x98\0" /* offset 10605 */ "\xe8\xa0\x9f\0" /* offset 10609 */ "\xe5\xbb\x8a\0" /* offset 10613 */ "\xe6\x9c\x97\0" /* offset 10617 */ "\xe6\xb5\xaa\0" /* offset 10621 */ "\xe7\x8b\xbc\0" /* offset 10625 */ "\xe9\x83\x8e\0" /* offset 10629 */ "\xe4\xbe\x86\0" /* offset 10633 */ "\xe5\x86\xb7\0" /* offset 10637 */ "\xe5\x8b\x9e\0" /* offset 10641 */ "\xe6\x93\x84\0" /* offset 10645 */ "\xe6\xab\x93\0" /* offset 10649 */ "\xe7\x88\x90\0" /* offset 10653 */ "\xe7\x9b\xa7\0" /* offset 10657 */ "\xe8\x98\x86\0" /* offset 10661 */ "\xe8\x99\x9c\0" /* offset 10665 */ "\xe8\xb7\xaf\0" /* offset 10669 */ "\xe9\x9c\xb2\0" /* offset 10673 */ "\xe9\xad\xaf\0" /* offset 10677 */ "\xe9\xb7\xba\0" /* offset 10681 */ "\xe7\xa2\x8c\0" /* offset 10685 */ "\xe7\xa5\xbf\0" /* offset 10689 */ "\xe7\xb6\xa0\0" /* offset 10693 */ "\xe8\x8f\x89\0" /* offset 10697 */ "\xe9\x8c\x84\0" /* offset 10701 */ "\xe8\xab\x96\0" /* offset 10705 */ "\xe5\xa3\x9f\0" /* offset 10709 */ "\xe5\xbc\x84\0" /* offset 10713 */ "\xe7\xb1\xa0\0" /* offset 10717 */ "\xe8\x81\xbe\0" /* offset 10721 */ "\xe7\x89\xa2\0" /* offset 10725 */ "\xe7\xa3\x8a\0" /* offset 10729 */ "\xe8\xb3\x82\0" /* offset 10733 */ "\xe9\x9b\xb7\0" /* offset 10737 */ "\xe5\xa3\x98\0" /* offset 10741 */ "\xe5\xb1\xa2\0" /* offset 10745 */ "\xe6\xa8\x93\0" /* offset 10749 */ "\xe6\xb7\x9a\0" /* offset 10753 */ "\xe6\xbc\x8f\0" /* offset 10757 */ "\xe7\xb4\xaf\0" /* offset 10761 */ "\xe7\xb8\xb7\0" /* offset 10765 */ "\xe9\x99\x8b\0" /* offset 10769 */ "\xe5\x8b\x92\0" /* offset 10773 */ "\xe8\x82\x8b\0" /* offset 10777 */ "\xe5\x87\x9c\0" /* offset 10781 */ "\xe5\x87\x8c\0" /* offset 10785 */ "\xe7\xa8\x9c\0" /* offset 10789 */ "\xe7\xb6\xbe\0" /* offset 10793 */ "\xe8\x8f\xb1\0" /* offset 10797 */ "\xe9\x99\xb5\0" /* offset 10801 */ "\xe8\xae\x80\0" /* offset 10805 */ "\xe6\x8b\x8f\0" /* offset 10809 */ "\xe8\xab\xbe\0" /* offset 10813 */ "\xe4\xb8\xb9\0" /* offset 10817 */ "\xe5\xaf\xa7\0" /* offset 10821 */ "\xe6\x80\x92\0" /* offset 10825 */ "\xe7\x8e\x87\0" /* offset 10829 */ "\xe7\x95\xb0\0" /* offset 10833 */ "\xe5\x8c\x97\0" /* offset 10837 */ "\xe7\xa3\xbb\0" /* offset 10841 */ "\xe4\xbe\xbf\0" /* offset 10845 */ "\xe5\xbe\xa9\0" /* offset 10849 */ "\xe4\xb8\x8d\0" /* offset 10853 */ "\xe6\xb3\x8c\0" /* offset 10857 */ "\xe6\x95\xb8\0" /* offset 10861 */ "\xe7\xb4\xa2\0" /* offset 10865 */ "\xe5\x8f\x83\0" /* offset 10869 */ "\xe5\xa1\x9e\0" /* offset 10873 */ "\xe7\x9c\x81\0" /* offset 10877 */ "\xe8\x91\x89\0" /* offset 10881 */ "\xe8\xaa\xaa\0" /* offset 10885 */ "\xe6\xae\xba\0" /* offset 10889 */ "\xe6\xb2\x88\0" /* offset 10893 */ "\xe6\x8b\xbe\0" /* offset 10897 */ "\xe8\x8b\xa5\0" /* offset 10901 */ "\xe6\x8e\xa0\0" /* offset 10905 */ "\xe7\x95\xa5\0" /* offset 10909 */ "\xe4\xba\xae\0" /* offset 10913 */ "\xe5\x85\xa9\0" /* offset 10917 */ "\xe5\x87\x89\0" /* offset 10921 */ "\xe6\xa2\x81\0" /* offset 10925 */ "\xe7\xb3\xa7\0" /* offset 10929 */ "\xe8\x89\xaf\0" /* offset 10933 */ "\xe8\xab\x92\0" /* offset 10937 */ "\xe9\x87\x8f\0" /* offset 10941 */ "\xe5\x8b\xb5\0" /* offset 10945 */ "\xe5\x91\x82\0" /* offset 10949 */ "\xe5\xbb\xac\0" /* offset 10953 */ "\xe6\x97\x85\0" /* offset 10957 */ "\xe6\xbf\xbe\0" /* offset 10961 */ "\xe7\xa4\xaa\0" /* offset 10965 */ "\xe9\x96\xad\0" /* offset 10969 */ "\xe9\xa9\xaa\0" /* offset 10973 */ "\xe9\xba\x97\0" /* offset 10977 */ "\xe9\xbb\x8e\0" /* offset 10981 */ "\xe6\x9b\x86\0" /* offset 10985 */ "\xe6\xad\xb7\0" /* offset 10989 */ "\xe8\xbd\xa2\0" /* offset 10993 */ "\xe5\xb9\xb4\0" /* offset 10997 */ "\xe6\x86\x90\0" /* offset 11001 */ "\xe6\x88\x80\0" /* offset 11005 */ "\xe6\x92\x9a\0" /* offset 11009 */ "\xe6\xbc\xa3\0" /* offset 11013 */ "\xe7\x85\x89\0" /* offset 11017 */ "\xe7\x92\x89\0" /* offset 11021 */ "\xe7\xa7\x8a\0" /* offset 11025 */ "\xe7\xb7\xb4\0" /* offset 11029 */ "\xe8\x81\xaf\0" /* offset 11033 */ "\xe8\xbc\xa6\0" /* offset 11037 */ "\xe8\x93\xae\0" /* offset 11041 */ "\xe9\x80\xa3\0" /* offset 11045 */ "\xe9\x8d\x8a\0" /* offset 11049 */ "\xe5\x88\x97\0" /* offset 11053 */ "\xe5\x8a\xa3\0" /* offset 11057 */ "\xe5\x92\xbd\0" /* offset 11061 */ "\xe7\x83\x88\0" /* offset 11065 */ "\xe8\xa3\x82\0" /* offset 11069 */ "\xe5\xbb\x89\0" /* offset 11073 */ "\xe5\xbf\xb5\0" /* offset 11077 */ "\xe6\x8d\xbb\0" /* offset 11081 */ "\xe6\xae\xae\0" /* offset 11085 */ "\xe7\xb0\xbe\0" /* offset 11089 */ "\xe7\x8d\xb5\0" /* offset 11093 */ "\xe4\xbb\xa4\0" /* offset 11097 */ "\xe5\x9b\xb9\0" /* offset 11101 */ "\xe5\xb6\xba\0" /* offset 11105 */ "\xe6\x80\x9c\0" /* offset 11109 */ "\xe7\x8e\xb2\0" /* offset 11113 */ "\xe7\x91\xa9\0" /* offset 11117 */ "\xe7\xbe\x9a\0" /* offset 11121 */ "\xe8\x81\x86\0" /* offset 11125 */ "\xe9\x88\xb4\0" /* offset 11129 */ "\xe9\x9b\xb6\0" /* offset 11133 */ "\xe9\x9d\x88\0" /* offset 11137 */ "\xe9\xa0\x98\0" /* offset 11141 */ "\xe4\xbe\x8b\0" /* offset 11145 */ "\xe7\xa6\xae\0" /* offset 11149 */ "\xe9\x86\xb4\0" /* offset 11153 */ "\xe9\x9a\xb8\0" /* offset 11157 */ "\xe6\x83\xa1\0" /* offset 11161 */ "\xe4\xba\x86\0" /* offset 11165 */ "\xe5\x83\x9a\0" /* offset 11169 */ "\xe5\xaf\xae\0" /* offset 11173 */ "\xe5\xb0\xbf\0" /* offset 11177 */ "\xe6\x96\x99\0" /* offset 11181 */ "\xe7\x87\x8e\0" /* offset 11185 */ "\xe7\x99\x82\0" /* offset 11189 */ "\xe8\x93\xbc\0" /* offset 11193 */ "\xe9\x81\xbc\0" /* offset 11197 */ "\xe6\x9a\x88\0" /* offset 11201 */ "\xe9\x98\xae\0" /* offset 11205 */ "\xe5\x8a\x89\0" /* offset 11209 */ "\xe6\x9d\xbb\0" /* offset 11213 */ "\xe6\x9f\xb3\0" /* offset 11217 */ "\xe6\xb5\x81\0" /* offset 11221 */ "\xe6\xba\x9c\0" /* offset 11225 */ "\xe7\x90\x89\0" /* offset 11229 */ "\xe7\x95\x99\0" /* offset 11233 */ "\xe7\xa1\xab\0" /* offset 11237 */ "\xe7\xb4\x90\0" /* offset 11241 */ "\xe9\xa1\x9e\0" /* offset 11245 */ "\xe6\x88\xae\0" /* offset 11249 */ "\xe9\x99\xb8\0" /* offset 11253 */ "\xe5\x80\xab\0" /* offset 11257 */ "\xe5\xb4\x99\0" /* offset 11261 */ "\xe6\xb7\xaa\0" /* offset 11265 */ "\xe8\xbc\xaa\0" /* offset 11269 */ "\xe5\xbe\x8b\0" /* offset 11273 */ "\xe6\x85\x84\0" /* offset 11277 */ "\xe6\xa0\x97\0" /* offset 11281 */ "\xe9\x9a\x86\0" /* offset 11285 */ "\xe5\x88\xa9\0" /* offset 11289 */ "\xe5\x90\x8f\0" /* offset 11293 */ "\xe5\xb1\xa5\0" /* offset 11297 */ "\xe6\x98\x93\0" /* offset 11301 */ "\xe6\x9d\x8e\0" /* offset 11305 */ "\xe6\xa2\xa8\0" /* offset 11309 */ "\xe6\xb3\xa5\0" /* offset 11313 */ "\xe7\x90\x86\0" /* offset 11317 */ "\xe7\x97\xa2\0" /* offset 11321 */ "\xe7\xbd\xb9\0" /* offset 11325 */ "\xe8\xa3\x8f\0" /* offset 11329 */ "\xe8\xa3\xa1\0" /* offset 11333 */ "\xe9\x9b\xa2\0" /* offset 11337 */ "\xe5\x8c\xbf\0" /* offset 11341 */ "\xe6\xba\xba\0" /* offset 11345 */ "\xe5\x90\x9d\0" /* offset 11349 */ "\xe7\x87\x90\0" /* offset 11353 */ "\xe7\x92\x98\0" /* offset 11357 */ "\xe8\x97\xba\0" /* offset 11361 */ "\xe9\x9a\xa3\0" /* offset 11365 */ "\xe9\xb1\x97\0" /* offset 11369 */ "\xe9\xba\x9f\0" /* offset 11373 */ "\xe6\x9e\x97\0" /* offset 11377 */ "\xe6\xb7\x8b\0" /* offset 11381 */ "\xe8\x87\xa8\0" /* offset 11385 */ "\xe7\xac\xa0\0" /* offset 11389 */ "\xe7\xb2\x92\0" /* offset 11393 */ "\xe7\x8b\x80\0" /* offset 11397 */ "\xe7\x82\x99\0" /* offset 11401 */ "\xe8\xad\x98\0" /* offset 11405 */ "\xe4\xbb\x80\0" /* offset 11409 */ "\xe8\x8c\xb6\0" /* offset 11413 */ "\xe5\x88\xba\0" /* offset 11417 */ "\xe5\x88\x87\0" /* offset 11421 */ "\xe5\xba\xa6\0" /* offset 11425 */ "\xe6\x8b\x93\0" /* offset 11429 */ "\xe7\xb3\x96\0" /* offset 11433 */ "\xe5\xae\x85\0" /* offset 11437 */ "\xe6\xb4\x9e\0" /* offset 11441 */ "\xe6\x9a\xb4\0" /* offset 11445 */ "\xe8\xbc\xbb\0" /* offset 11449 */ "\xe9\x99\x8d\0" /* offset 11453 */ "\xe5\xbb\x93\0" /* offset 11457 */ "\xe5\x85\x80\0" /* offset 11461 */ "\xe5\x97\x80\0" /* offset 11465 */ "\xe5\xa1\x9a\0" /* offset 11469 */ "\xe6\x99\xb4\0" /* offset 11473 */ "\xe5\x87\x9e\0" /* offset 11477 */ "\xe7\x8c\xaa\0" /* offset 11481 */ "\xe7\x9b\x8a\0" /* offset 11485 */ "\xe7\xa4\xbc\0" /* offset 11489 */ "\xe7\xa5\x9e\0" /* offset 11493 */ "\xe7\xa5\xa5\0" /* offset 11497 */ "\xe7\xa6\x8f\0" /* offset 11501 */ "\xe9\x9d\x96\0" /* offset 11505 */ "\xe7\xb2\xbe\0" /* offset 11509 */ "\xe8\x98\x92\0" /* offset 11513 */ "\xe8\xab\xb8\0" /* offset 11517 */ "\xe9\x80\xb8\0" /* offset 11521 */ "\xe9\x83\xbd\0" /* offset 11525 */ "\xe9\xa3\xaf\0" /* offset 11529 */ "\xe9\xa3\xbc\0" /* offset 11533 */ "\xe9\xa4\xa8\0" /* offset 11537 */ "\xe9\xb6\xb4\0" /* offset 11541 */ "\xe4\xbe\xae\0" /* offset 11545 */ "\xe5\x83\xa7\0" /* offset 11549 */ "\xe5\x85\x8d\0" /* offset 11553 */ "\xe5\x8b\x89\0" /* offset 11557 */ "\xe5\x8b\xa4\0" /* offset 11561 */ "\xe5\x8d\x91\0" /* offset 11565 */ "\xe5\x96\x9d\0" /* offset 11569 */ "\xe5\x98\x86\0" /* offset 11573 */ "\xe5\x99\xa8\0" /* offset 11577 */ "\xe5\xa1\x80\0" /* offset 11581 */ "\xe5\xa2\xa8\0" /* offset 11585 */ "\xe5\xb1\xa4\0" /* offset 11589 */ "\xe6\x82\x94\0" /* offset 11593 */ "\xe6\x85\xa8\0" /* offset 11597 */ "\xe6\x86\x8e\0" /* offset 11601 */ "\xe6\x87\xb2\0" /* offset 11605 */ "\xe6\x95\x8f\0" /* offset 11609 */ "\xe6\x97\xa2\0" /* offset 11613 */ "\xe6\x9a\x91\0" /* offset 11617 */ "\xe6\xa2\x85\0" /* offset 11621 */ "\xe6\xb5\xb7\0" /* offset 11625 */ "\xe6\xb8\x9a\0" /* offset 11629 */ "\xe6\xbc\xa2\0" /* offset 11633 */ "\xe7\x85\xae\0" /* offset 11637 */ "\xe7\x88\xab\0" /* offset 11641 */ "\xe7\x90\xa2\0" /* offset 11645 */ "\xe7\xa2\x91\0" /* offset 11649 */ "\xe7\xa5\x89\0" /* offset 11653 */ "\xe7\xa5\x88\0" /* offset 11657 */ "\xe7\xa5\x90\0" /* offset 11661 */ "\xe7\xa5\x96\0" /* offset 11665 */ "\xe7\xa6\x8d\0" /* offset 11669 */ "\xe7\xa6\x8e\0" /* offset 11673 */ "\xe7\xa9\x80\0" /* offset 11677 */ "\xe7\xaa\x81\0" /* offset 11681 */ "\xe7\xaf\x80\0" /* offset 11685 */ "\xe7\xb8\x89\0" /* offset 11689 */ "\xe7\xb9\x81\0" /* offset 11693 */ "\xe7\xbd\xb2\0" /* offset 11697 */ "\xe8\x80\x85\0" /* offset 11701 */ "\xe8\x87\xad\0" /* offset 11705 */ "\xe8\x89\xb9\0" /* offset 11709 */ "\xe8\x91\x97\0" /* offset 11713 */ "\xe8\xa4\x90\0" /* offset 11717 */ "\xe8\xa6\x96\0" /* offset 11721 */ "\xe8\xac\x81\0" /* offset 11725 */ "\xe8\xac\xb9\0" /* offset 11729 */ "\xe8\xb3\x93\0" /* offset 11733 */ "\xe8\xb4\x88\0" /* offset 11737 */ "\xe8\xbe\xb6\0" /* offset 11741 */ "\xe9\x9b\xa3\0" /* offset 11745 */ "\xe9\x9f\xbf\0" /* offset 11749 */ "\xe9\xa0\xbb\0" /* offset 11753 */ "\x66\x66\0" /* offset 11757 */ "\x66\x69\0" /* offset 11760 */ "\x66\x6c\0" /* offset 11763 */ "\x66\x66\x69\0" /* offset 11766 */ "\x66\x66\x6c\0" /* offset 11770 */ "\x73\x74\0" /* offset 11774 */ "\xd5\xb4\xd5\xb6\0" /* offset 11777 */ "\xd5\xb4\xd5\xa5\0" /* offset 11782 */ "\xd5\xb4\xd5\xab\0" /* offset 11787 */ "\xd5\xbe\xd5\xb6\0" /* offset 11792 */ "\xd5\xb4\xd5\xad\0" /* offset 11797 */ "\xd7\x99\xd6\xb4\0" /* offset 11802 */ "\xd7\xb2\xd6\xb7\0" /* offset 11807 */ "\xd7\xa2\0" /* offset 11812 */ "\xd7\x94\0" /* offset 11815 */ "\xd7\x9b\0" /* offset 11818 */ "\xd7\x9c\0" /* offset 11821 */ "\xd7\x9d\0" /* offset 11824 */ "\xd7\xa8\0" /* offset 11827 */ "\xd7\xaa\0" /* offset 11830 */ "\xd7\xa9\xd7\x81\0" /* offset 11833 */ "\xd7\xa9\xd7\x82\0" /* offset 11838 */ "\xd7\xa9\xd6\xbc\xd7\x81\0" /* offset 11843 */ "\xd7\xa9\xd6\xbc\xd7\x82\0" /* offset 11850 */ "\xd7\x90\xd6\xb7\0" /* offset 11857 */ "\xd7\x90\xd6\xb8\0" /* offset 11862 */ "\xd7\x90\xd6\xbc\0" /* offset 11867 */ "\xd7\x91\xd6\xbc\0" /* offset 11872 */ "\xd7\x92\xd6\xbc\0" /* offset 11877 */ "\xd7\x93\xd6\xbc\0" /* offset 11882 */ "\xd7\x94\xd6\xbc\0" /* offset 11887 */ "\xd7\x95\xd6\xbc\0" /* offset 11892 */ "\xd7\x96\xd6\xbc\0" /* offset 11897 */ "\xd7\x98\xd6\xbc\0" /* offset 11902 */ "\xd7\x99\xd6\xbc\0" /* offset 11907 */ "\xd7\x9a\xd6\xbc\0" /* offset 11912 */ "\xd7\x9b\xd6\xbc\0" /* offset 11917 */ "\xd7\x9c\xd6\xbc\0" /* offset 11922 */ "\xd7\x9e\xd6\xbc\0" /* offset 11927 */ "\xd7\xa0\xd6\xbc\0" /* offset 11932 */ "\xd7\xa1\xd6\xbc\0" /* offset 11937 */ "\xd7\xa3\xd6\xbc\0" /* offset 11942 */ "\xd7\xa4\xd6\xbc\0" /* offset 11947 */ "\xd7\xa6\xd6\xbc\0" /* offset 11952 */ "\xd7\xa7\xd6\xbc\0" /* offset 11957 */ "\xd7\xa8\xd6\xbc\0" /* offset 11962 */ "\xd7\xa9\xd6\xbc\0" /* offset 11967 */ "\xd7\xaa\xd6\xbc\0" /* offset 11972 */ "\xd7\x95\xd6\xb9\0" /* offset 11977 */ "\xd7\x91\xd6\xbf\0" /* offset 11982 */ "\xd7\x9b\xd6\xbf\0" /* offset 11987 */ "\xd7\xa4\xd6\xbf\0" /* offset 11992 */ "\xd7\x90\xd7\x9c\0" /* offset 11997 */ "\xd9\xb1\0" /* offset 12002 */ "\xd9\xbb\0" /* offset 12005 */ "\xd9\xbe\0" /* offset 12008 */ "\xda\x80\0" /* offset 12011 */ "\xd9\xba\0" /* offset 12014 */ "\xd9\xbf\0" /* offset 12017 */ "\xd9\xb9\0" /* offset 12020 */ "\xda\xa4\0" /* offset 12023 */ "\xda\xa6\0" /* offset 12026 */ "\xda\x84\0" /* offset 12029 */ "\xda\x83\0" /* offset 12032 */ "\xda\x86\0" /* offset 12035 */ "\xda\x87\0" /* offset 12038 */ "\xda\x8d\0" /* offset 12041 */ "\xda\x8c\0" /* offset 12044 */ "\xda\x8e\0" /* offset 12047 */ "\xda\x88\0" /* offset 12050 */ "\xda\x98\0" /* offset 12053 */ "\xda\x91\0" /* offset 12056 */ "\xda\xa9\0" /* offset 12059 */ "\xda\xaf\0" /* offset 12062 */ "\xda\xb3\0" /* offset 12065 */ "\xda\xb1\0" /* offset 12068 */ "\xda\xba\0" /* offset 12071 */ "\xda\xbb\0" /* offset 12074 */ "\xdb\x81\0" /* offset 12077 */ "\xda\xbe\0" /* offset 12080 */ "\xdb\x92\0" /* offset 12083 */ "\xda\xad\0" /* offset 12086 */ "\xdb\x87\0" /* offset 12089 */ "\xdb\x86\0" /* offset 12092 */ "\xdb\x88\0" /* offset 12095 */ "\xdb\x8b\0" /* offset 12098 */ "\xdb\x85\0" /* offset 12101 */ "\xdb\x89\0" /* offset 12104 */ "\xdb\x90\0" /* offset 12107 */ "\xd9\x89\0" /* offset 12110 */ "\xd9\x8a\xd9\x94\xd8\xa7\0" /* offset 12113 */ "\xd9\x8a\xd9\x94\xdb\x95\0" /* offset 12120 */ "\xd9\x8a\xd9\x94\xd9\x88\0" /* offset 12127 */ "\xd9\x8a\xd9\x94\xdb\x87\0" /* offset 12134 */ "\xd9\x8a\xd9\x94\xdb\x86\0" /* offset 12141 */ "\xd9\x8a\xd9\x94\xdb\x88\0" /* offset 12148 */ "\xd9\x8a\xd9\x94\xdb\x90\0" /* offset 12155 */ "\xd9\x8a\xd9\x94\xd9\x89\0" /* offset 12162 */ "\xdb\x8c\0" /* offset 12169 */ "\xd9\x8a\xd9\x94\xd8\xac\0" /* offset 12172 */ "\xd9\x8a\xd9\x94\xd8\xad\0" /* offset 12179 */ "\xd9\x8a\xd9\x94\xd9\x85\0" /* offset 12186 */ "\xd9\x8a\xd9\x94\xd9\x8a\0" /* offset 12193 */ "\xd8\xa8\xd8\xac\0" /* offset 12200 */ "\xd8\xa8\xd8\xad\0" /* offset 12205 */ "\xd8\xa8\xd8\xae\0" /* offset 12210 */ "\xd8\xa8\xd9\x85\0" /* offset 12215 */ "\xd8\xa8\xd9\x89\0" /* offset 12220 */ "\xd8\xa8\xd9\x8a\0" /* offset 12225 */ "\xd8\xaa\xd8\xac\0" /* offset 12230 */ "\xd8\xaa\xd8\xad\0" /* offset 12235 */ "\xd8\xaa\xd8\xae\0" /* offset 12240 */ "\xd8\xaa\xd9\x85\0" /* offset 12245 */ "\xd8\xaa\xd9\x89\0" /* offset 12250 */ "\xd8\xaa\xd9\x8a\0" /* offset 12255 */ "\xd8\xab\xd8\xac\0" /* offset 12260 */ "\xd8\xab\xd9\x85\0" /* offset 12265 */ "\xd8\xab\xd9\x89\0" /* offset 12270 */ "\xd8\xab\xd9\x8a\0" /* offset 12275 */ "\xd8\xac\xd8\xad\0" /* offset 12280 */ "\xd8\xac\xd9\x85\0" /* offset 12285 */ "\xd8\xad\xd8\xac\0" /* offset 12290 */ "\xd8\xad\xd9\x85\0" /* offset 12295 */ "\xd8\xae\xd8\xac\0" /* offset 12300 */ "\xd8\xae\xd8\xad\0" /* offset 12305 */ "\xd8\xae\xd9\x85\0" /* offset 12310 */ "\xd8\xb3\xd8\xac\0" /* offset 12315 */ "\xd8\xb3\xd8\xad\0" /* offset 12320 */ "\xd8\xb3\xd8\xae\0" /* offset 12325 */ "\xd8\xb3\xd9\x85\0" /* offset 12330 */ "\xd8\xb5\xd8\xad\0" /* offset 12335 */ "\xd8\xb5\xd9\x85\0" /* offset 12340 */ "\xd8\xb6\xd8\xac\0" /* offset 12345 */ "\xd8\xb6\xd8\xad\0" /* offset 12350 */ "\xd8\xb6\xd8\xae\0" /* offset 12355 */ "\xd8\xb6\xd9\x85\0" /* offset 12360 */ "\xd8\xb7\xd8\xad\0" /* offset 12365 */ "\xd8\xb7\xd9\x85\0" /* offset 12370 */ "\xd8\xb8\xd9\x85\0" /* offset 12375 */ "\xd8\xb9\xd8\xac\0" /* offset 12380 */ "\xd8\xb9\xd9\x85\0" /* offset 12385 */ "\xd8\xba\xd8\xac\0" /* offset 12390 */ "\xd8\xba\xd9\x85\0" /* offset 12395 */ "\xd9\x81\xd8\xac\0" /* offset 12400 */ "\xd9\x81\xd8\xad\0" /* offset 12405 */ "\xd9\x81\xd8\xae\0" /* offset 12410 */ "\xd9\x81\xd9\x85\0" /* offset 12415 */ "\xd9\x81\xd9\x89\0" /* offset 12420 */ "\xd9\x81\xd9\x8a\0" /* offset 12425 */ "\xd9\x82\xd8\xad\0" /* offset 12430 */ "\xd9\x82\xd9\x85\0" /* offset 12435 */ "\xd9\x82\xd9\x89\0" /* offset 12440 */ "\xd9\x82\xd9\x8a\0" /* offset 12445 */ "\xd9\x83\xd8\xa7\0" /* offset 12450 */ "\xd9\x83\xd8\xac\0" /* offset 12455 */ "\xd9\x83\xd8\xad\0" /* offset 12460 */ "\xd9\x83\xd8\xae\0" /* offset 12465 */ "\xd9\x83\xd9\x84\0" /* offset 12470 */ "\xd9\x83\xd9\x85\0" /* offset 12475 */ "\xd9\x83\xd9\x89\0" /* offset 12480 */ "\xd9\x83\xd9\x8a\0" /* offset 12485 */ "\xd9\x84\xd8\xac\0" /* offset 12490 */ "\xd9\x84\xd8\xad\0" /* offset 12495 */ "\xd9\x84\xd8\xae\0" /* offset 12500 */ "\xd9\x84\xd9\x85\0" /* offset 12505 */ "\xd9\x84\xd9\x89\0" /* offset 12510 */ "\xd9\x84\xd9\x8a\0" /* offset 12515 */ "\xd9\x85\xd8\xac\0" /* offset 12520 */ "\xd9\x85\xd8\xad\0" /* offset 12525 */ "\xd9\x85\xd8\xae\0" /* offset 12530 */ "\xd9\x85\xd9\x85\0" /* offset 12535 */ "\xd9\x85\xd9\x89\0" /* offset 12540 */ "\xd9\x85\xd9\x8a\0" /* offset 12545 */ "\xd9\x86\xd8\xac\0" /* offset 12550 */ "\xd9\x86\xd8\xad\0" /* offset 12555 */ "\xd9\x86\xd8\xae\0" /* offset 12560 */ "\xd9\x86\xd9\x85\0" /* offset 12565 */ "\xd9\x86\xd9\x89\0" /* offset 12570 */ "\xd9\x86\xd9\x8a\0" /* offset 12575 */ "\xd9\x87\xd8\xac\0" /* offset 12580 */ "\xd9\x87\xd9\x85\0" /* offset 12585 */ "\xd9\x87\xd9\x89\0" /* offset 12590 */ "\xd9\x87\xd9\x8a\0" /* offset 12595 */ "\xd9\x8a\xd8\xac\0" /* offset 12600 */ "\xd9\x8a\xd8\xad\0" /* offset 12605 */ "\xd9\x8a\xd8\xae\0" /* offset 12610 */ "\xd9\x8a\xd9\x85\0" /* offset 12615 */ "\xd9\x8a\xd9\x89\0" /* offset 12620 */ "\xd9\x8a\xd9\x8a\0" /* offset 12625 */ "\xd8\xb0\xd9\xb0\0" /* offset 12630 */ "\xd8\xb1\xd9\xb0\0" /* offset 12635 */ "\xd9\x89\xd9\xb0\0" /* offset 12640 */ "\x20\xd9\x8c\xd9\x91\0" /* offset 12645 */ "\x20\xd9\x8d\xd9\x91\0" /* offset 12651 */ "\x20\xd9\x8e\xd9\x91\0" /* offset 12657 */ "\x20\xd9\x8f\xd9\x91\0" /* offset 12663 */ "\x20\xd9\x90\xd9\x91\0" /* offset 12669 */ "\x20\xd9\x91\xd9\xb0\0" /* offset 12675 */ "\xd9\x8a\xd9\x94\xd8\xb1\0" /* offset 12681 */ "\xd9\x8a\xd9\x94\xd8\xb2\0" /* offset 12688 */ "\xd9\x8a\xd9\x94\xd9\x86\0" /* offset 12695 */ "\xd8\xa8\xd8\xb1\0" /* offset 12702 */ "\xd8\xa8\xd8\xb2\0" /* offset 12707 */ "\xd8\xa8\xd9\x86\0" /* offset 12712 */ "\xd8\xaa\xd8\xb1\0" /* offset 12717 */ "\xd8\xaa\xd8\xb2\0" /* offset 12722 */ "\xd8\xaa\xd9\x86\0" /* offset 12727 */ "\xd8\xab\xd8\xb1\0" /* offset 12732 */ "\xd8\xab\xd8\xb2\0" /* offset 12737 */ "\xd8\xab\xd9\x86\0" /* offset 12742 */ "\xd9\x85\xd8\xa7\0" /* offset 12747 */ "\xd9\x86\xd8\xb1\0" /* offset 12752 */ "\xd9\x86\xd8\xb2\0" /* offset 12757 */ "\xd9\x86\xd9\x86\0" /* offset 12762 */ "\xd9\x8a\xd8\xb1\0" /* offset 12767 */ "\xd9\x8a\xd8\xb2\0" /* offset 12772 */ "\xd9\x8a\xd9\x86\0" /* offset 12777 */ "\xd9\x8a\xd9\x94\xd8\xae\0" /* offset 12782 */ "\xd9\x8a\xd9\x94\xd9\x87\0" /* offset 12789 */ "\xd8\xa8\xd9\x87\0" /* offset 12796 */ "\xd8\xaa\xd9\x87\0" /* offset 12801 */ "\xd8\xb5\xd8\xae\0" /* offset 12806 */ "\xd9\x84\xd9\x87\0" /* offset 12811 */ "\xd9\x86\xd9\x87\0" /* offset 12816 */ "\xd9\x87\xd9\xb0\0" /* offset 12821 */ "\xd9\x8a\xd9\x87\0" /* offset 12826 */ "\xd8\xab\xd9\x87\0" /* offset 12831 */ "\xd8\xb3\xd9\x87\0" /* offset 12836 */ "\xd8\xb4\xd9\x85\0" /* offset 12841 */ "\xd8\xb4\xd9\x87\0" /* offset 12846 */ "\xd9\x80\xd9\x8e\xd9\x91\0" /* offset 12851 */ "\xd9\x80\xd9\x8f\xd9\x91\0" /* offset 12858 */ "\xd9\x80\xd9\x90\xd9\x91\0" /* offset 12865 */ "\xd8\xb7\xd9\x89\0" /* offset 12872 */ "\xd8\xb7\xd9\x8a\0" /* offset 12877 */ "\xd8\xb9\xd9\x89\0" /* offset 12882 */ "\xd8\xb9\xd9\x8a\0" /* offset 12887 */ "\xd8\xba\xd9\x89\0" /* offset 12892 */ "\xd8\xba\xd9\x8a\0" /* offset 12897 */ "\xd8\xb3\xd9\x89\0" /* offset 12902 */ "\xd8\xb3\xd9\x8a\0" /* offset 12907 */ "\xd8\xb4\xd9\x89\0" /* offset 12912 */ "\xd8\xb4\xd9\x8a\0" /* offset 12917 */ "\xd8\xad\xd9\x89\0" /* offset 12922 */ "\xd8\xad\xd9\x8a\0" /* offset 12927 */ "\xd8\xac\xd9\x89\0" /* offset 12932 */ "\xd8\xac\xd9\x8a\0" /* offset 12937 */ "\xd8\xae\xd9\x89\0" /* offset 12942 */ "\xd8\xae\xd9\x8a\0" /* offset 12947 */ "\xd8\xb5\xd9\x89\0" /* offset 12952 */ "\xd8\xb5\xd9\x8a\0" /* offset 12957 */ "\xd8\xb6\xd9\x89\0" /* offset 12962 */ "\xd8\xb6\xd9\x8a\0" /* offset 12967 */ "\xd8\xb4\xd8\xac\0" /* offset 12972 */ "\xd8\xb4\xd8\xad\0" /* offset 12977 */ "\xd8\xb4\xd8\xae\0" /* offset 12982 */ "\xd8\xb4\xd8\xb1\0" /* offset 12987 */ "\xd8\xb3\xd8\xb1\0" /* offset 12992 */ "\xd8\xb5\xd8\xb1\0" /* offset 12997 */ "\xd8\xb6\xd8\xb1\0" /* offset 13002 */ "\xd8\xa7\xd9\x8b\0" /* offset 13007 */ "\xd8\xaa\xd8\xac\xd9\x85\0" /* offset 13012 */ "\xd8\xaa\xd8\xad\xd8\xac\0" /* offset 13019 */ "\xd8\xaa\xd8\xad\xd9\x85\0" /* offset 13026 */ "\xd8\xaa\xd8\xae\xd9\x85\0" /* offset 13033 */ "\xd8\xaa\xd9\x85\xd8\xac\0" /* offset 13040 */ "\xd8\xaa\xd9\x85\xd8\xad\0" /* offset 13047 */ "\xd8\xaa\xd9\x85\xd8\xae\0" /* offset 13054 */ "\xd8\xac\xd9\x85\xd8\xad\0" /* offset 13061 */ "\xd8\xad\xd9\x85\xd9\x8a\0" /* offset 13068 */ "\xd8\xad\xd9\x85\xd9\x89\0" /* offset 13075 */ "\xd8\xb3\xd8\xad\xd8\xac\0" /* offset 13082 */ "\xd8\xb3\xd8\xac\xd8\xad\0" /* offset 13089 */ "\xd8\xb3\xd8\xac\xd9\x89\0" /* offset 13096 */ "\xd8\xb3\xd9\x85\xd8\xad\0" /* offset 13103 */ "\xd8\xb3\xd9\x85\xd8\xac\0" /* offset 13110 */ "\xd8\xb3\xd9\x85\xd9\x85\0" /* offset 13117 */ "\xd8\xb5\xd8\xad\xd8\xad\0" /* offset 13124 */ "\xd8\xb5\xd9\x85\xd9\x85\0" /* offset 13131 */ "\xd8\xb4\xd8\xad\xd9\x85\0" /* offset 13138 */ "\xd8\xb4\xd8\xac\xd9\x8a\0" /* offset 13145 */ "\xd8\xb4\xd9\x85\xd8\xae\0" /* offset 13152 */ "\xd8\xb4\xd9\x85\xd9\x85\0" /* offset 13159 */ "\xd8\xb6\xd8\xad\xd9\x89\0" /* offset 13166 */ "\xd8\xb6\xd8\xae\xd9\x85\0" /* offset 13173 */ "\xd8\xb7\xd9\x85\xd8\xad\0" /* offset 13180 */ "\xd8\xb7\xd9\x85\xd9\x85\0" /* offset 13187 */ "\xd8\xb7\xd9\x85\xd9\x8a\0" /* offset 13194 */ "\xd8\xb9\xd8\xac\xd9\x85\0" /* offset 13201 */ "\xd8\xb9\xd9\x85\xd9\x85\0" /* offset 13208 */ "\xd8\xb9\xd9\x85\xd9\x89\0" /* offset 13215 */ "\xd8\xba\xd9\x85\xd9\x85\0" /* offset 13222 */ "\xd8\xba\xd9\x85\xd9\x8a\0" /* offset 13229 */ "\xd8\xba\xd9\x85\xd9\x89\0" /* offset 13236 */ "\xd9\x81\xd8\xae\xd9\x85\0" /* offset 13243 */ "\xd9\x82\xd9\x85\xd8\xad\0" /* offset 13250 */ "\xd9\x82\xd9\x85\xd9\x85\0" /* offset 13257 */ "\xd9\x84\xd8\xad\xd9\x85\0" /* offset 13264 */ "\xd9\x84\xd8\xad\xd9\x8a\0" /* offset 13271 */ "\xd9\x84\xd8\xad\xd9\x89\0" /* offset 13278 */ "\xd9\x84\xd8\xac\xd8\xac\0" /* offset 13285 */ "\xd9\x84\xd8\xae\xd9\x85\0" /* offset 13292 */ "\xd9\x84\xd9\x85\xd8\xad\0" /* offset 13299 */ "\xd9\x85\xd8\xad\xd8\xac\0" /* offset 13306 */ "\xd9\x85\xd8\xad\xd9\x85\0" /* offset 13313 */ "\xd9\x85\xd8\xad\xd9\x8a\0" /* offset 13320 */ "\xd9\x85\xd8\xac\xd8\xad\0" /* offset 13327 */ "\xd9\x85\xd8\xac\xd9\x85\0" /* offset 13334 */ "\xd9\x85\xd8\xae\xd8\xac\0" /* offset 13341 */ "\xd9\x85\xd8\xae\xd9\x85\0" /* offset 13348 */ "\xd9\x85\xd8\xac\xd8\xae\0" /* offset 13355 */ "\xd9\x87\xd9\x85\xd8\xac\0" /* offset 13362 */ "\xd9\x87\xd9\x85\xd9\x85\0" /* offset 13369 */ "\xd9\x86\xd8\xad\xd9\x85\0" /* offset 13376 */ "\xd9\x86\xd8\xad\xd9\x89\0" /* offset 13383 */ "\xd9\x86\xd8\xac\xd9\x85\0" /* offset 13390 */ "\xd9\x86\xd8\xac\xd9\x89\0" /* offset 13397 */ "\xd9\x86\xd9\x85\xd9\x8a\0" /* offset 13404 */ "\xd9\x86\xd9\x85\xd9\x89\0" /* offset 13411 */ "\xd9\x8a\xd9\x85\xd9\x85\0" /* offset 13418 */ "\xd8\xa8\xd8\xae\xd9\x8a\0" /* offset 13425 */ "\xd8\xaa\xd8\xac\xd9\x8a\0" /* offset 13432 */ "\xd8\xaa\xd8\xac\xd9\x89\0" /* offset 13439 */ "\xd8\xaa\xd8\xae\xd9\x8a\0" /* offset 13446 */ "\xd8\xaa\xd8\xae\xd9\x89\0" /* offset 13453 */ "\xd8\xaa\xd9\x85\xd9\x8a\0" /* offset 13460 */ "\xd8\xaa\xd9\x85\xd9\x89\0" /* offset 13467 */ "\xd8\xac\xd9\x85\xd9\x8a\0" /* offset 13474 */ "\xd8\xac\xd8\xad\xd9\x89\0" /* offset 13481 */ "\xd8\xac\xd9\x85\xd9\x89\0" /* offset 13488 */ "\xd8\xb3\xd8\xae\xd9\x89\0" /* offset 13495 */ "\xd8\xb5\xd8\xad\xd9\x8a\0" /* offset 13502 */ "\xd8\xb4\xd8\xad\xd9\x8a\0" /* offset 13509 */ "\xd8\xb6\xd8\xad\xd9\x8a\0" /* offset 13516 */ "\xd9\x84\xd8\xac\xd9\x8a\0" /* offset 13523 */ "\xd9\x84\xd9\x85\xd9\x8a\0" /* offset 13530 */ "\xd9\x8a\xd8\xad\xd9\x8a\0" /* offset 13537 */ "\xd9\x8a\xd8\xac\xd9\x8a\0" /* offset 13544 */ "\xd9\x8a\xd9\x85\xd9\x8a\0" /* offset 13551 */ "\xd9\x85\xd9\x85\xd9\x8a\0" /* offset 13558 */ "\xd9\x82\xd9\x85\xd9\x8a\0" /* offset 13565 */ "\xd9\x86\xd8\xad\xd9\x8a\0" /* offset 13572 */ "\xd8\xb9\xd9\x85\xd9\x8a\0" /* offset 13579 */ "\xd9\x83\xd9\x85\xd9\x8a\0" /* offset 13586 */ "\xd9\x86\xd8\xac\xd8\xad\0" /* offset 13593 */ "\xd9\x85\xd8\xae\xd9\x8a\0" /* offset 13600 */ "\xd9\x84\xd8\xac\xd9\x85\0" /* offset 13607 */ "\xd9\x83\xd9\x85\xd9\x85\0" /* offset 13614 */ "\xd8\xac\xd8\xad\xd9\x8a\0" /* offset 13621 */ "\xd8\xad\xd8\xac\xd9\x8a\0" /* offset 13628 */ "\xd9\x85\xd8\xac\xd9\x8a\0" /* offset 13635 */ "\xd9\x81\xd9\x85\xd9\x8a\0" /* offset 13642 */ "\xd8\xa8\xd8\xad\xd9\x8a\0" /* offset 13649 */ "\xd8\xb3\xd8\xae\xd9\x8a\0" /* offset 13656 */ "\xd9\x86\xd8\xac\xd9\x8a\0" /* offset 13663 */ "\xd8\xb5\xd9\x84\xdb\x92\0" /* offset 13670 */ "\xd9\x82\xd9\x84\xdb\x92\0" /* offset 13677 */ "\xd8\xa7\xd9\x84\xd9\x84\xd9\x87\0" /* offset 13684 */ "\xd8\xa7\xd9\x83\xd8\xa8\xd8\xb1\0" /* offset 13693 */ "\xd9\x85\xd8\xad\xd9\x85\xd8\xaf\0" /* offset 13702 */ "\xd8\xb5\xd9\x84\xd8\xb9\xd9\x85\0" /* offset 13711 */ "\xd8\xb1\xd8\xb3\xd9\x88\xd9\x84\0" /* offset 13720 */ "\xd8\xb9\xd9\x84\xd9\x8a\xd9\x87\0" /* offset 13729 */ "\xd9\x88\xd8\xb3\xd9\x84\xd9\x85\0" /* offset 13738 */ "\xd8\xb5\xd9\x84\xd9\x89\0" /* offset 13747 */ "\xd8\xb5\xd9\x84\xd9\x89\x20\xd8\xa7\xd9\x84\xd9\x84\xd9\x87\x20\xd8\xb9\xd9\x84\xd9\x8a\xd9\x87\x20\xd9\x88\xd8\xb3\xd9\x84\xd9\x85\0" /* offset 13754 */ "\xd8\xac\xd9\x84\x20\xd8\xac\xd9\x84\xd8\xa7\xd9\x84\xd9\x87\0" /* offset 13788 */ "\xd8\xb1\xdb\x8c\xd8\xa7\xd9\x84\0" /* offset 13804 */ "\xe2\x80\x94\0" /* offset 13813 */ "\xe2\x80\x93\0" /* offset 13817 */ "\x5f\0" /* offset 13821 */ "\x7b\0" /* offset 13823 */ "\x7d\0" /* offset 13825 */ "\xe3\x80\x94\0" /* offset 13827 */ "\xe3\x80\x95\0" /* offset 13831 */ "\xe3\x80\x90\0" /* offset 13835 */ "\xe3\x80\x91\0" /* offset 13839 */ "\xe3\x80\x8a\0" /* offset 13843 */ "\xe3\x80\x8b\0" /* offset 13847 */ "\xe3\x80\x8c\0" /* offset 13851 */ "\xe3\x80\x8d\0" /* offset 13855 */ "\xe3\x80\x8e\0" /* offset 13859 */ "\xe3\x80\x8f\0" /* offset 13863 */ "\x2c\0" /* offset 13867 */ "\xe3\x80\x81\0" /* offset 13869 */ "\x3a\0" /* offset 13873 */ "\x3f\0" /* offset 13875 */ "\x21\0" /* offset 13877 */ "\x23\0" /* offset 13879 */ "\x26\0" /* offset 13881 */ "\x2a\0" /* offset 13883 */ "\x2d\0" /* offset 13885 */ "\x3c\0" /* offset 13887 */ "\x3e\0" /* offset 13889 */ "\x5c\0" /* offset 13891 */ "\x24\0" /* offset 13893 */ "\x25\0" /* offset 13895 */ "\x40\0" /* offset 13897 */ "\x20\xd9\x8b\0" /* offset 13899 */ "\xd9\x80\xd9\x8b\0" /* offset 13903 */ "\x20\xd9\x8c\0" /* offset 13908 */ "\x20\xd9\x8d\0" /* offset 13912 */ "\x20\xd9\x8e\0" /* offset 13916 */ "\xd9\x80\xd9\x8e\0" /* offset 13920 */ "\x20\xd9\x8f\0" /* offset 13925 */ "\xd9\x80\xd9\x8f\0" /* offset 13929 */ "\x20\xd9\x90\0" /* offset 13934 */ "\xd9\x80\xd9\x90\0" /* offset 13938 */ "\x20\xd9\x91\0" /* offset 13943 */ "\xd9\x80\xd9\x91\0" /* offset 13947 */ "\x20\xd9\x92\0" /* offset 13952 */ "\xd9\x80\xd9\x92\0" /* offset 13956 */ "\xd8\xa1\0" /* offset 13961 */ "\xd8\xa7\0" /* offset 13964 */ "\xd8\xa8\0" /* offset 13967 */ "\xd8\xa9\0" /* offset 13970 */ "\xd8\xaa\0" /* offset 13973 */ "\xd8\xab\0" /* offset 13976 */ "\xd8\xac\0" /* offset 13979 */ "\xd8\xad\0" /* offset 13982 */ "\xd8\xae\0" /* offset 13985 */ "\xd8\xaf\0" /* offset 13988 */ "\xd8\xb0\0" /* offset 13991 */ "\xd8\xb1\0" /* offset 13994 */ "\xd8\xb2\0" /* offset 13997 */ "\xd8\xb3\0" /* offset 14000 */ "\xd8\xb4\0" /* offset 14003 */ "\xd8\xb5\0" /* offset 14006 */ "\xd8\xb6\0" /* offset 14009 */ "\xd8\xb7\0" /* offset 14012 */ "\xd8\xb8\0" /* offset 14015 */ "\xd8\xb9\0" /* offset 14018 */ "\xd8\xba\0" /* offset 14021 */ "\xd9\x81\0" /* offset 14024 */ "\xd9\x82\0" /* offset 14027 */ "\xd9\x83\0" /* offset 14030 */ "\xd9\x84\0" /* offset 14033 */ "\xd9\x85\0" /* offset 14036 */ "\xd9\x86\0" /* offset 14039 */ "\xd9\x87\0" /* offset 14042 */ "\xd9\x88\0" /* offset 14045 */ "\xd9\x8a\0" /* offset 14048 */ "\xd9\x84\xd8\xa7\xd9\x93\0" /* offset 14051 */ "\xd9\x84\xd8\xa7\xd9\x94\0" /* offset 14058 */ "\xd9\x84\xd8\xa7\xd9\x95\0" /* offset 14065 */ "\xd9\x84\xd8\xa7\0" /* offset 14072 */ "\x22\0" /* offset 14077 */ "\x27\0" /* offset 14079 */ "\x2f\0" /* offset 14081 */ "\x5b\0" /* offset 14083 */ "\x5d\0" /* offset 14085 */ "\x5e\0" /* offset 14087 */ "\x7c\0" /* offset 14089 */ "\x7e\0" /* offset 14091 */ "\xe2\xa6\x85\0" /* offset 14093 */ "\xe2\xa6\x86\0" /* offset 14097 */ "\xe3\x80\x82\0" /* offset 14101 */ "\xe3\x83\xbb\0" /* offset 14105 */ "\xe3\x82\xa1\0" /* offset 14109 */ "\xe3\x82\xa3\0" /* offset 14113 */ "\xe3\x82\xa5\0" /* offset 14117 */ "\xe3\x82\xa7\0" /* offset 14121 */ "\xe3\x82\xa9\0" /* offset 14125 */ "\xe3\x83\xa3\0" /* offset 14129 */ "\xe3\x83\xa5\0" /* offset 14133 */ "\xe3\x83\xa7\0" /* offset 14137 */ "\xe3\x83\x83\0" /* offset 14141 */ "\xe3\x83\xbc\0" /* offset 14145 */ "\xe3\x83\xb3\0" /* offset 14149 */ "\xe3\x82\x99\0" /* offset 14153 */ "\xe3\x82\x9a\0" /* offset 14157 */ "\xc2\xa2\0" /* offset 14161 */ "\xc2\xa3\0" /* offset 14164 */ "\xc2\xac\0" /* offset 14167 */ "\xc2\xa6\0" /* offset 14170 */ "\xc2\xa5\0" /* offset 14173 */ "\xe2\x82\xa9\0" /* offset 14176 */ "\xe2\x94\x82\0" /* offset 14180 */ "\xe2\x86\x90\0" /* offset 14184 */ "\xe2\x86\x91\0" /* offset 14188 */ "\xe2\x86\x92\0" /* offset 14192 */ "\xe2\x86\x93\0" /* offset 14196 */ "\xe2\x96\xa0\0" /* offset 14200 */ "\xe2\x97\x8b\0" /* offset 14204 */ "\xf0\x9d\x85\x97\xf0\x9d\x85\xa5\0" /* offset 14208 */ "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\0" /* offset 14217 */ "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xae\0" /* offset 14226 */ "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xaf\0" /* offset 14239 */ "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xb0\0" /* offset 14252 */ "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xb1\0" /* offset 14265 */ "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xb2\0" /* offset 14278 */ "\xf0\x9d\x86\xb9\xf0\x9d\x85\xa5\0" /* offset 14291 */ "\xf0\x9d\x86\xba\xf0\x9d\x85\xa5\0" /* offset 14300 */ "\xf0\x9d\x86\xb9\xf0\x9d\x85\xa5\xf0\x9d\x85\xae\0" /* offset 14309 */ "\xf0\x9d\x86\xba\xf0\x9d\x85\xa5\xf0\x9d\x85\xae\0" /* offset 14322 */ "\xf0\x9d\x86\xb9\xf0\x9d\x85\xa5\xf0\x9d\x85\xaf\0" /* offset 14335 */ "\xf0\x9d\x86\xba\xf0\x9d\x85\xa5\xf0\x9d\x85\xaf\0" /* offset 14348 */ "\xce\x91\0" /* offset 14361 */ "\xce\x92\0" /* offset 14364 */ "\xce\x94\0" /* offset 14367 */ "\xce\x95\0" /* offset 14370 */ "\xce\x96\0" /* offset 14373 */ "\xce\x97\0" /* offset 14376 */ "\xce\x99\0" /* offset 14379 */ "\xce\x9a\0" /* offset 14382 */ "\xce\x9b\0" /* offset 14385 */ "\xce\x9c\0" /* offset 14388 */ "\xce\x9d\0" /* offset 14391 */ "\xce\x9e\0" /* offset 14394 */ "\xce\x9f\0" /* offset 14397 */ "\xce\xa1\0" /* offset 14400 */ "\xce\xa3\0" /* offset 14403 */ "\xce\xa4\0" /* offset 14406 */ "\xce\xa6\0" /* offset 14409 */ "\xce\xa7\0" /* offset 14412 */ "\xce\xa8\0" /* offset 14415 */ "\xe2\x88\x87\0" /* offset 14418 */ "\xce\xb1\0" /* offset 14422 */ "\xce\xb4\0" /* offset 14425 */ "\xce\xb6\0" /* offset 14428 */ "\xce\xb7\0" /* offset 14431 */ "\xce\xbb\0" /* offset 14434 */ "\xce\xbd\0" /* offset 14437 */ "\xce\xbe\0" /* offset 14440 */ "\xce\xbf\0" /* offset 14443 */ "\xcf\x83\0" /* offset 14446 */ "\xcf\x84\0" /* offset 14449 */ "\xcf\x85\0" /* offset 14452 */ "\xcf\x87\0" /* offset 14455 */ "\xcf\x88\0" /* offset 14458 */ "\xcf\x89\0" /* offset 14461 */ "\xe2\x88\x82\0" /* offset 14464 */ "\xe4\xb8\xbd\0" /* offset 14468 */ "\xe4\xb8\xb8\0" /* offset 14472 */ "\xe4\xb9\x81\0" /* offset 14476 */ "\xf0\xa0\x84\xa2\0" /* offset 14480 */ "\xe4\xbd\xa0\0" /* offset 14485 */ "\xe4\xbe\xbb\0" /* offset 14489 */ "\xe5\x80\x82\0" /* offset 14493 */ "\xe5\x81\xba\0" /* offset 14497 */ "\xe5\x82\x99\0" /* offset 14501 */ "\xe5\x83\x8f\0" /* offset 14505 */ "\xe3\x92\x9e\0" /* offset 14509 */ "\xf0\xa0\x98\xba\0" /* offset 14513 */ "\xe5\x85\x94\0" /* offset 14518 */ "\xe5\x85\xa4\0" /* offset 14522 */ "\xe5\x85\xb7\0" /* offset 14526 */ "\xf0\xa0\x94\x9c\0" /* offset 14530 */ "\xe3\x92\xb9\0" /* offset 14535 */ "\xe5\x85\xa7\0" /* offset 14539 */ "\xe5\x86\x8d\0" /* offset 14543 */ "\xf0\xa0\x95\x8b\0" /* offset 14547 */ "\xe5\x86\x97\0" /* offset 14552 */ "\xe5\x86\xa4\0" /* offset 14556 */ "\xe4\xbb\x8c\0" /* offset 14560 */ "\xe5\x86\xac\0" /* offset 14564 */ "\xe5\x86\xb5\0" /* offset 14568 */ "\xf0\xa9\x87\x9f\0" /* offset 14572 */ "\xe5\x88\x83\0" /* offset 14577 */ "\xe3\x93\x9f\0" /* offset 14581 */ "\xe5\x88\xbb\0" /* offset 14585 */ "\xe5\x89\x86\0" /* offset 14589 */ "\xe5\x89\xb2\0" /* offset 14593 */ "\xe5\x89\xb7\0" /* offset 14597 */ "\xe3\x94\x95\0" /* offset 14601 */ "\xe5\x8b\x87\0" /* offset 14605 */ "\xe5\x8b\xba\0" /* offset 14609 */ "\xe5\x8c\x85\0" /* offset 14613 */ "\xe5\x8c\x86\0" /* offset 14617 */ "\xe5\x8d\x89\0" /* offset 14621 */ "\xe5\x8d\x9a\0" /* offset 14625 */ "\xe5\x8d\xb3\0" /* offset 14629 */ "\xe5\x8d\xbd\0" /* offset 14633 */ "\xe5\x8d\xbf\0" /* offset 14637 */ "\xf0\xa0\xa8\xac\0" /* offset 14641 */ "\xe7\x81\xb0\0" /* offset 14646 */ "\xe5\x8f\x8a\0" /* offset 14650 */ "\xe5\x8f\x9f\0" /* offset 14654 */ "\xf0\xa0\xad\xa3\0" /* offset 14658 */ "\xe5\x8f\xab\0" /* offset 14663 */ "\xe5\x8f\xb1\0" /* offset 14667 */ "\xe5\x90\x86\0" /* offset 14671 */ "\xe5\x92\x9e\0" /* offset 14675 */ "\xe5\x90\xb8\0" /* offset 14679 */ "\xe5\x91\x88\0" /* offset 14683 */ "\xe5\x91\xa8\0" /* offset 14687 */ "\xe5\x92\xa2\0" /* offset 14691 */ "\xe5\x93\xb6\0" /* offset 14695 */ "\xe5\x94\x90\0" /* offset 14699 */ "\xe5\x95\x93\0" /* offset 14703 */ "\xe5\x95\xa3\0" /* offset 14707 */ "\xe5\x96\x84\0" /* offset 14711 */ "\xe5\x96\x99\0" /* offset 14715 */ "\xe5\x96\xab\0" /* offset 14719 */ "\xe5\x96\xb3\0" /* offset 14723 */ "\xe5\x97\x82\0" /* offset 14727 */ "\xe5\x9c\x96\0" /* offset 14731 */ "\xe5\x9c\x97\0" /* offset 14735 */ "\xe5\x99\x91\0" /* offset 14739 */ "\xe5\x99\xb4\0" /* offset 14743 */ "\xe5\xa3\xae\0" /* offset 14747 */ "\xe5\x9f\x8e\0" /* offset 14751 */ "\xe5\x9f\xb4\0" /* offset 14755 */ "\xe5\xa0\x8d\0" /* offset 14759 */ "\xe5\x9e\x8b\0" /* offset 14763 */ "\xe5\xa0\xb2\0" /* offset 14767 */ "\xe5\xa0\xb1\0" /* offset 14771 */ "\xe5\xa2\xac\0" /* offset 14775 */ "\xf0\xa1\x93\xa4\0" /* offset 14779 */ "\xe5\xa3\xb2\0" /* offset 14784 */ "\xe5\xa3\xb7\0" /* offset 14788 */ "\xe5\xa4\x86\0" /* offset 14792 */ "\xe5\xa4\x9a\0" /* offset 14796 */ "\xe5\xa4\xa2\0" /* offset 14800 */ "\xe5\xa5\xa2\0" /* offset 14804 */ "\xf0\xa1\x9a\xa8\0" /* offset 14808 */ "\xf0\xa1\x9b\xaa\0" /* offset 14813 */ "\xe5\xa7\xac\0" /* offset 14818 */ "\xe5\xa8\x9b\0" /* offset 14822 */ "\xe5\xa8\xa7\0" /* offset 14826 */ "\xe5\xa7\x98\0" /* offset 14830 */ "\xe5\xa9\xa6\0" /* offset 14834 */ "\xe3\x9b\xae\0" /* offset 14838 */ "\xf0\xa1\x8d\xaa\0" /* offset 14842 */ "\xe5\xac\x88\0" /* offset 14847 */ "\xe5\xac\xbe\0" /* offset 14851 */ "\xf0\xa1\xa7\x88\0" /* offset 14855 */ "\xe5\xaf\x83\0" /* offset 14860 */ "\xe5\xaf\x98\0" /* offset 14864 */ "\xe5\xaf\xb3\0" /* offset 14868 */ "\xf0\xa1\xac\x98\0" /* offset 14872 */ "\xe5\xaf\xbf\0" /* offset 14877 */ "\xe5\xb0\x86\0" /* offset 14881 */ "\xe5\xbc\xb3\0" /* offset 14885 */ "\xe3\x9e\x81\0" /* offset 14889 */ "\xe5\xb1\xa0\0" /* offset 14893 */ "\xe5\xb3\x80\0" /* offset 14897 */ "\xe5\xb2\x8d\0" /* offset 14901 */ "\xf0\xa1\xb7\xa4\0" /* offset 14905 */ "\xe5\xb5\x83\0" /* offset 14910 */ "\xf0\xa1\xb7\xa6\0" /* offset 14914 */ "\xe5\xb5\xae\0" /* offset 14919 */ "\xe5\xb5\xab\0" /* offset 14923 */ "\xe5\xb5\xbc\0" /* offset 14927 */ "\xe5\xb7\xa1\0" /* offset 14931 */ "\xe5\xb7\xa2\0" /* offset 14935 */ "\xe3\xa0\xaf\0" /* offset 14939 */ "\xe5\xb7\xbd\0" /* offset 14943 */ "\xe5\xb8\xa8\0" /* offset 14947 */ "\xe5\xb8\xbd\0" /* offset 14951 */ "\xe5\xb9\xa9\0" /* offset 14955 */ "\xe3\xa1\xa2\0" /* offset 14959 */ "\xf0\xa2\x86\x83\0" /* offset 14963 */ "\xe3\xa1\xbc\0" /* offset 14968 */ "\xe5\xba\xb0\0" /* offset 14972 */ "\xe5\xba\xb3\0" /* offset 14976 */ "\xe5\xba\xb6\0" /* offset 14980 */ "\xf0\xaa\x8e\x92\0" /* offset 14984 */ "\xf0\xa2\x8c\xb1\0" /* offset 14989 */ "\xe8\x88\x81\0" /* offset 14994 */ "\xe5\xbc\xa2\0" /* offset 14998 */ "\xe3\xa3\x87\0" /* offset 15002 */ "\xf0\xa3\x8a\xb8\0" /* offset 15006 */ "\xf0\xa6\x87\x9a\0" /* offset 15011 */ "\xe5\xbd\xa2\0" /* offset 15016 */ "\xe5\xbd\xab\0" /* offset 15020 */ "\xe3\xa3\xa3\0" /* offset 15024 */ "\xe5\xbe\x9a\0" /* offset 15028 */ "\xe5\xbf\x8d\0" /* offset 15032 */ "\xe5\xbf\x97\0" /* offset 15036 */ "\xe5\xbf\xb9\0" /* offset 15040 */ "\xe6\x82\x81\0" /* offset 15044 */ "\xe3\xa4\xba\0" /* offset 15048 */ "\xe3\xa4\x9c\0" /* offset 15052 */ "\xf0\xa2\x9b\x94\0" /* offset 15056 */ "\xe6\x83\x87\0" /* offset 15061 */ "\xe6\x85\x88\0" /* offset 15065 */ "\xe6\x85\x8c\0" /* offset 15069 */ "\xe6\x85\x8e\0" /* offset 15073 */ "\xe6\x85\xba\0" /* offset 15077 */ "\xe6\x86\xb2\0" /* offset 15081 */ "\xe6\x86\xa4\0" /* offset 15085 */ "\xe6\x86\xaf\0" /* offset 15089 */ "\xe6\x87\x9e\0" /* offset 15093 */ "\xe6\x88\x90\0" /* offset 15097 */ "\xe6\x88\x9b\0" /* offset 15101 */ "\xe6\x89\x9d\0" /* offset 15105 */ "\xe6\x8a\xb1\0" /* offset 15109 */ "\xe6\x8b\x94\0" /* offset 15113 */ "\xe6\x8d\x90\0" /* offset 15117 */ "\xf0\xa2\xac\x8c\0" /* offset 15121 */ "\xe6\x8c\xbd\0" /* offset 15126 */ "\xe6\x8b\xbc\0" /* offset 15130 */ "\xe6\x8d\xa8\0" /* offset 15134 */ "\xe6\x8e\x83\0" /* offset 15138 */ "\xe6\x8f\xa4\0" /* offset 15142 */ "\xf0\xa2\xaf\xb1\0" /* offset 15146 */ "\xe6\x90\xa2\0" /* offset 15151 */ "\xe6\x8f\x85\0" /* offset 15155 */ "\xe6\x8e\xa9\0" /* offset 15159 */ "\xe3\xa8\xae\0" /* offset 15163 */ "\xe6\x91\xa9\0" /* offset 15167 */ "\xe6\x91\xbe\0" /* offset 15171 */ "\xe6\x92\x9d\0" /* offset 15175 */ "\xe6\x91\xb7\0" /* offset 15179 */ "\xe3\xa9\xac\0" /* offset 15183 */ "\xe6\x95\xac\0" /* offset 15187 */ "\xf0\xa3\x80\x8a\0" /* offset 15191 */ "\xe6\x97\xa3\0" /* offset 15196 */ "\xe6\x9b\xb8\0" /* offset 15200 */ "\xe6\x99\x89\0" /* offset 15204 */ "\xe3\xac\x99\0" /* offset 15208 */ "\xe3\xac\x88\0" /* offset 15212 */ "\xe3\xab\xa4\0" /* offset 15216 */ "\xe5\x86\x92\0" /* offset 15220 */ "\xe5\x86\x95\0" /* offset 15224 */ "\xe6\x9c\x80\0" /* offset 15228 */ "\xe6\x9a\x9c\0" /* offset 15232 */ "\xe8\x82\xad\0" /* offset 15236 */ "\xe4\x8f\x99\0" /* offset 15240 */ "\xe6\x9c\x9b\0" /* offset 15244 */ "\xe6\x9c\xa1\0" /* offset 15248 */ "\xe6\x9d\x9e\0" /* offset 15252 */ "\xe6\x9d\x93\0" /* offset 15256 */ "\xf0\xa3\x8f\x83\0" /* offset 15260 */ "\xe3\xad\x89\0" /* offset 15265 */ "\xe6\x9f\xba\0" /* offset 15269 */ "\xe6\x9e\x85\0" /* offset 15273 */ "\xe6\xa1\x92\0" /* offset 15277 */ "\xf0\xa3\x91\xad\0" /* offset 15281 */ "\xe6\xa2\x8e\0" /* offset 15286 */ "\xe6\xa0\x9f\0" /* offset 15290 */ "\xe6\xa4\x94\0" /* offset 15294 */ "\xe3\xae\x9d\0" /* offset 15298 */ "\xe6\xa5\x82\0" /* offset 15302 */ "\xe6\xa6\xa3\0" /* offset 15306 */ "\xe6\xa7\xaa\0" /* offset 15310 */ "\xe6\xaa\xa8\0" /* offset 15314 */ "\xf0\xa3\x9a\xa3\0" /* offset 15318 */ "\xe6\xab\x9b\0" /* offset 15323 */ "\xe3\xb0\x98\0" /* offset 15327 */ "\xe6\xac\xa1\0" /* offset 15331 */ "\xf0\xa3\xa2\xa7\0" /* offset 15335 */ "\xe6\xad\x94\0" /* offset 15340 */ "\xe3\xb1\x8e\0" /* offset 15344 */ "\xe6\xad\xb2\0" /* offset 15348 */ "\xe6\xae\x9f\0" /* offset 15352 */ "\xe6\xae\xbb\0" /* offset 15356 */ "\xf0\xa3\xaa\x8d\0" /* offset 15360 */ "\xf0\xa1\xb4\x8b\0" /* offset 15365 */ "\xf0\xa3\xab\xba\0" /* offset 15370 */ "\xe6\xb1\x8e\0" /* offset 15375 */ "\xf0\xa3\xb2\xbc\0" /* offset 15379 */ "\xe6\xb2\xbf\0" /* offset 15384 */ "\xe6\xb3\x8d\0" /* offset 15388 */ "\xe6\xb1\xa7\0" /* offset 15392 */ "\xe6\xb4\x96\0" /* offset 15396 */ "\xe6\xb4\xbe\0" /* offset 15400 */ "\xe6\xb5\xa9\0" /* offset 15404 */ "\xe6\xb5\xb8\0" /* offset 15408 */ "\xe6\xb6\x85\0" /* offset 15412 */ "\xf0\xa3\xb4\x9e\0" /* offset 15416 */ "\xe6\xb4\xb4\0" /* offset 15421 */ "\xe6\xb8\xaf\0" /* offset 15425 */ "\xe6\xb9\xae\0" /* offset 15429 */ "\xe3\xb4\xb3\0" /* offset 15433 */ "\xe6\xbb\x8b\0" /* offset 15437 */ "\xe6\xbb\x87\0" /* offset 15441 */ "\xf0\xa3\xbb\x91\0" /* offset 15445 */ "\xe6\xb7\xb9\0" /* offset 15450 */ "\xe6\xbd\xae\0" /* offset 15454 */ "\xf0\xa3\xbd\x9e\0" /* offset 15458 */ "\xf0\xa3\xbe\x8e\0" /* offset 15463 */ "\xe6\xbf\x86\0" /* offset 15468 */ "\xe7\x80\xb9\0" /* offset 15472 */ "\xe7\x80\x9e\0" /* offset 15476 */ "\xe7\x80\x9b\0" /* offset 15480 */ "\xe3\xb6\x96\0" /* offset 15484 */ "\xe7\x81\x8a\0" /* offset 15488 */ "\xe7\x81\xbd\0" /* offset 15492 */ "\xe7\x81\xb7\0" /* offset 15496 */ "\xe7\x82\xad\0" /* offset 15500 */ "\xf0\xa0\x94\xa5\0" /* offset 15504 */ "\xe7\x85\x85\0" /* offset 15509 */ "\xf0\xa4\x89\xa3\0" /* offset 15513 */ "\xe7\x86\x9c\0" /* offset 15518 */ "\xe4\x8e\xab\0" /* offset 15522 */ "\xe7\x88\xa8\0" /* offset 15526 */ "\xe7\x88\xb5\0" /* offset 15530 */ "\xe7\x89\x90\0" /* offset 15534 */ "\xf0\xa4\x98\x88\0" /* offset 15538 */ "\xe7\x8a\x80\0" /* offset 15543 */ "\xe7\x8a\x95\0" /* offset 15547 */ "\xf0\xa4\x9c\xb5\0" /* offset 15551 */ "\xf0\xa4\xa0\x94\0" /* offset 15556 */ "\xe7\x8d\xba\0" /* offset 15561 */ "\xe7\x8e\x8b\0" /* offset 15565 */ "\xe3\xba\xac\0" /* offset 15569 */ "\xe7\x8e\xa5\0" /* offset 15573 */ "\xe3\xba\xb8\0" /* offset 15577 */ "\xe7\x91\x87\0" /* offset 15581 */ "\xe7\x91\x9c\0" /* offset 15585 */ "\xe7\x91\xb1\0" /* offset 15589 */ "\xe7\x92\x85\0" /* offset 15593 */ "\xe7\x93\x8a\0" /* offset 15597 */ "\xe3\xbc\x9b\0" /* offset 15601 */ "\xe7\x94\xa4\0" /* offset 15605 */ "\xf0\xa4\xb0\xb6\0" /* offset 15609 */ "\xe7\x94\xbe\0" /* offset 15614 */ "\xf0\xa4\xb2\x92\0" /* offset 15618 */ "\xf0\xa2\x86\x9f\0" /* offset 15623 */ "\xe7\x98\x90\0" /* offset 15628 */ "\xf0\xa4\xbe\xa1\0" /* offset 15632 */ "\xf0\xa4\xbe\xb8\0" /* offset 15637 */ "\xf0\xa5\x81\x84\0" /* offset 15642 */ "\xe3\xbf\xbc\0" /* offset 15647 */ "\xe4\x80\x88\0" /* offset 15651 */ "\xe7\x9b\xb4\0" /* offset 15655 */ "\xf0\xa5\x83\xb3\0" /* offset 15659 */ "\xf0\xa5\x83\xb2\0" /* offset 15664 */ "\xf0\xa5\x84\x99\0" /* offset 15669 */ "\xf0\xa5\x84\xb3\0" /* offset 15674 */ "\xe7\x9c\x9e\0" /* offset 15679 */ "\xe7\x9c\x9f\0" /* offset 15683 */ "\xe7\x9d\x8a\0" /* offset 15687 */ "\xe4\x80\xb9\0" /* offset 15691 */ "\xe7\x9e\x8b\0" /* offset 15695 */ "\xe4\x81\x86\0" /* offset 15699 */ "\xe4\x82\x96\0" /* offset 15703 */ "\xf0\xa5\x90\x9d\0" /* offset 15707 */ "\xe7\xa1\x8e\0" /* offset 15712 */ "\xe7\xa3\x8c\0" /* offset 15716 */ "\xe4\x83\xa3\0" /* offset 15720 */ "\xf0\xa5\x98\xa6\0" /* offset 15724 */ "\xf0\xa5\x9a\x9a\0" /* offset 15729 */ "\xf0\xa5\x9b\x85\0" /* offset 15734 */ "\xe7\xa7\xab\0" /* offset 15739 */ "\xe4\x84\xaf\0" /* offset 15743 */ "\xe7\xa9\x8a\0" /* offset 15747 */ "\xe7\xa9\x8f\0" /* offset 15751 */ "\xf0\xa5\xa5\xbc\0" /* offset 15755 */ "\xf0\xa5\xaa\xa7\0" /* offset 15760 */ "\xe7\xaa\xae\0" /* offset 15765 */ "\xe4\x88\x82\0" /* offset 15769 */ "\xf0\xa5\xae\xab\0" /* offset 15773 */ "\xe7\xaf\x86\0" /* offset 15778 */ "\xe7\xaf\x89\0" /* offset 15782 */ "\xe4\x88\xa7\0" /* offset 15786 */ "\xf0\xa5\xb2\x80\0" /* offset 15790 */ "\xe7\xb3\x92\0" /* offset 15795 */ "\xe4\x8a\xa0\0" /* offset 15799 */ "\xe7\xb3\xa8\0" /* offset 15803 */ "\xe7\xb3\xa3\0" /* offset 15807 */ "\xe7\xb4\x80\0" /* offset 15811 */ "\xf0\xa5\xbe\x86\0" /* offset 15815 */ "\xe7\xb5\xa3\0" /* offset 15820 */ "\xe4\x8c\x81\0" /* offset 15824 */ "\xe7\xb7\x87\0" /* offset 15828 */ "\xe7\xb8\x82\0" /* offset 15832 */ "\xe7\xb9\x85\0" /* offset 15836 */ "\xe4\x8c\xb4\0" /* offset 15840 */ "\xf0\xa6\x88\xa8\0" /* offset 15844 */ "\xf0\xa6\x89\x87\0" /* offset 15849 */ "\xe4\x8d\x99\0" /* offset 15854 */ "\xf0\xa6\x8b\x99\0" /* offset 15858 */ "\xe7\xbd\xba\0" /* offset 15863 */ "\xf0\xa6\x8c\xbe\0" /* offset 15867 */ "\xe7\xbe\x95\0" /* offset 15872 */ "\xe7\xbf\xba\0" /* offset 15876 */ "\xf0\xa6\x93\x9a\0" /* offset 15880 */ "\xf0\xa6\x94\xa3\0" /* offset 15885 */ "\xe8\x81\xa0\0" /* offset 15890 */ "\xf0\xa6\x96\xa8\0" /* offset 15894 */ "\xe8\x81\xb0\0" /* offset 15899 */ "\xf0\xa3\x8d\x9f\0" /* offset 15903 */ "\xe4\x8f\x95\0" /* offset 15908 */ "\xe8\x82\xb2\0" /* offset 15912 */ "\xe8\x84\x83\0" /* offset 15916 */ "\xe4\x90\x8b\0" /* offset 15920 */ "\xe8\x84\xbe\0" /* offset 15924 */ "\xe5\xaa\xb5\0" /* offset 15928 */ "\xf0\xa6\x9e\xa7\0" /* offset 15932 */ "\xf0\xa6\x9e\xb5\0" /* offset 15937 */ "\xf0\xa3\x8e\x93\0" /* offset 15942 */ "\xf0\xa3\x8e\x9c\0" /* offset 15947 */ "\xe8\x88\x84\0" /* offset 15952 */ "\xe8\xbe\x9e\0" /* offset 15956 */ "\xe4\x91\xab\0" /* offset 15960 */ "\xe8\x8a\x91\0" /* offset 15964 */ "\xe8\x8a\x8b\0" /* offset 15968 */ "\xe8\x8a\x9d\0" /* offset 15972 */ "\xe5\x8a\xb3\0" /* offset 15976 */ "\xe8\x8a\xb1\0" /* offset 15980 */ "\xe8\x8a\xb3\0" /* offset 15984 */ "\xe8\x8a\xbd\0" /* offset 15988 */ "\xe8\x8b\xa6\0" /* offset 15992 */ "\xf0\xa6\xac\xbc\0" /* offset 15996 */ "\xe8\x8c\x9d\0" /* offset 16001 */ "\xe8\x8d\xa3\0" /* offset 16005 */ "\xe8\x8e\xad\0" /* offset 16009 */ "\xe8\x8c\xa3\0" /* offset 16013 */ "\xe8\x8e\xbd\0" /* offset 16017 */ "\xe8\x8f\xa7\0" /* offset 16021 */ "\xe8\x8d\x93\0" /* offset 16025 */ "\xe8\x8f\x8a\0" /* offset 16029 */ "\xe8\x8f\x8c\0" /* offset 16033 */ "\xe8\x8f\x9c\0" /* offset 16037 */ "\xf0\xa6\xb0\xb6\0" /* offset 16041 */ "\xf0\xa6\xb5\xab\0" /* offset 16046 */ "\xf0\xa6\xb3\x95\0" /* offset 16051 */ "\xe4\x94\xab\0" /* offset 16056 */ "\xe8\x93\xb1\0" /* offset 16060 */ "\xe8\x93\xb3\0" /* offset 16064 */ "\xe8\x94\x96\0" /* offset 16068 */ "\xf0\xa7\x8f\x8a\0" /* offset 16072 */ "\xe8\x95\xa4\0" /* offset 16077 */ "\xf0\xa6\xbc\xac\0" /* offset 16081 */ "\xe4\x95\x9d\0" /* offset 16086 */ "\xe4\x95\xa1\0" /* offset 16090 */ "\xf0\xa6\xbe\xb1\0" /* offset 16094 */ "\xf0\xa7\x83\x92\0" /* offset 16099 */ "\xe4\x95\xab\0" /* offset 16104 */ "\xe8\x99\x90\0" /* offset 16108 */ "\xe8\x99\xa7\0" /* offset 16112 */ "\xe8\x99\xa9\0" /* offset 16116 */ "\xe8\x9a\xa9\0" /* offset 16120 */ "\xe8\x9a\x88\0" /* offset 16124 */ "\xe8\x9c\x8e\0" /* offset 16128 */ "\xe8\x9b\xa2\0" /* offset 16132 */ "\xe8\x9d\xb9\0" /* offset 16136 */ "\xe8\x9c\xa8\0" /* offset 16140 */ "\xe8\x9d\xab\0" /* offset 16144 */ "\xe8\x9e\x86\0" /* offset 16148 */ "\xe4\xb5\x97\0" /* offset 16152 */ "\xe8\x9f\xa1\0" /* offset 16156 */ "\xe8\xa0\x81\0" /* offset 16160 */ "\xe4\x97\xb9\0" /* offset 16164 */ "\xe8\xa1\xa0\0" /* offset 16168 */ "\xf0\xa7\x99\xa7\0" /* offset 16172 */ "\xe8\xa3\x97\0" /* offset 16177 */ "\xe8\xa3\x9e\0" /* offset 16181 */ "\xe4\x98\xb5\0" /* offset 16185 */ "\xe8\xa3\xba\0" /* offset 16189 */ "\xe3\x92\xbb\0" /* offset 16193 */ "\xf0\xa7\xa2\xae\0" /* offset 16197 */ "\xf0\xa7\xa5\xa6\0" /* offset 16202 */ "\xe4\x9a\xbe\0" /* offset 16207 */ "\xe4\x9b\x87\0" /* offset 16211 */ "\xe8\xaa\xa0\0" /* offset 16215 */ "\xe8\xab\xad\0" /* offset 16219 */ "\xe8\xae\x8a\0" /* offset 16223 */ "\xf0\xa7\xb2\xa8\0" /* offset 16227 */ "\xe8\xb2\xab\0" /* offset 16232 */ "\xe8\xb3\x81\0" /* offset 16236 */ "\xe8\xb4\x9b\0" /* offset 16240 */ "\xe8\xb5\xb7\0" /* offset 16244 */ "\xf0\xa7\xbc\xaf\0" /* offset 16248 */ "\xf0\xa0\xa0\x84\0" /* offset 16253 */ "\xe8\xb7\x8b\0" /* offset 16258 */ "\xe8\xb6\xbc\0" /* offset 16262 */ "\xe8\xb7\xb0\0" /* offset 16266 */ "\xf0\xa0\xa3\x9e\0" /* offset 16270 */ "\xe8\xbb\x94\0" /* offset 16275 */ "\xe8\xbc\xb8\0" /* offset 16279 */ "\xf0\xa8\x97\x92\0" /* offset 16283 */ "\xf0\xa8\x97\xad\0" /* offset 16288 */ "\xe9\x82\x94\0" /* offset 16293 */ "\xe9\x83\xb1\0" /* offset 16297 */ "\xe9\x84\x91\0" /* offset 16301 */ "\xf0\xa8\x9c\xae\0" /* offset 16305 */ "\xe9\x84\x9b\0" /* offset 16310 */ "\xe9\x88\xb8\0" /* offset 16314 */ "\xe9\x8b\x97\0" /* offset 16318 */ "\xe9\x8b\x98\0" /* offset 16322 */ "\xe9\x89\xbc\0" /* offset 16326 */ "\xe9\x8f\xb9\0" /* offset 16330 */ "\xe9\x90\x95\0" /* offset 16334 */ "\xf0\xa8\xaf\xba\0" /* offset 16338 */ "\xe9\x96\x8b\0" /* offset 16343 */ "\xe4\xa6\x95\0" /* offset 16347 */ "\xe9\x96\xb7\0" /* offset 16351 */ "\xf0\xa8\xb5\xb7\0" /* offset 16355 */ "\xe4\xa7\xa6\0" /* offset 16360 */ "\xe9\x9b\x83\0" /* offset 16364 */ "\xe5\xb6\xb2\0" /* offset 16368 */ "\xe9\x9c\xa3\0" /* offset 16372 */ "\xf0\xa9\x85\x85\0" /* offset 16376 */ "\xf0\xa9\x88\x9a\0" /* offset 16381 */ "\xe4\xa9\xae\0" /* offset 16386 */ "\xe4\xa9\xb6\0" /* offset 16390 */ "\xe9\x9f\xa0\0" /* offset 16394 */ "\xf0\xa9\x90\x8a\0" /* offset 16398 */ "\xe4\xaa\xb2\0" /* offset 16403 */ "\xf0\xa9\x92\x96\0" /* offset 16407 */ "\xe9\xa0\x8b\0" /* offset 16412 */ "\xe9\xa0\xa9\0" /* offset 16416 */ "\xf0\xa9\x96\xb6\0" /* offset 16420 */ "\xe9\xa3\xa2\0" /* offset 16425 */ "\xe4\xac\xb3\0" /* offset 16429 */ "\xe9\xa4\xa9\0" /* offset 16433 */ "\xe9\xa6\xa7\0" /* offset 16437 */ "\xe9\xa7\x82\0" /* offset 16441 */ "\xe9\xa7\xbe\0" /* offset 16445 */ "\xe4\xaf\x8e\0" /* offset 16449 */ "\xf0\xa9\xac\xb0\0" /* offset 16453 */ "\xe9\xac\x92\0" /* offset 16458 */ "\xe9\xb1\x80\0" /* offset 16462 */ "\xe9\xb3\xbd\0" /* offset 16466 */ "\xe4\xb3\x8e\0" /* offset 16470 */ "\xe4\xb3\xad\0" /* offset 16474 */ "\xe9\xb5\xa7\0" /* offset 16478 */ "\xf0\xaa\x83\x8e\0" /* offset 16482 */ "\xe4\xb3\xb8\0" /* offset 16487 */ "\xf0\xaa\x84\x85\0" /* offset 16491 */ "\xf0\xaa\x88\x8e\0" /* offset 16496 */ "\xf0\xaa\x8a\x91\0" /* offset 16501 */ "\xe4\xb5\x96\0" /* offset 16506 */ "\xe9\xbb\xbe\0" /* offset 16510 */ "\xe9\xbc\x85\0" /* offset 16514 */ "\xe9\xbc\x8f\0" /* offset 16518 */ "\xe9\xbc\x96\0" /* offset 16522 */ "\xf0\xaa\x98\x80\0" /* offset 16526 */; #endif /* DECOMP_H */ psi-0.14/iris/src/libidn/qint.h0000644000175000017500000000052611305557616014471 0ustar janjan// simple stdint.h-style replacement without any conflicts #ifndef QINT_H #define QINT_H typedef unsigned char my_uint8_t; typedef unsigned short int my_uint16_t; typedef unsigned int my_uint32_t; typedef char my_int8_t; typedef short int my_int16_t; typedef int my_int32_t; #endif psi-0.14/iris/src/libidn/rfc3454.c0000644000175000017500000077271011305557616014616 0ustar janjan#include /* * A.1 Unassigned code points in Unicode 3.2 * */ Stringprep_table_element stringprep_rfc3454_A_1[] = { { 0x000221 }, /* 0221 */ { 0x000234, 0x00024F }, /* 0234-024F */ { 0x0002AE, 0x0002AF }, /* 02AE-02AF */ { 0x0002EF, 0x0002FF }, /* 02EF-02FF */ { 0x000350, 0x00035F }, /* 0350-035F */ { 0x000370, 0x000373 }, /* 0370-0373 */ { 0x000376, 0x000379 }, /* 0376-0379 */ { 0x00037B, 0x00037D }, /* 037B-037D */ { 0x00037F, 0x000383 }, /* 037F-0383 */ { 0x00038B }, /* 038B */ { 0x00038D }, /* 038D */ { 0x0003A2 }, /* 03A2 */ { 0x0003CF }, /* 03CF */ { 0x0003F7, 0x0003FF }, /* 03F7-03FF */ { 0x000487 }, /* 0487 */ { 0x0004CF }, /* 04CF */ { 0x0004F6, 0x0004F7 }, /* 04F6-04F7 */ { 0x0004FA, 0x0004FF }, /* 04FA-04FF */ { 0x000510, 0x000530 }, /* 0510-0530 */ { 0x000557, 0x000558 }, /* 0557-0558 */ { 0x000560 }, /* 0560 */ { 0x000588 }, /* 0588 */ { 0x00058B, 0x000590 }, /* 058B-0590 */ { 0x0005A2 }, /* 05A2 */ { 0x0005BA }, /* 05BA */ { 0x0005C5, 0x0005CF }, /* 05C5-05CF */ { 0x0005EB, 0x0005EF }, /* 05EB-05EF */ { 0x0005F5, 0x00060B }, /* 05F5-060B */ { 0x00060D, 0x00061A }, /* 060D-061A */ { 0x00061C, 0x00061E }, /* 061C-061E */ { 0x000620 }, /* 0620 */ { 0x00063B, 0x00063F }, /* 063B-063F */ { 0x000656, 0x00065F }, /* 0656-065F */ { 0x0006EE, 0x0006EF }, /* 06EE-06EF */ { 0x0006FF }, /* 06FF */ { 0x00070E }, /* 070E */ { 0x00072D, 0x00072F }, /* 072D-072F */ { 0x00074B, 0x00077F }, /* 074B-077F */ { 0x0007B2, 0x000900 }, /* 07B2-0900 */ { 0x000904 }, /* 0904 */ { 0x00093A, 0x00093B }, /* 093A-093B */ { 0x00094E, 0x00094F }, /* 094E-094F */ { 0x000955, 0x000957 }, /* 0955-0957 */ { 0x000971, 0x000980 }, /* 0971-0980 */ { 0x000984 }, /* 0984 */ { 0x00098D, 0x00098E }, /* 098D-098E */ { 0x000991, 0x000992 }, /* 0991-0992 */ { 0x0009A9 }, /* 09A9 */ { 0x0009B1 }, /* 09B1 */ { 0x0009B3, 0x0009B5 }, /* 09B3-09B5 */ { 0x0009BA, 0x0009BB }, /* 09BA-09BB */ { 0x0009BD }, /* 09BD */ { 0x0009C5, 0x0009C6 }, /* 09C5-09C6 */ { 0x0009C9, 0x0009CA }, /* 09C9-09CA */ { 0x0009CE, 0x0009D6 }, /* 09CE-09D6 */ { 0x0009D8, 0x0009DB }, /* 09D8-09DB */ { 0x0009DE }, /* 09DE */ { 0x0009E4, 0x0009E5 }, /* 09E4-09E5 */ { 0x0009FB, 0x000A01 }, /* 09FB-0A01 */ { 0x000A03, 0x000A04 }, /* 0A03-0A04 */ { 0x000A0B, 0x000A0E }, /* 0A0B-0A0E */ { 0x000A11, 0x000A12 }, /* 0A11-0A12 */ { 0x000A29 }, /* 0A29 */ { 0x000A31 }, /* 0A31 */ { 0x000A34 }, /* 0A34 */ { 0x000A37 }, /* 0A37 */ { 0x000A3A, 0x000A3B }, /* 0A3A-0A3B */ { 0x000A3D }, /* 0A3D */ { 0x000A43, 0x000A46 }, /* 0A43-0A46 */ { 0x000A49, 0x000A4A }, /* 0A49-0A4A */ { 0x000A4E, 0x000A58 }, /* 0A4E-0A58 */ { 0x000A5D }, /* 0A5D */ { 0x000A5F, 0x000A65 }, /* 0A5F-0A65 */ { 0x000A75, 0x000A80 }, /* 0A75-0A80 */ { 0x000A84 }, /* 0A84 */ { 0x000A8C }, /* 0A8C */ { 0x000A8E }, /* 0A8E */ { 0x000A92 }, /* 0A92 */ { 0x000AA9 }, /* 0AA9 */ { 0x000AB1 }, /* 0AB1 */ { 0x000AB4 }, /* 0AB4 */ { 0x000ABA, 0x000ABB }, /* 0ABA-0ABB */ { 0x000AC6 }, /* 0AC6 */ { 0x000ACA }, /* 0ACA */ { 0x000ACE, 0x000ACF }, /* 0ACE-0ACF */ { 0x000AD1, 0x000ADF }, /* 0AD1-0ADF */ { 0x000AE1, 0x000AE5 }, /* 0AE1-0AE5 */ { 0x000AF0, 0x000B00 }, /* 0AF0-0B00 */ { 0x000B04 }, /* 0B04 */ { 0x000B0D, 0x000B0E }, /* 0B0D-0B0E */ { 0x000B11, 0x000B12 }, /* 0B11-0B12 */ { 0x000B29 }, /* 0B29 */ { 0x000B31 }, /* 0B31 */ { 0x000B34, 0x000B35 }, /* 0B34-0B35 */ { 0x000B3A, 0x000B3B }, /* 0B3A-0B3B */ { 0x000B44, 0x000B46 }, /* 0B44-0B46 */ { 0x000B49, 0x000B4A }, /* 0B49-0B4A */ { 0x000B4E, 0x000B55 }, /* 0B4E-0B55 */ { 0x000B58, 0x000B5B }, /* 0B58-0B5B */ { 0x000B5E }, /* 0B5E */ { 0x000B62, 0x000B65 }, /* 0B62-0B65 */ { 0x000B71, 0x000B81 }, /* 0B71-0B81 */ { 0x000B84 }, /* 0B84 */ { 0x000B8B, 0x000B8D }, /* 0B8B-0B8D */ { 0x000B91 }, /* 0B91 */ { 0x000B96, 0x000B98 }, /* 0B96-0B98 */ { 0x000B9B }, /* 0B9B */ { 0x000B9D }, /* 0B9D */ { 0x000BA0, 0x000BA2 }, /* 0BA0-0BA2 */ { 0x000BA5, 0x000BA7 }, /* 0BA5-0BA7 */ { 0x000BAB, 0x000BAD }, /* 0BAB-0BAD */ { 0x000BB6 }, /* 0BB6 */ { 0x000BBA, 0x000BBD }, /* 0BBA-0BBD */ { 0x000BC3, 0x000BC5 }, /* 0BC3-0BC5 */ { 0x000BC9 }, /* 0BC9 */ { 0x000BCE, 0x000BD6 }, /* 0BCE-0BD6 */ { 0x000BD8, 0x000BE6 }, /* 0BD8-0BE6 */ { 0x000BF3, 0x000C00 }, /* 0BF3-0C00 */ { 0x000C04 }, /* 0C04 */ { 0x000C0D }, /* 0C0D */ { 0x000C11 }, /* 0C11 */ { 0x000C29 }, /* 0C29 */ { 0x000C34 }, /* 0C34 */ { 0x000C3A, 0x000C3D }, /* 0C3A-0C3D */ { 0x000C45 }, /* 0C45 */ { 0x000C49 }, /* 0C49 */ { 0x000C4E, 0x000C54 }, /* 0C4E-0C54 */ { 0x000C57, 0x000C5F }, /* 0C57-0C5F */ { 0x000C62, 0x000C65 }, /* 0C62-0C65 */ { 0x000C70, 0x000C81 }, /* 0C70-0C81 */ { 0x000C84 }, /* 0C84 */ { 0x000C8D }, /* 0C8D */ { 0x000C91 }, /* 0C91 */ { 0x000CA9 }, /* 0CA9 */ { 0x000CB4 }, /* 0CB4 */ { 0x000CBA, 0x000CBD }, /* 0CBA-0CBD */ { 0x000CC5 }, /* 0CC5 */ { 0x000CC9 }, /* 0CC9 */ { 0x000CCE, 0x000CD4 }, /* 0CCE-0CD4 */ { 0x000CD7, 0x000CDD }, /* 0CD7-0CDD */ { 0x000CDF }, /* 0CDF */ { 0x000CE2, 0x000CE5 }, /* 0CE2-0CE5 */ { 0x000CF0, 0x000D01 }, /* 0CF0-0D01 */ { 0x000D04 }, /* 0D04 */ { 0x000D0D }, /* 0D0D */ { 0x000D11 }, /* 0D11 */ { 0x000D29 }, /* 0D29 */ { 0x000D3A, 0x000D3D }, /* 0D3A-0D3D */ { 0x000D44, 0x000D45 }, /* 0D44-0D45 */ { 0x000D49 }, /* 0D49 */ { 0x000D4E, 0x000D56 }, /* 0D4E-0D56 */ { 0x000D58, 0x000D5F }, /* 0D58-0D5F */ { 0x000D62, 0x000D65 }, /* 0D62-0D65 */ { 0x000D70, 0x000D81 }, /* 0D70-0D81 */ { 0x000D84 }, /* 0D84 */ { 0x000D97, 0x000D99 }, /* 0D97-0D99 */ { 0x000DB2 }, /* 0DB2 */ { 0x000DBC }, /* 0DBC */ { 0x000DBE, 0x000DBF }, /* 0DBE-0DBF */ { 0x000DC7, 0x000DC9 }, /* 0DC7-0DC9 */ { 0x000DCB, 0x000DCE }, /* 0DCB-0DCE */ { 0x000DD5 }, /* 0DD5 */ { 0x000DD7 }, /* 0DD7 */ { 0x000DE0, 0x000DF1 }, /* 0DE0-0DF1 */ { 0x000DF5, 0x000E00 }, /* 0DF5-0E00 */ { 0x000E3B, 0x000E3E }, /* 0E3B-0E3E */ { 0x000E5C, 0x000E80 }, /* 0E5C-0E80 */ { 0x000E83 }, /* 0E83 */ { 0x000E85, 0x000E86 }, /* 0E85-0E86 */ { 0x000E89 }, /* 0E89 */ { 0x000E8B, 0x000E8C }, /* 0E8B-0E8C */ { 0x000E8E, 0x000E93 }, /* 0E8E-0E93 */ { 0x000E98 }, /* 0E98 */ { 0x000EA0 }, /* 0EA0 */ { 0x000EA4 }, /* 0EA4 */ { 0x000EA6 }, /* 0EA6 */ { 0x000EA8, 0x000EA9 }, /* 0EA8-0EA9 */ { 0x000EAC }, /* 0EAC */ { 0x000EBA }, /* 0EBA */ { 0x000EBE, 0x000EBF }, /* 0EBE-0EBF */ { 0x000EC5 }, /* 0EC5 */ { 0x000EC7 }, /* 0EC7 */ { 0x000ECE, 0x000ECF }, /* 0ECE-0ECF */ { 0x000EDA, 0x000EDB }, /* 0EDA-0EDB */ { 0x000EDE, 0x000EFF }, /* 0EDE-0EFF */ { 0x000F48 }, /* 0F48 */ { 0x000F6B, 0x000F70 }, /* 0F6B-0F70 */ { 0x000F8C, 0x000F8F }, /* 0F8C-0F8F */ { 0x000F98 }, /* 0F98 */ { 0x000FBD }, /* 0FBD */ { 0x000FCD, 0x000FCE }, /* 0FCD-0FCE */ { 0x000FD0, 0x000FFF }, /* 0FD0-0FFF */ { 0x001022 }, /* 1022 */ { 0x001028 }, /* 1028 */ { 0x00102B }, /* 102B */ { 0x001033, 0x001035 }, /* 1033-1035 */ { 0x00103A, 0x00103F }, /* 103A-103F */ { 0x00105A, 0x00109F }, /* 105A-109F */ { 0x0010C6, 0x0010CF }, /* 10C6-10CF */ { 0x0010F9, 0x0010FA }, /* 10F9-10FA */ { 0x0010FC, 0x0010FF }, /* 10FC-10FF */ { 0x00115A, 0x00115E }, /* 115A-115E */ { 0x0011A3, 0x0011A7 }, /* 11A3-11A7 */ { 0x0011FA, 0x0011FF }, /* 11FA-11FF */ { 0x001207 }, /* 1207 */ { 0x001247 }, /* 1247 */ { 0x001249 }, /* 1249 */ { 0x00124E, 0x00124F }, /* 124E-124F */ { 0x001257 }, /* 1257 */ { 0x001259 }, /* 1259 */ { 0x00125E, 0x00125F }, /* 125E-125F */ { 0x001287 }, /* 1287 */ { 0x001289 }, /* 1289 */ { 0x00128E, 0x00128F }, /* 128E-128F */ { 0x0012AF }, /* 12AF */ { 0x0012B1 }, /* 12B1 */ { 0x0012B6, 0x0012B7 }, /* 12B6-12B7 */ { 0x0012BF }, /* 12BF */ { 0x0012C1 }, /* 12C1 */ { 0x0012C6, 0x0012C7 }, /* 12C6-12C7 */ { 0x0012CF }, /* 12CF */ { 0x0012D7 }, /* 12D7 */ { 0x0012EF }, /* 12EF */ { 0x00130F }, /* 130F */ { 0x001311 }, /* 1311 */ { 0x001316, 0x001317 }, /* 1316-1317 */ { 0x00131F }, /* 131F */ { 0x001347 }, /* 1347 */ { 0x00135B, 0x001360 }, /* 135B-1360 */ { 0x00137D, 0x00139F }, /* 137D-139F */ { 0x0013F5, 0x001400 }, /* 13F5-1400 */ { 0x001677, 0x00167F }, /* 1677-167F */ { 0x00169D, 0x00169F }, /* 169D-169F */ { 0x0016F1, 0x0016FF }, /* 16F1-16FF */ { 0x00170D }, /* 170D */ { 0x001715, 0x00171F }, /* 1715-171F */ { 0x001737, 0x00173F }, /* 1737-173F */ { 0x001754, 0x00175F }, /* 1754-175F */ { 0x00176D }, /* 176D */ { 0x001771 }, /* 1771 */ { 0x001774, 0x00177F }, /* 1774-177F */ { 0x0017DD, 0x0017DF }, /* 17DD-17DF */ { 0x0017EA, 0x0017FF }, /* 17EA-17FF */ { 0x00180F }, /* 180F */ { 0x00181A, 0x00181F }, /* 181A-181F */ { 0x001878, 0x00187F }, /* 1878-187F */ { 0x0018AA, 0x001DFF }, /* 18AA-1DFF */ { 0x001E9C, 0x001E9F }, /* 1E9C-1E9F */ { 0x001EFA, 0x001EFF }, /* 1EFA-1EFF */ { 0x001F16, 0x001F17 }, /* 1F16-1F17 */ { 0x001F1E, 0x001F1F }, /* 1F1E-1F1F */ { 0x001F46, 0x001F47 }, /* 1F46-1F47 */ { 0x001F4E, 0x001F4F }, /* 1F4E-1F4F */ { 0x001F58 }, /* 1F58 */ { 0x001F5A }, /* 1F5A */ { 0x001F5C }, /* 1F5C */ { 0x001F5E }, /* 1F5E */ { 0x001F7E, 0x001F7F }, /* 1F7E-1F7F */ { 0x001FB5 }, /* 1FB5 */ { 0x001FC5 }, /* 1FC5 */ { 0x001FD4, 0x001FD5 }, /* 1FD4-1FD5 */ { 0x001FDC }, /* 1FDC */ { 0x001FF0, 0x001FF1 }, /* 1FF0-1FF1 */ { 0x001FF5 }, /* 1FF5 */ { 0x001FFF }, /* 1FFF */ { 0x002053, 0x002056 }, /* 2053-2056 */ { 0x002058, 0x00205E }, /* 2058-205E */ { 0x002064, 0x002069 }, /* 2064-2069 */ { 0x002072, 0x002073 }, /* 2072-2073 */ { 0x00208F, 0x00209F }, /* 208F-209F */ { 0x0020B2, 0x0020CF }, /* 20B2-20CF */ { 0x0020EB, 0x0020FF }, /* 20EB-20FF */ { 0x00213B, 0x00213C }, /* 213B-213C */ { 0x00214C, 0x002152 }, /* 214C-2152 */ { 0x002184, 0x00218F }, /* 2184-218F */ { 0x0023CF, 0x0023FF }, /* 23CF-23FF */ { 0x002427, 0x00243F }, /* 2427-243F */ { 0x00244B, 0x00245F }, /* 244B-245F */ { 0x0024FF }, /* 24FF */ { 0x002614, 0x002615 }, /* 2614-2615 */ { 0x002618 }, /* 2618 */ { 0x00267E, 0x00267F }, /* 267E-267F */ { 0x00268A, 0x002700 }, /* 268A-2700 */ { 0x002705 }, /* 2705 */ { 0x00270A, 0x00270B }, /* 270A-270B */ { 0x002728 }, /* 2728 */ { 0x00274C }, /* 274C */ { 0x00274E }, /* 274E */ { 0x002753, 0x002755 }, /* 2753-2755 */ { 0x002757 }, /* 2757 */ { 0x00275F, 0x002760 }, /* 275F-2760 */ { 0x002795, 0x002797 }, /* 2795-2797 */ { 0x0027B0 }, /* 27B0 */ { 0x0027BF, 0x0027CF }, /* 27BF-27CF */ { 0x0027EC, 0x0027EF }, /* 27EC-27EF */ { 0x002B00, 0x002E7F }, /* 2B00-2E7F */ { 0x002E9A }, /* 2E9A */ { 0x002EF4, 0x002EFF }, /* 2EF4-2EFF */ { 0x002FD6, 0x002FEF }, /* 2FD6-2FEF */ { 0x002FFC, 0x002FFF }, /* 2FFC-2FFF */ { 0x003040 }, /* 3040 */ { 0x003097, 0x003098 }, /* 3097-3098 */ { 0x003100, 0x003104 }, /* 3100-3104 */ { 0x00312D, 0x003130 }, /* 312D-3130 */ { 0x00318F }, /* 318F */ { 0x0031B8, 0x0031EF }, /* 31B8-31EF */ { 0x00321D, 0x00321F }, /* 321D-321F */ { 0x003244, 0x003250 }, /* 3244-3250 */ { 0x00327C, 0x00327E }, /* 327C-327E */ { 0x0032CC, 0x0032CF }, /* 32CC-32CF */ { 0x0032FF }, /* 32FF */ { 0x003377, 0x00337A }, /* 3377-337A */ { 0x0033DE, 0x0033DF }, /* 33DE-33DF */ { 0x0033FF }, /* 33FF */ { 0x004DB6, 0x004DFF }, /* 4DB6-4DFF */ { 0x009FA6, 0x009FFF }, /* 9FA6-9FFF */ { 0x00A48D, 0x00A48F }, /* A48D-A48F */ { 0x00A4C7, 0x00ABFF }, /* A4C7-ABFF */ { 0x00D7A4, 0x00D7FF }, /* D7A4-D7FF */ { 0x00FA2E, 0x00FA2F }, /* FA2E-FA2F */ { 0x00FA6B, 0x00FAFF }, /* FA6B-FAFF */ { 0x00FB07, 0x00FB12 }, /* FB07-FB12 */ { 0x00FB18, 0x00FB1C }, /* FB18-FB1C */ { 0x00FB37 }, /* FB37 */ { 0x00FB3D }, /* FB3D */ { 0x00FB3F }, /* FB3F */ { 0x00FB42 }, /* FB42 */ { 0x00FB45 }, /* FB45 */ { 0x00FBB2, 0x00FBD2 }, /* FBB2-FBD2 */ { 0x00FD40, 0x00FD4F }, /* FD40-FD4F */ { 0x00FD90, 0x00FD91 }, /* FD90-FD91 */ { 0x00FDC8, 0x00FDCF }, /* FDC8-FDCF */ { 0x00FDFD, 0x00FDFF }, /* FDFD-FDFF */ { 0x00FE10, 0x00FE1F }, /* FE10-FE1F */ { 0x00FE24, 0x00FE2F }, /* FE24-FE2F */ { 0x00FE47, 0x00FE48 }, /* FE47-FE48 */ { 0x00FE53 }, /* FE53 */ { 0x00FE67 }, /* FE67 */ { 0x00FE6C, 0x00FE6F }, /* FE6C-FE6F */ { 0x00FE75 }, /* FE75 */ { 0x00FEFD, 0x00FEFE }, /* FEFD-FEFE */ { 0x00FF00 }, /* FF00 */ { 0x00FFBF, 0x00FFC1 }, /* FFBF-FFC1 */ { 0x00FFC8, 0x00FFC9 }, /* FFC8-FFC9 */ { 0x00FFD0, 0x00FFD1 }, /* FFD0-FFD1 */ { 0x00FFD8, 0x00FFD9 }, /* FFD8-FFD9 */ { 0x00FFDD, 0x00FFDF }, /* FFDD-FFDF */ { 0x00FFE7 }, /* FFE7 */ { 0x00FFEF, 0x00FFF8 }, /* FFEF-FFF8 */ { 0x010000, 0x0102FF }, /* 10000-102FF */ { 0x01031F }, /* 1031F */ { 0x010324, 0x01032F }, /* 10324-1032F */ { 0x01034B, 0x0103FF }, /* 1034B-103FF */ { 0x010426, 0x010427 }, /* 10426-10427 */ { 0x01044E, 0x01CFFF }, /* 1044E-1CFFF */ { 0x01D0F6, 0x01D0FF }, /* 1D0F6-1D0FF */ { 0x01D127, 0x01D129 }, /* 1D127-1D129 */ { 0x01D1DE, 0x01D3FF }, /* 1D1DE-1D3FF */ { 0x01D455 }, /* 1D455 */ { 0x01D49D }, /* 1D49D */ { 0x01D4A0, 0x01D4A1 }, /* 1D4A0-1D4A1 */ { 0x01D4A3, 0x01D4A4 }, /* 1D4A3-1D4A4 */ { 0x01D4A7, 0x01D4A8 }, /* 1D4A7-1D4A8 */ { 0x01D4AD }, /* 1D4AD */ { 0x01D4BA }, /* 1D4BA */ { 0x01D4BC }, /* 1D4BC */ { 0x01D4C1 }, /* 1D4C1 */ { 0x01D4C4 }, /* 1D4C4 */ { 0x01D506 }, /* 1D506 */ { 0x01D50B, 0x01D50C }, /* 1D50B-1D50C */ { 0x01D515 }, /* 1D515 */ { 0x01D51D }, /* 1D51D */ { 0x01D53A }, /* 1D53A */ { 0x01D53F }, /* 1D53F */ { 0x01D545 }, /* 1D545 */ { 0x01D547, 0x01D549 }, /* 1D547-1D549 */ { 0x01D551 }, /* 1D551 */ { 0x01D6A4, 0x01D6A7 }, /* 1D6A4-1D6A7 */ { 0x01D7CA, 0x01D7CD }, /* 1D7CA-1D7CD */ { 0x01D800, 0x01FFFD }, /* 1D800-1FFFD */ { 0x02A6D7, 0x02F7FF }, /* 2A6D7-2F7FF */ { 0x02FA1E, 0x02FFFD }, /* 2FA1E-2FFFD */ { 0x030000, 0x03FFFD }, /* 30000-3FFFD */ { 0x040000, 0x04FFFD }, /* 40000-4FFFD */ { 0x050000, 0x05FFFD }, /* 50000-5FFFD */ { 0x060000, 0x06FFFD }, /* 60000-6FFFD */ { 0x070000, 0x07FFFD }, /* 70000-7FFFD */ { 0x080000, 0x08FFFD }, /* 80000-8FFFD */ { 0x090000, 0x09FFFD }, /* 90000-9FFFD */ { 0x0A0000, 0x0AFFFD }, /* A0000-AFFFD */ { 0x0B0000, 0x0BFFFD }, /* B0000-BFFFD */ { 0x0C0000, 0x0CFFFD }, /* C0000-CFFFD */ { 0x0D0000, 0x0DFFFD }, /* D0000-DFFFD */ { 0x0E0000 }, /* E0000 */ { 0x0E0002, 0x0E001F }, /* E0002-E001F */ { 0x0E0080, 0x0EFFFD }, /* E0080-EFFFD */ { 0 }, }; /* * B.1 Commonly mapped to nothing * */ Stringprep_table_element stringprep_rfc3454_B_1[] = { { 0x0000AD }, /* 00AD; ; Map to nothing */ { 0x00034F }, /* 034F; ; Map to nothing */ { 0x001806 }, /* 1806; ; Map to nothing */ { 0x00180B }, /* 180B; ; Map to nothing */ { 0x00180C }, /* 180C; ; Map to nothing */ { 0x00180D }, /* 180D; ; Map to nothing */ { 0x00200B }, /* 200B; ; Map to nothing */ { 0x00200C }, /* 200C; ; Map to nothing */ { 0x00200D }, /* 200D; ; Map to nothing */ { 0x002060 }, /* 2060; ; Map to nothing */ { 0x00FE00 }, /* FE00; ; Map to nothing */ { 0x00FE01 }, /* FE01; ; Map to nothing */ { 0x00FE02 }, /* FE02; ; Map to nothing */ { 0x00FE03 }, /* FE03; ; Map to nothing */ { 0x00FE04 }, /* FE04; ; Map to nothing */ { 0x00FE05 }, /* FE05; ; Map to nothing */ { 0x00FE06 }, /* FE06; ; Map to nothing */ { 0x00FE07 }, /* FE07; ; Map to nothing */ { 0x00FE08 }, /* FE08; ; Map to nothing */ { 0x00FE09 }, /* FE09; ; Map to nothing */ { 0x00FE0A }, /* FE0A; ; Map to nothing */ { 0x00FE0B }, /* FE0B; ; Map to nothing */ { 0x00FE0C }, /* FE0C; ; Map to nothing */ { 0x00FE0D }, /* FE0D; ; Map to nothing */ { 0x00FE0E }, /* FE0E; ; Map to nothing */ { 0x00FE0F }, /* FE0F; ; Map to nothing */ { 0x00FEFF }, /* FEFF; ; Map to nothing */ { 0 }, }; /* * B.2 Mapping for case-folding used with NFKC * */ Stringprep_table_element stringprep_rfc3454_B_2[] = { { 0x000041, 0, { 0x000061 }}, /* 0041; 0061; Case map */ { 0x000042, 0, { 0x000062 }}, /* 0042; 0062; Case map */ { 0x000043, 0, { 0x000063 }}, /* 0043; 0063; Case map */ { 0x000044, 0, { 0x000064 }}, /* 0044; 0064; Case map */ { 0x000045, 0, { 0x000065 }}, /* 0045; 0065; Case map */ { 0x000046, 0, { 0x000066 }}, /* 0046; 0066; Case map */ { 0x000047, 0, { 0x000067 }}, /* 0047; 0067; Case map */ { 0x000048, 0, { 0x000068 }}, /* 0048; 0068; Case map */ { 0x000049, 0, { 0x000069 }}, /* 0049; 0069; Case map */ { 0x00004A, 0, { 0x00006A }}, /* 004A; 006A; Case map */ { 0x00004B, 0, { 0x00006B }}, /* 004B; 006B; Case map */ { 0x00004C, 0, { 0x00006C }}, /* 004C; 006C; Case map */ { 0x00004D, 0, { 0x00006D }}, /* 004D; 006D; Case map */ { 0x00004E, 0, { 0x00006E }}, /* 004E; 006E; Case map */ { 0x00004F, 0, { 0x00006F }}, /* 004F; 006F; Case map */ { 0x000050, 0, { 0x000070 }}, /* 0050; 0070; Case map */ { 0x000051, 0, { 0x000071 }}, /* 0051; 0071; Case map */ { 0x000052, 0, { 0x000072 }}, /* 0052; 0072; Case map */ { 0x000053, 0, { 0x000073 }}, /* 0053; 0073; Case map */ { 0x000054, 0, { 0x000074 }}, /* 0054; 0074; Case map */ { 0x000055, 0, { 0x000075 }}, /* 0055; 0075; Case map */ { 0x000056, 0, { 0x000076 }}, /* 0056; 0076; Case map */ { 0x000057, 0, { 0x000077 }}, /* 0057; 0077; Case map */ { 0x000058, 0, { 0x000078 }}, /* 0058; 0078; Case map */ { 0x000059, 0, { 0x000079 }}, /* 0059; 0079; Case map */ { 0x00005A, 0, { 0x00007A }}, /* 005A; 007A; Case map */ { 0x0000B5, 0, { 0x0003BC }}, /* 00B5; 03BC; Case map */ { 0x0000C0, 0, { 0x0000E0 }}, /* 00C0; 00E0; Case map */ { 0x0000C1, 0, { 0x0000E1 }}, /* 00C1; 00E1; Case map */ { 0x0000C2, 0, { 0x0000E2 }}, /* 00C2; 00E2; Case map */ { 0x0000C3, 0, { 0x0000E3 }}, /* 00C3; 00E3; Case map */ { 0x0000C4, 0, { 0x0000E4 }}, /* 00C4; 00E4; Case map */ { 0x0000C5, 0, { 0x0000E5 }}, /* 00C5; 00E5; Case map */ { 0x0000C6, 0, { 0x0000E6 }}, /* 00C6; 00E6; Case map */ { 0x0000C7, 0, { 0x0000E7 }}, /* 00C7; 00E7; Case map */ { 0x0000C8, 0, { 0x0000E8 }}, /* 00C8; 00E8; Case map */ { 0x0000C9, 0, { 0x0000E9 }}, /* 00C9; 00E9; Case map */ { 0x0000CA, 0, { 0x0000EA }}, /* 00CA; 00EA; Case map */ { 0x0000CB, 0, { 0x0000EB }}, /* 00CB; 00EB; Case map */ { 0x0000CC, 0, { 0x0000EC }}, /* 00CC; 00EC; Case map */ { 0x0000CD, 0, { 0x0000ED }}, /* 00CD; 00ED; Case map */ { 0x0000CE, 0, { 0x0000EE }}, /* 00CE; 00EE; Case map */ { 0x0000CF, 0, { 0x0000EF }}, /* 00CF; 00EF; Case map */ { 0x0000D0, 0, { 0x0000F0 }}, /* 00D0; 00F0; Case map */ { 0x0000D1, 0, { 0x0000F1 }}, /* 00D1; 00F1; Case map */ { 0x0000D2, 0, { 0x0000F2 }}, /* 00D2; 00F2; Case map */ { 0x0000D3, 0, { 0x0000F3 }}, /* 00D3; 00F3; Case map */ { 0x0000D4, 0, { 0x0000F4 }}, /* 00D4; 00F4; Case map */ { 0x0000D5, 0, { 0x0000F5 }}, /* 00D5; 00F5; Case map */ { 0x0000D6, 0, { 0x0000F6 }}, /* 00D6; 00F6; Case map */ { 0x0000D8, 0, { 0x0000F8 }}, /* 00D8; 00F8; Case map */ { 0x0000D9, 0, { 0x0000F9 }}, /* 00D9; 00F9; Case map */ { 0x0000DA, 0, { 0x0000FA }}, /* 00DA; 00FA; Case map */ { 0x0000DB, 0, { 0x0000FB }}, /* 00DB; 00FB; Case map */ { 0x0000DC, 0, { 0x0000FC }}, /* 00DC; 00FC; Case map */ { 0x0000DD, 0, { 0x0000FD }}, /* 00DD; 00FD; Case map */ { 0x0000DE, 0, { 0x0000FE }}, /* 00DE; 00FE; Case map */ { 0x0000DF, 0, { 0x000073, /* 00DF; 0073 0073; Case map */ 0x000073 }}, { 0x000100, 0, { 0x000101 }}, /* 0100; 0101; Case map */ { 0x000102, 0, { 0x000103 }}, /* 0102; 0103; Case map */ { 0x000104, 0, { 0x000105 }}, /* 0104; 0105; Case map */ { 0x000106, 0, { 0x000107 }}, /* 0106; 0107; Case map */ { 0x000108, 0, { 0x000109 }}, /* 0108; 0109; Case map */ { 0x00010A, 0, { 0x00010B }}, /* 010A; 010B; Case map */ { 0x00010C, 0, { 0x00010D }}, /* 010C; 010D; Case map */ { 0x00010E, 0, { 0x00010F }}, /* 010E; 010F; Case map */ { 0x000110, 0, { 0x000111 }}, /* 0110; 0111; Case map */ { 0x000112, 0, { 0x000113 }}, /* 0112; 0113; Case map */ { 0x000114, 0, { 0x000115 }}, /* 0114; 0115; Case map */ { 0x000116, 0, { 0x000117 }}, /* 0116; 0117; Case map */ { 0x000118, 0, { 0x000119 }}, /* 0118; 0119; Case map */ { 0x00011A, 0, { 0x00011B }}, /* 011A; 011B; Case map */ { 0x00011C, 0, { 0x00011D }}, /* 011C; 011D; Case map */ { 0x00011E, 0, { 0x00011F }}, /* 011E; 011F; Case map */ { 0x000120, 0, { 0x000121 }}, /* 0120; 0121; Case map */ { 0x000122, 0, { 0x000123 }}, /* 0122; 0123; Case map */ { 0x000124, 0, { 0x000125 }}, /* 0124; 0125; Case map */ { 0x000126, 0, { 0x000127 }}, /* 0126; 0127; Case map */ { 0x000128, 0, { 0x000129 }}, /* 0128; 0129; Case map */ { 0x00012A, 0, { 0x00012B }}, /* 012A; 012B; Case map */ { 0x00012C, 0, { 0x00012D }}, /* 012C; 012D; Case map */ { 0x00012E, 0, { 0x00012F }}, /* 012E; 012F; Case map */ { 0x000130, 0, { 0x000069, /* 0130; 0069 0307; Case map */ 0x000307 }}, { 0x000132, 0, { 0x000133 }}, /* 0132; 0133; Case map */ { 0x000134, 0, { 0x000135 }}, /* 0134; 0135; Case map */ { 0x000136, 0, { 0x000137 }}, /* 0136; 0137; Case map */ { 0x000139, 0, { 0x00013A }}, /* 0139; 013A; Case map */ { 0x00013B, 0, { 0x00013C }}, /* 013B; 013C; Case map */ { 0x00013D, 0, { 0x00013E }}, /* 013D; 013E; Case map */ { 0x00013F, 0, { 0x000140 }}, /* 013F; 0140; Case map */ { 0x000141, 0, { 0x000142 }}, /* 0141; 0142; Case map */ { 0x000143, 0, { 0x000144 }}, /* 0143; 0144; Case map */ { 0x000145, 0, { 0x000146 }}, /* 0145; 0146; Case map */ { 0x000147, 0, { 0x000148 }}, /* 0147; 0148; Case map */ { 0x000149, 0, { 0x0002BC, /* 0149; 02BC 006E; Case map */ 0x00006E }}, { 0x00014A, 0, { 0x00014B }}, /* 014A; 014B; Case map */ { 0x00014C, 0, { 0x00014D }}, /* 014C; 014D; Case map */ { 0x00014E, 0, { 0x00014F }}, /* 014E; 014F; Case map */ { 0x000150, 0, { 0x000151 }}, /* 0150; 0151; Case map */ { 0x000152, 0, { 0x000153 }}, /* 0152; 0153; Case map */ { 0x000154, 0, { 0x000155 }}, /* 0154; 0155; Case map */ { 0x000156, 0, { 0x000157 }}, /* 0156; 0157; Case map */ { 0x000158, 0, { 0x000159 }}, /* 0158; 0159; Case map */ { 0x00015A, 0, { 0x00015B }}, /* 015A; 015B; Case map */ { 0x00015C, 0, { 0x00015D }}, /* 015C; 015D; Case map */ { 0x00015E, 0, { 0x00015F }}, /* 015E; 015F; Case map */ { 0x000160, 0, { 0x000161 }}, /* 0160; 0161; Case map */ { 0x000162, 0, { 0x000163 }}, /* 0162; 0163; Case map */ { 0x000164, 0, { 0x000165 }}, /* 0164; 0165; Case map */ { 0x000166, 0, { 0x000167 }}, /* 0166; 0167; Case map */ { 0x000168, 0, { 0x000169 }}, /* 0168; 0169; Case map */ { 0x00016A, 0, { 0x00016B }}, /* 016A; 016B; Case map */ { 0x00016C, 0, { 0x00016D }}, /* 016C; 016D; Case map */ { 0x00016E, 0, { 0x00016F }}, /* 016E; 016F; Case map */ { 0x000170, 0, { 0x000171 }}, /* 0170; 0171; Case map */ { 0x000172, 0, { 0x000173 }}, /* 0172; 0173; Case map */ { 0x000174, 0, { 0x000175 }}, /* 0174; 0175; Case map */ { 0x000176, 0, { 0x000177 }}, /* 0176; 0177; Case map */ { 0x000178, 0, { 0x0000FF }}, /* 0178; 00FF; Case map */ { 0x000179, 0, { 0x00017A }}, /* 0179; 017A; Case map */ { 0x00017B, 0, { 0x00017C }}, /* 017B; 017C; Case map */ { 0x00017D, 0, { 0x00017E }}, /* 017D; 017E; Case map */ { 0x00017F, 0, { 0x000073 }}, /* 017F; 0073; Case map */ { 0x000181, 0, { 0x000253 }}, /* 0181; 0253; Case map */ { 0x000182, 0, { 0x000183 }}, /* 0182; 0183; Case map */ { 0x000184, 0, { 0x000185 }}, /* 0184; 0185; Case map */ { 0x000186, 0, { 0x000254 }}, /* 0186; 0254; Case map */ { 0x000187, 0, { 0x000188 }}, /* 0187; 0188; Case map */ { 0x000189, 0, { 0x000256 }}, /* 0189; 0256; Case map */ { 0x00018A, 0, { 0x000257 }}, /* 018A; 0257; Case map */ { 0x00018B, 0, { 0x00018C }}, /* 018B; 018C; Case map */ { 0x00018E, 0, { 0x0001DD }}, /* 018E; 01DD; Case map */ { 0x00018F, 0, { 0x000259 }}, /* 018F; 0259; Case map */ { 0x000190, 0, { 0x00025B }}, /* 0190; 025B; Case map */ { 0x000191, 0, { 0x000192 }}, /* 0191; 0192; Case map */ { 0x000193, 0, { 0x000260 }}, /* 0193; 0260; Case map */ { 0x000194, 0, { 0x000263 }}, /* 0194; 0263; Case map */ { 0x000196, 0, { 0x000269 }}, /* 0196; 0269; Case map */ { 0x000197, 0, { 0x000268 }}, /* 0197; 0268; Case map */ { 0x000198, 0, { 0x000199 }}, /* 0198; 0199; Case map */ { 0x00019C, 0, { 0x00026F }}, /* 019C; 026F; Case map */ { 0x00019D, 0, { 0x000272 }}, /* 019D; 0272; Case map */ { 0x00019F, 0, { 0x000275 }}, /* 019F; 0275; Case map */ { 0x0001A0, 0, { 0x0001A1 }}, /* 01A0; 01A1; Case map */ { 0x0001A2, 0, { 0x0001A3 }}, /* 01A2; 01A3; Case map */ { 0x0001A4, 0, { 0x0001A5 }}, /* 01A4; 01A5; Case map */ { 0x0001A6, 0, { 0x000280 }}, /* 01A6; 0280; Case map */ { 0x0001A7, 0, { 0x0001A8 }}, /* 01A7; 01A8; Case map */ { 0x0001A9, 0, { 0x000283 }}, /* 01A9; 0283; Case map */ { 0x0001AC, 0, { 0x0001AD }}, /* 01AC; 01AD; Case map */ { 0x0001AE, 0, { 0x000288 }}, /* 01AE; 0288; Case map */ { 0x0001AF, 0, { 0x0001B0 }}, /* 01AF; 01B0; Case map */ { 0x0001B1, 0, { 0x00028A }}, /* 01B1; 028A; Case map */ { 0x0001B2, 0, { 0x00028B }}, /* 01B2; 028B; Case map */ { 0x0001B3, 0, { 0x0001B4 }}, /* 01B3; 01B4; Case map */ { 0x0001B5, 0, { 0x0001B6 }}, /* 01B5; 01B6; Case map */ { 0x0001B7, 0, { 0x000292 }}, /* 01B7; 0292; Case map */ { 0x0001B8, 0, { 0x0001B9 }}, /* 01B8; 01B9; Case map */ { 0x0001BC, 0, { 0x0001BD }}, /* 01BC; 01BD; Case map */ { 0x0001C4, 0, { 0x0001C6 }}, /* 01C4; 01C6; Case map */ { 0x0001C5, 0, { 0x0001C6 }}, /* 01C5; 01C6; Case map */ { 0x0001C7, 0, { 0x0001C9 }}, /* 01C7; 01C9; Case map */ { 0x0001C8, 0, { 0x0001C9 }}, /* 01C8; 01C9; Case map */ { 0x0001CA, 0, { 0x0001CC }}, /* 01CA; 01CC; Case map */ { 0x0001CB, 0, { 0x0001CC }}, /* 01CB; 01CC; Case map */ { 0x0001CD, 0, { 0x0001CE }}, /* 01CD; 01CE; Case map */ { 0x0001CF, 0, { 0x0001D0 }}, /* 01CF; 01D0; Case map */ { 0x0001D1, 0, { 0x0001D2 }}, /* 01D1; 01D2; Case map */ { 0x0001D3, 0, { 0x0001D4 }}, /* 01D3; 01D4; Case map */ { 0x0001D5, 0, { 0x0001D6 }}, /* 01D5; 01D6; Case map */ { 0x0001D7, 0, { 0x0001D8 }}, /* 01D7; 01D8; Case map */ { 0x0001D9, 0, { 0x0001DA }}, /* 01D9; 01DA; Case map */ { 0x0001DB, 0, { 0x0001DC }}, /* 01DB; 01DC; Case map */ { 0x0001DE, 0, { 0x0001DF }}, /* 01DE; 01DF; Case map */ { 0x0001E0, 0, { 0x0001E1 }}, /* 01E0; 01E1; Case map */ { 0x0001E2, 0, { 0x0001E3 }}, /* 01E2; 01E3; Case map */ { 0x0001E4, 0, { 0x0001E5 }}, /* 01E4; 01E5; Case map */ { 0x0001E6, 0, { 0x0001E7 }}, /* 01E6; 01E7; Case map */ { 0x0001E8, 0, { 0x0001E9 }}, /* 01E8; 01E9; Case map */ { 0x0001EA, 0, { 0x0001EB }}, /* 01EA; 01EB; Case map */ { 0x0001EC, 0, { 0x0001ED }}, /* 01EC; 01ED; Case map */ { 0x0001EE, 0, { 0x0001EF }}, /* 01EE; 01EF; Case map */ { 0x0001F0, 0, { 0x00006A, /* 01F0; 006A 030C; Case map */ 0x00030C }}, { 0x0001F1, 0, { 0x0001F3 }}, /* 01F1; 01F3; Case map */ { 0x0001F2, 0, { 0x0001F3 }}, /* 01F2; 01F3; Case map */ { 0x0001F4, 0, { 0x0001F5 }}, /* 01F4; 01F5; Case map */ { 0x0001F6, 0, { 0x000195 }}, /* 01F6; 0195; Case map */ { 0x0001F7, 0, { 0x0001BF }}, /* 01F7; 01BF; Case map */ { 0x0001F8, 0, { 0x0001F9 }}, /* 01F8; 01F9; Case map */ { 0x0001FA, 0, { 0x0001FB }}, /* 01FA; 01FB; Case map */ { 0x0001FC, 0, { 0x0001FD }}, /* 01FC; 01FD; Case map */ { 0x0001FE, 0, { 0x0001FF }}, /* 01FE; 01FF; Case map */ { 0x000200, 0, { 0x000201 }}, /* 0200; 0201; Case map */ { 0x000202, 0, { 0x000203 }}, /* 0202; 0203; Case map */ { 0x000204, 0, { 0x000205 }}, /* 0204; 0205; Case map */ { 0x000206, 0, { 0x000207 }}, /* 0206; 0207; Case map */ { 0x000208, 0, { 0x000209 }}, /* 0208; 0209; Case map */ { 0x00020A, 0, { 0x00020B }}, /* 020A; 020B; Case map */ { 0x00020C, 0, { 0x00020D }}, /* 020C; 020D; Case map */ { 0x00020E, 0, { 0x00020F }}, /* 020E; 020F; Case map */ { 0x000210, 0, { 0x000211 }}, /* 0210; 0211; Case map */ { 0x000212, 0, { 0x000213 }}, /* 0212; 0213; Case map */ { 0x000214, 0, { 0x000215 }}, /* 0214; 0215; Case map */ { 0x000216, 0, { 0x000217 }}, /* 0216; 0217; Case map */ { 0x000218, 0, { 0x000219 }}, /* 0218; 0219; Case map */ { 0x00021A, 0, { 0x00021B }}, /* 021A; 021B; Case map */ { 0x00021C, 0, { 0x00021D }}, /* 021C; 021D; Case map */ { 0x00021E, 0, { 0x00021F }}, /* 021E; 021F; Case map */ { 0x000220, 0, { 0x00019E }}, /* 0220; 019E; Case map */ { 0x000222, 0, { 0x000223 }}, /* 0222; 0223; Case map */ { 0x000224, 0, { 0x000225 }}, /* 0224; 0225; Case map */ { 0x000226, 0, { 0x000227 }}, /* 0226; 0227; Case map */ { 0x000228, 0, { 0x000229 }}, /* 0228; 0229; Case map */ { 0x00022A, 0, { 0x00022B }}, /* 022A; 022B; Case map */ { 0x00022C, 0, { 0x00022D }}, /* 022C; 022D; Case map */ { 0x00022E, 0, { 0x00022F }}, /* 022E; 022F; Case map */ { 0x000230, 0, { 0x000231 }}, /* 0230; 0231; Case map */ { 0x000232, 0, { 0x000233 }}, /* 0232; 0233; Case map */ { 0x000345, 0, { 0x0003B9 }}, /* 0345; 03B9; Case map */ { 0x00037A, 0, { 0x000020, /* 037A; 0020 03B9; Additional folding */ 0x0003B9 }}, { 0x000386, 0, { 0x0003AC }}, /* 0386; 03AC; Case map */ { 0x000388, 0, { 0x0003AD }}, /* 0388; 03AD; Case map */ { 0x000389, 0, { 0x0003AE }}, /* 0389; 03AE; Case map */ { 0x00038A, 0, { 0x0003AF }}, /* 038A; 03AF; Case map */ { 0x00038C, 0, { 0x0003CC }}, /* 038C; 03CC; Case map */ { 0x00038E, 0, { 0x0003CD }}, /* 038E; 03CD; Case map */ { 0x00038F, 0, { 0x0003CE }}, /* 038F; 03CE; Case map */ { 0x000390, 0, { 0x0003B9, /* 0390; 03B9 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x000391, 0, { 0x0003B1 }}, /* 0391; 03B1; Case map */ { 0x000392, 0, { 0x0003B2 }}, /* 0392; 03B2; Case map */ { 0x000393, 0, { 0x0003B3 }}, /* 0393; 03B3; Case map */ { 0x000394, 0, { 0x0003B4 }}, /* 0394; 03B4; Case map */ { 0x000395, 0, { 0x0003B5 }}, /* 0395; 03B5; Case map */ { 0x000396, 0, { 0x0003B6 }}, /* 0396; 03B6; Case map */ { 0x000397, 0, { 0x0003B7 }}, /* 0397; 03B7; Case map */ { 0x000398, 0, { 0x0003B8 }}, /* 0398; 03B8; Case map */ { 0x000399, 0, { 0x0003B9 }}, /* 0399; 03B9; Case map */ { 0x00039A, 0, { 0x0003BA }}, /* 039A; 03BA; Case map */ { 0x00039B, 0, { 0x0003BB }}, /* 039B; 03BB; Case map */ { 0x00039C, 0, { 0x0003BC }}, /* 039C; 03BC; Case map */ { 0x00039D, 0, { 0x0003BD }}, /* 039D; 03BD; Case map */ { 0x00039E, 0, { 0x0003BE }}, /* 039E; 03BE; Case map */ { 0x00039F, 0, { 0x0003BF }}, /* 039F; 03BF; Case map */ { 0x0003A0, 0, { 0x0003C0 }}, /* 03A0; 03C0; Case map */ { 0x0003A1, 0, { 0x0003C1 }}, /* 03A1; 03C1; Case map */ { 0x0003A3, 0, { 0x0003C3 }}, /* 03A3; 03C3; Case map */ { 0x0003A4, 0, { 0x0003C4 }}, /* 03A4; 03C4; Case map */ { 0x0003A5, 0, { 0x0003C5 }}, /* 03A5; 03C5; Case map */ { 0x0003A6, 0, { 0x0003C6 }}, /* 03A6; 03C6; Case map */ { 0x0003A7, 0, { 0x0003C7 }}, /* 03A7; 03C7; Case map */ { 0x0003A8, 0, { 0x0003C8 }}, /* 03A8; 03C8; Case map */ { 0x0003A9, 0, { 0x0003C9 }}, /* 03A9; 03C9; Case map */ { 0x0003AA, 0, { 0x0003CA }}, /* 03AA; 03CA; Case map */ { 0x0003AB, 0, { 0x0003CB }}, /* 03AB; 03CB; Case map */ { 0x0003B0, 0, { 0x0003C5, /* 03B0; 03C5 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x0003C2, 0, { 0x0003C3 }}, /* 03C2; 03C3; Case map */ { 0x0003D0, 0, { 0x0003B2 }}, /* 03D0; 03B2; Case map */ { 0x0003D1, 0, { 0x0003B8 }}, /* 03D1; 03B8; Case map */ { 0x0003D2, 0, { 0x0003C5 }}, /* 03D2; 03C5; Additional folding */ { 0x0003D3, 0, { 0x0003CD }}, /* 03D3; 03CD; Additional folding */ { 0x0003D4, 0, { 0x0003CB }}, /* 03D4; 03CB; Additional folding */ { 0x0003D5, 0, { 0x0003C6 }}, /* 03D5; 03C6; Case map */ { 0x0003D6, 0, { 0x0003C0 }}, /* 03D6; 03C0; Case map */ { 0x0003D8, 0, { 0x0003D9 }}, /* 03D8; 03D9; Case map */ { 0x0003DA, 0, { 0x0003DB }}, /* 03DA; 03DB; Case map */ { 0x0003DC, 0, { 0x0003DD }}, /* 03DC; 03DD; Case map */ { 0x0003DE, 0, { 0x0003DF }}, /* 03DE; 03DF; Case map */ { 0x0003E0, 0, { 0x0003E1 }}, /* 03E0; 03E1; Case map */ { 0x0003E2, 0, { 0x0003E3 }}, /* 03E2; 03E3; Case map */ { 0x0003E4, 0, { 0x0003E5 }}, /* 03E4; 03E5; Case map */ { 0x0003E6, 0, { 0x0003E7 }}, /* 03E6; 03E7; Case map */ { 0x0003E8, 0, { 0x0003E9 }}, /* 03E8; 03E9; Case map */ { 0x0003EA, 0, { 0x0003EB }}, /* 03EA; 03EB; Case map */ { 0x0003EC, 0, { 0x0003ED }}, /* 03EC; 03ED; Case map */ { 0x0003EE, 0, { 0x0003EF }}, /* 03EE; 03EF; Case map */ { 0x0003F0, 0, { 0x0003BA }}, /* 03F0; 03BA; Case map */ { 0x0003F1, 0, { 0x0003C1 }}, /* 03F1; 03C1; Case map */ { 0x0003F2, 0, { 0x0003C3 }}, /* 03F2; 03C3; Case map */ { 0x0003F4, 0, { 0x0003B8 }}, /* 03F4; 03B8; Case map */ { 0x0003F5, 0, { 0x0003B5 }}, /* 03F5; 03B5; Case map */ { 0x000400, 0, { 0x000450 }}, /* 0400; 0450; Case map */ { 0x000401, 0, { 0x000451 }}, /* 0401; 0451; Case map */ { 0x000402, 0, { 0x000452 }}, /* 0402; 0452; Case map */ { 0x000403, 0, { 0x000453 }}, /* 0403; 0453; Case map */ { 0x000404, 0, { 0x000454 }}, /* 0404; 0454; Case map */ { 0x000405, 0, { 0x000455 }}, /* 0405; 0455; Case map */ { 0x000406, 0, { 0x000456 }}, /* 0406; 0456; Case map */ { 0x000407, 0, { 0x000457 }}, /* 0407; 0457; Case map */ { 0x000408, 0, { 0x000458 }}, /* 0408; 0458; Case map */ { 0x000409, 0, { 0x000459 }}, /* 0409; 0459; Case map */ { 0x00040A, 0, { 0x00045A }}, /* 040A; 045A; Case map */ { 0x00040B, 0, { 0x00045B }}, /* 040B; 045B; Case map */ { 0x00040C, 0, { 0x00045C }}, /* 040C; 045C; Case map */ { 0x00040D, 0, { 0x00045D }}, /* 040D; 045D; Case map */ { 0x00040E, 0, { 0x00045E }}, /* 040E; 045E; Case map */ { 0x00040F, 0, { 0x00045F }}, /* 040F; 045F; Case map */ { 0x000410, 0, { 0x000430 }}, /* 0410; 0430; Case map */ { 0x000411, 0, { 0x000431 }}, /* 0411; 0431; Case map */ { 0x000412, 0, { 0x000432 }}, /* 0412; 0432; Case map */ { 0x000413, 0, { 0x000433 }}, /* 0413; 0433; Case map */ { 0x000414, 0, { 0x000434 }}, /* 0414; 0434; Case map */ { 0x000415, 0, { 0x000435 }}, /* 0415; 0435; Case map */ { 0x000416, 0, { 0x000436 }}, /* 0416; 0436; Case map */ { 0x000417, 0, { 0x000437 }}, /* 0417; 0437; Case map */ { 0x000418, 0, { 0x000438 }}, /* 0418; 0438; Case map */ { 0x000419, 0, { 0x000439 }}, /* 0419; 0439; Case map */ { 0x00041A, 0, { 0x00043A }}, /* 041A; 043A; Case map */ { 0x00041B, 0, { 0x00043B }}, /* 041B; 043B; Case map */ { 0x00041C, 0, { 0x00043C }}, /* 041C; 043C; Case map */ { 0x00041D, 0, { 0x00043D }}, /* 041D; 043D; Case map */ { 0x00041E, 0, { 0x00043E }}, /* 041E; 043E; Case map */ { 0x00041F, 0, { 0x00043F }}, /* 041F; 043F; Case map */ { 0x000420, 0, { 0x000440 }}, /* 0420; 0440; Case map */ { 0x000421, 0, { 0x000441 }}, /* 0421; 0441; Case map */ { 0x000422, 0, { 0x000442 }}, /* 0422; 0442; Case map */ { 0x000423, 0, { 0x000443 }}, /* 0423; 0443; Case map */ { 0x000424, 0, { 0x000444 }}, /* 0424; 0444; Case map */ { 0x000425, 0, { 0x000445 }}, /* 0425; 0445; Case map */ { 0x000426, 0, { 0x000446 }}, /* 0426; 0446; Case map */ { 0x000427, 0, { 0x000447 }}, /* 0427; 0447; Case map */ { 0x000428, 0, { 0x000448 }}, /* 0428; 0448; Case map */ { 0x000429, 0, { 0x000449 }}, /* 0429; 0449; Case map */ { 0x00042A, 0, { 0x00044A }}, /* 042A; 044A; Case map */ { 0x00042B, 0, { 0x00044B }}, /* 042B; 044B; Case map */ { 0x00042C, 0, { 0x00044C }}, /* 042C; 044C; Case map */ { 0x00042D, 0, { 0x00044D }}, /* 042D; 044D; Case map */ { 0x00042E, 0, { 0x00044E }}, /* 042E; 044E; Case map */ { 0x00042F, 0, { 0x00044F }}, /* 042F; 044F; Case map */ { 0x000460, 0, { 0x000461 }}, /* 0460; 0461; Case map */ { 0x000462, 0, { 0x000463 }}, /* 0462; 0463; Case map */ { 0x000464, 0, { 0x000465 }}, /* 0464; 0465; Case map */ { 0x000466, 0, { 0x000467 }}, /* 0466; 0467; Case map */ { 0x000468, 0, { 0x000469 }}, /* 0468; 0469; Case map */ { 0x00046A, 0, { 0x00046B }}, /* 046A; 046B; Case map */ { 0x00046C, 0, { 0x00046D }}, /* 046C; 046D; Case map */ { 0x00046E, 0, { 0x00046F }}, /* 046E; 046F; Case map */ { 0x000470, 0, { 0x000471 }}, /* 0470; 0471; Case map */ { 0x000472, 0, { 0x000473 }}, /* 0472; 0473; Case map */ { 0x000474, 0, { 0x000475 }}, /* 0474; 0475; Case map */ { 0x000476, 0, { 0x000477 }}, /* 0476; 0477; Case map */ { 0x000478, 0, { 0x000479 }}, /* 0478; 0479; Case map */ { 0x00047A, 0, { 0x00047B }}, /* 047A; 047B; Case map */ { 0x00047C, 0, { 0x00047D }}, /* 047C; 047D; Case map */ { 0x00047E, 0, { 0x00047F }}, /* 047E; 047F; Case map */ { 0x000480, 0, { 0x000481 }}, /* 0480; 0481; Case map */ { 0x00048A, 0, { 0x00048B }}, /* 048A; 048B; Case map */ { 0x00048C, 0, { 0x00048D }}, /* 048C; 048D; Case map */ { 0x00048E, 0, { 0x00048F }}, /* 048E; 048F; Case map */ { 0x000490, 0, { 0x000491 }}, /* 0490; 0491; Case map */ { 0x000492, 0, { 0x000493 }}, /* 0492; 0493; Case map */ { 0x000494, 0, { 0x000495 }}, /* 0494; 0495; Case map */ { 0x000496, 0, { 0x000497 }}, /* 0496; 0497; Case map */ { 0x000498, 0, { 0x000499 }}, /* 0498; 0499; Case map */ { 0x00049A, 0, { 0x00049B }}, /* 049A; 049B; Case map */ { 0x00049C, 0, { 0x00049D }}, /* 049C; 049D; Case map */ { 0x00049E, 0, { 0x00049F }}, /* 049E; 049F; Case map */ { 0x0004A0, 0, { 0x0004A1 }}, /* 04A0; 04A1; Case map */ { 0x0004A2, 0, { 0x0004A3 }}, /* 04A2; 04A3; Case map */ { 0x0004A4, 0, { 0x0004A5 }}, /* 04A4; 04A5; Case map */ { 0x0004A6, 0, { 0x0004A7 }}, /* 04A6; 04A7; Case map */ { 0x0004A8, 0, { 0x0004A9 }}, /* 04A8; 04A9; Case map */ { 0x0004AA, 0, { 0x0004AB }}, /* 04AA; 04AB; Case map */ { 0x0004AC, 0, { 0x0004AD }}, /* 04AC; 04AD; Case map */ { 0x0004AE, 0, { 0x0004AF }}, /* 04AE; 04AF; Case map */ { 0x0004B0, 0, { 0x0004B1 }}, /* 04B0; 04B1; Case map */ { 0x0004B2, 0, { 0x0004B3 }}, /* 04B2; 04B3; Case map */ { 0x0004B4, 0, { 0x0004B5 }}, /* 04B4; 04B5; Case map */ { 0x0004B6, 0, { 0x0004B7 }}, /* 04B6; 04B7; Case map */ { 0x0004B8, 0, { 0x0004B9 }}, /* 04B8; 04B9; Case map */ { 0x0004BA, 0, { 0x0004BB }}, /* 04BA; 04BB; Case map */ { 0x0004BC, 0, { 0x0004BD }}, /* 04BC; 04BD; Case map */ { 0x0004BE, 0, { 0x0004BF }}, /* 04BE; 04BF; Case map */ { 0x0004C1, 0, { 0x0004C2 }}, /* 04C1; 04C2; Case map */ { 0x0004C3, 0, { 0x0004C4 }}, /* 04C3; 04C4; Case map */ { 0x0004C5, 0, { 0x0004C6 }}, /* 04C5; 04C6; Case map */ { 0x0004C7, 0, { 0x0004C8 }}, /* 04C7; 04C8; Case map */ { 0x0004C9, 0, { 0x0004CA }}, /* 04C9; 04CA; Case map */ { 0x0004CB, 0, { 0x0004CC }}, /* 04CB; 04CC; Case map */ { 0x0004CD, 0, { 0x0004CE }}, /* 04CD; 04CE; Case map */ { 0x0004D0, 0, { 0x0004D1 }}, /* 04D0; 04D1; Case map */ { 0x0004D2, 0, { 0x0004D3 }}, /* 04D2; 04D3; Case map */ { 0x0004D4, 0, { 0x0004D5 }}, /* 04D4; 04D5; Case map */ { 0x0004D6, 0, { 0x0004D7 }}, /* 04D6; 04D7; Case map */ { 0x0004D8, 0, { 0x0004D9 }}, /* 04D8; 04D9; Case map */ { 0x0004DA, 0, { 0x0004DB }}, /* 04DA; 04DB; Case map */ { 0x0004DC, 0, { 0x0004DD }}, /* 04DC; 04DD; Case map */ { 0x0004DE, 0, { 0x0004DF }}, /* 04DE; 04DF; Case map */ { 0x0004E0, 0, { 0x0004E1 }}, /* 04E0; 04E1; Case map */ { 0x0004E2, 0, { 0x0004E3 }}, /* 04E2; 04E3; Case map */ { 0x0004E4, 0, { 0x0004E5 }}, /* 04E4; 04E5; Case map */ { 0x0004E6, 0, { 0x0004E7 }}, /* 04E6; 04E7; Case map */ { 0x0004E8, 0, { 0x0004E9 }}, /* 04E8; 04E9; Case map */ { 0x0004EA, 0, { 0x0004EB }}, /* 04EA; 04EB; Case map */ { 0x0004EC, 0, { 0x0004ED }}, /* 04EC; 04ED; Case map */ { 0x0004EE, 0, { 0x0004EF }}, /* 04EE; 04EF; Case map */ { 0x0004F0, 0, { 0x0004F1 }}, /* 04F0; 04F1; Case map */ { 0x0004F2, 0, { 0x0004F3 }}, /* 04F2; 04F3; Case map */ { 0x0004F4, 0, { 0x0004F5 }}, /* 04F4; 04F5; Case map */ { 0x0004F8, 0, { 0x0004F9 }}, /* 04F8; 04F9; Case map */ { 0x000500, 0, { 0x000501 }}, /* 0500; 0501; Case map */ { 0x000502, 0, { 0x000503 }}, /* 0502; 0503; Case map */ { 0x000504, 0, { 0x000505 }}, /* 0504; 0505; Case map */ { 0x000506, 0, { 0x000507 }}, /* 0506; 0507; Case map */ { 0x000508, 0, { 0x000509 }}, /* 0508; 0509; Case map */ { 0x00050A, 0, { 0x00050B }}, /* 050A; 050B; Case map */ { 0x00050C, 0, { 0x00050D }}, /* 050C; 050D; Case map */ { 0x00050E, 0, { 0x00050F }}, /* 050E; 050F; Case map */ { 0x000531, 0, { 0x000561 }}, /* 0531; 0561; Case map */ { 0x000532, 0, { 0x000562 }}, /* 0532; 0562; Case map */ { 0x000533, 0, { 0x000563 }}, /* 0533; 0563; Case map */ { 0x000534, 0, { 0x000564 }}, /* 0534; 0564; Case map */ { 0x000535, 0, { 0x000565 }}, /* 0535; 0565; Case map */ { 0x000536, 0, { 0x000566 }}, /* 0536; 0566; Case map */ { 0x000537, 0, { 0x000567 }}, /* 0537; 0567; Case map */ { 0x000538, 0, { 0x000568 }}, /* 0538; 0568; Case map */ { 0x000539, 0, { 0x000569 }}, /* 0539; 0569; Case map */ { 0x00053A, 0, { 0x00056A }}, /* 053A; 056A; Case map */ { 0x00053B, 0, { 0x00056B }}, /* 053B; 056B; Case map */ { 0x00053C, 0, { 0x00056C }}, /* 053C; 056C; Case map */ { 0x00053D, 0, { 0x00056D }}, /* 053D; 056D; Case map */ { 0x00053E, 0, { 0x00056E }}, /* 053E; 056E; Case map */ { 0x00053F, 0, { 0x00056F }}, /* 053F; 056F; Case map */ { 0x000540, 0, { 0x000570 }}, /* 0540; 0570; Case map */ { 0x000541, 0, { 0x000571 }}, /* 0541; 0571; Case map */ { 0x000542, 0, { 0x000572 }}, /* 0542; 0572; Case map */ { 0x000543, 0, { 0x000573 }}, /* 0543; 0573; Case map */ { 0x000544, 0, { 0x000574 }}, /* 0544; 0574; Case map */ { 0x000545, 0, { 0x000575 }}, /* 0545; 0575; Case map */ { 0x000546, 0, { 0x000576 }}, /* 0546; 0576; Case map */ { 0x000547, 0, { 0x000577 }}, /* 0547; 0577; Case map */ { 0x000548, 0, { 0x000578 }}, /* 0548; 0578; Case map */ { 0x000549, 0, { 0x000579 }}, /* 0549; 0579; Case map */ { 0x00054A, 0, { 0x00057A }}, /* 054A; 057A; Case map */ { 0x00054B, 0, { 0x00057B }}, /* 054B; 057B; Case map */ { 0x00054C, 0, { 0x00057C }}, /* 054C; 057C; Case map */ { 0x00054D, 0, { 0x00057D }}, /* 054D; 057D; Case map */ { 0x00054E, 0, { 0x00057E }}, /* 054E; 057E; Case map */ { 0x00054F, 0, { 0x00057F }}, /* 054F; 057F; Case map */ { 0x000550, 0, { 0x000580 }}, /* 0550; 0580; Case map */ { 0x000551, 0, { 0x000581 }}, /* 0551; 0581; Case map */ { 0x000552, 0, { 0x000582 }}, /* 0552; 0582; Case map */ { 0x000553, 0, { 0x000583 }}, /* 0553; 0583; Case map */ { 0x000554, 0, { 0x000584 }}, /* 0554; 0584; Case map */ { 0x000555, 0, { 0x000585 }}, /* 0555; 0585; Case map */ { 0x000556, 0, { 0x000586 }}, /* 0556; 0586; Case map */ { 0x000587, 0, { 0x000565, /* 0587; 0565 0582; Case map */ 0x000582 }}, { 0x001E00, 0, { 0x001E01 }}, /* 1E00; 1E01; Case map */ { 0x001E02, 0, { 0x001E03 }}, /* 1E02; 1E03; Case map */ { 0x001E04, 0, { 0x001E05 }}, /* 1E04; 1E05; Case map */ { 0x001E06, 0, { 0x001E07 }}, /* 1E06; 1E07; Case map */ { 0x001E08, 0, { 0x001E09 }}, /* 1E08; 1E09; Case map */ { 0x001E0A, 0, { 0x001E0B }}, /* 1E0A; 1E0B; Case map */ { 0x001E0C, 0, { 0x001E0D }}, /* 1E0C; 1E0D; Case map */ { 0x001E0E, 0, { 0x001E0F }}, /* 1E0E; 1E0F; Case map */ { 0x001E10, 0, { 0x001E11 }}, /* 1E10; 1E11; Case map */ { 0x001E12, 0, { 0x001E13 }}, /* 1E12; 1E13; Case map */ { 0x001E14, 0, { 0x001E15 }}, /* 1E14; 1E15; Case map */ { 0x001E16, 0, { 0x001E17 }}, /* 1E16; 1E17; Case map */ { 0x001E18, 0, { 0x001E19 }}, /* 1E18; 1E19; Case map */ { 0x001E1A, 0, { 0x001E1B }}, /* 1E1A; 1E1B; Case map */ { 0x001E1C, 0, { 0x001E1D }}, /* 1E1C; 1E1D; Case map */ { 0x001E1E, 0, { 0x001E1F }}, /* 1E1E; 1E1F; Case map */ { 0x001E20, 0, { 0x001E21 }}, /* 1E20; 1E21; Case map */ { 0x001E22, 0, { 0x001E23 }}, /* 1E22; 1E23; Case map */ { 0x001E24, 0, { 0x001E25 }}, /* 1E24; 1E25; Case map */ { 0x001E26, 0, { 0x001E27 }}, /* 1E26; 1E27; Case map */ { 0x001E28, 0, { 0x001E29 }}, /* 1E28; 1E29; Case map */ { 0x001E2A, 0, { 0x001E2B }}, /* 1E2A; 1E2B; Case map */ { 0x001E2C, 0, { 0x001E2D }}, /* 1E2C; 1E2D; Case map */ { 0x001E2E, 0, { 0x001E2F }}, /* 1E2E; 1E2F; Case map */ { 0x001E30, 0, { 0x001E31 }}, /* 1E30; 1E31; Case map */ { 0x001E32, 0, { 0x001E33 }}, /* 1E32; 1E33; Case map */ { 0x001E34, 0, { 0x001E35 }}, /* 1E34; 1E35; Case map */ { 0x001E36, 0, { 0x001E37 }}, /* 1E36; 1E37; Case map */ { 0x001E38, 0, { 0x001E39 }}, /* 1E38; 1E39; Case map */ { 0x001E3A, 0, { 0x001E3B }}, /* 1E3A; 1E3B; Case map */ { 0x001E3C, 0, { 0x001E3D }}, /* 1E3C; 1E3D; Case map */ { 0x001E3E, 0, { 0x001E3F }}, /* 1E3E; 1E3F; Case map */ { 0x001E40, 0, { 0x001E41 }}, /* 1E40; 1E41; Case map */ { 0x001E42, 0, { 0x001E43 }}, /* 1E42; 1E43; Case map */ { 0x001E44, 0, { 0x001E45 }}, /* 1E44; 1E45; Case map */ { 0x001E46, 0, { 0x001E47 }}, /* 1E46; 1E47; Case map */ { 0x001E48, 0, { 0x001E49 }}, /* 1E48; 1E49; Case map */ { 0x001E4A, 0, { 0x001E4B }}, /* 1E4A; 1E4B; Case map */ { 0x001E4C, 0, { 0x001E4D }}, /* 1E4C; 1E4D; Case map */ { 0x001E4E, 0, { 0x001E4F }}, /* 1E4E; 1E4F; Case map */ { 0x001E50, 0, { 0x001E51 }}, /* 1E50; 1E51; Case map */ { 0x001E52, 0, { 0x001E53 }}, /* 1E52; 1E53; Case map */ { 0x001E54, 0, { 0x001E55 }}, /* 1E54; 1E55; Case map */ { 0x001E56, 0, { 0x001E57 }}, /* 1E56; 1E57; Case map */ { 0x001E58, 0, { 0x001E59 }}, /* 1E58; 1E59; Case map */ { 0x001E5A, 0, { 0x001E5B }}, /* 1E5A; 1E5B; Case map */ { 0x001E5C, 0, { 0x001E5D }}, /* 1E5C; 1E5D; Case map */ { 0x001E5E, 0, { 0x001E5F }}, /* 1E5E; 1E5F; Case map */ { 0x001E60, 0, { 0x001E61 }}, /* 1E60; 1E61; Case map */ { 0x001E62, 0, { 0x001E63 }}, /* 1E62; 1E63; Case map */ { 0x001E64, 0, { 0x001E65 }}, /* 1E64; 1E65; Case map */ { 0x001E66, 0, { 0x001E67 }}, /* 1E66; 1E67; Case map */ { 0x001E68, 0, { 0x001E69 }}, /* 1E68; 1E69; Case map */ { 0x001E6A, 0, { 0x001E6B }}, /* 1E6A; 1E6B; Case map */ { 0x001E6C, 0, { 0x001E6D }}, /* 1E6C; 1E6D; Case map */ { 0x001E6E, 0, { 0x001E6F }}, /* 1E6E; 1E6F; Case map */ { 0x001E70, 0, { 0x001E71 }}, /* 1E70; 1E71; Case map */ { 0x001E72, 0, { 0x001E73 }}, /* 1E72; 1E73; Case map */ { 0x001E74, 0, { 0x001E75 }}, /* 1E74; 1E75; Case map */ { 0x001E76, 0, { 0x001E77 }}, /* 1E76; 1E77; Case map */ { 0x001E78, 0, { 0x001E79 }}, /* 1E78; 1E79; Case map */ { 0x001E7A, 0, { 0x001E7B }}, /* 1E7A; 1E7B; Case map */ { 0x001E7C, 0, { 0x001E7D }}, /* 1E7C; 1E7D; Case map */ { 0x001E7E, 0, { 0x001E7F }}, /* 1E7E; 1E7F; Case map */ { 0x001E80, 0, { 0x001E81 }}, /* 1E80; 1E81; Case map */ { 0x001E82, 0, { 0x001E83 }}, /* 1E82; 1E83; Case map */ { 0x001E84, 0, { 0x001E85 }}, /* 1E84; 1E85; Case map */ { 0x001E86, 0, { 0x001E87 }}, /* 1E86; 1E87; Case map */ { 0x001E88, 0, { 0x001E89 }}, /* 1E88; 1E89; Case map */ { 0x001E8A, 0, { 0x001E8B }}, /* 1E8A; 1E8B; Case map */ { 0x001E8C, 0, { 0x001E8D }}, /* 1E8C; 1E8D; Case map */ { 0x001E8E, 0, { 0x001E8F }}, /* 1E8E; 1E8F; Case map */ { 0x001E90, 0, { 0x001E91 }}, /* 1E90; 1E91; Case map */ { 0x001E92, 0, { 0x001E93 }}, /* 1E92; 1E93; Case map */ { 0x001E94, 0, { 0x001E95 }}, /* 1E94; 1E95; Case map */ { 0x001E96, 0, { 0x000068, /* 1E96; 0068 0331; Case map */ 0x000331 }}, { 0x001E97, 0, { 0x000074, /* 1E97; 0074 0308; Case map */ 0x000308 }}, { 0x001E98, 0, { 0x000077, /* 1E98; 0077 030A; Case map */ 0x00030A }}, { 0x001E99, 0, { 0x000079, /* 1E99; 0079 030A; Case map */ 0x00030A }}, { 0x001E9A, 0, { 0x000061, /* 1E9A; 0061 02BE; Case map */ 0x0002BE }}, { 0x001E9B, 0, { 0x001E61 }}, /* 1E9B; 1E61; Case map */ { 0x001EA0, 0, { 0x001EA1 }}, /* 1EA0; 1EA1; Case map */ { 0x001EA2, 0, { 0x001EA3 }}, /* 1EA2; 1EA3; Case map */ { 0x001EA4, 0, { 0x001EA5 }}, /* 1EA4; 1EA5; Case map */ { 0x001EA6, 0, { 0x001EA7 }}, /* 1EA6; 1EA7; Case map */ { 0x001EA8, 0, { 0x001EA9 }}, /* 1EA8; 1EA9; Case map */ { 0x001EAA, 0, { 0x001EAB }}, /* 1EAA; 1EAB; Case map */ { 0x001EAC, 0, { 0x001EAD }}, /* 1EAC; 1EAD; Case map */ { 0x001EAE, 0, { 0x001EAF }}, /* 1EAE; 1EAF; Case map */ { 0x001EB0, 0, { 0x001EB1 }}, /* 1EB0; 1EB1; Case map */ { 0x001EB2, 0, { 0x001EB3 }}, /* 1EB2; 1EB3; Case map */ { 0x001EB4, 0, { 0x001EB5 }}, /* 1EB4; 1EB5; Case map */ { 0x001EB6, 0, { 0x001EB7 }}, /* 1EB6; 1EB7; Case map */ { 0x001EB8, 0, { 0x001EB9 }}, /* 1EB8; 1EB9; Case map */ { 0x001EBA, 0, { 0x001EBB }}, /* 1EBA; 1EBB; Case map */ { 0x001EBC, 0, { 0x001EBD }}, /* 1EBC; 1EBD; Case map */ { 0x001EBE, 0, { 0x001EBF }}, /* 1EBE; 1EBF; Case map */ { 0x001EC0, 0, { 0x001EC1 }}, /* 1EC0; 1EC1; Case map */ { 0x001EC2, 0, { 0x001EC3 }}, /* 1EC2; 1EC3; Case map */ { 0x001EC4, 0, { 0x001EC5 }}, /* 1EC4; 1EC5; Case map */ { 0x001EC6, 0, { 0x001EC7 }}, /* 1EC6; 1EC7; Case map */ { 0x001EC8, 0, { 0x001EC9 }}, /* 1EC8; 1EC9; Case map */ { 0x001ECA, 0, { 0x001ECB }}, /* 1ECA; 1ECB; Case map */ { 0x001ECC, 0, { 0x001ECD }}, /* 1ECC; 1ECD; Case map */ { 0x001ECE, 0, { 0x001ECF }}, /* 1ECE; 1ECF; Case map */ { 0x001ED0, 0, { 0x001ED1 }}, /* 1ED0; 1ED1; Case map */ { 0x001ED2, 0, { 0x001ED3 }}, /* 1ED2; 1ED3; Case map */ { 0x001ED4, 0, { 0x001ED5 }}, /* 1ED4; 1ED5; Case map */ { 0x001ED6, 0, { 0x001ED7 }}, /* 1ED6; 1ED7; Case map */ { 0x001ED8, 0, { 0x001ED9 }}, /* 1ED8; 1ED9; Case map */ { 0x001EDA, 0, { 0x001EDB }}, /* 1EDA; 1EDB; Case map */ { 0x001EDC, 0, { 0x001EDD }}, /* 1EDC; 1EDD; Case map */ { 0x001EDE, 0, { 0x001EDF }}, /* 1EDE; 1EDF; Case map */ { 0x001EE0, 0, { 0x001EE1 }}, /* 1EE0; 1EE1; Case map */ { 0x001EE2, 0, { 0x001EE3 }}, /* 1EE2; 1EE3; Case map */ { 0x001EE4, 0, { 0x001EE5 }}, /* 1EE4; 1EE5; Case map */ { 0x001EE6, 0, { 0x001EE7 }}, /* 1EE6; 1EE7; Case map */ { 0x001EE8, 0, { 0x001EE9 }}, /* 1EE8; 1EE9; Case map */ { 0x001EEA, 0, { 0x001EEB }}, /* 1EEA; 1EEB; Case map */ { 0x001EEC, 0, { 0x001EED }}, /* 1EEC; 1EED; Case map */ { 0x001EEE, 0, { 0x001EEF }}, /* 1EEE; 1EEF; Case map */ { 0x001EF0, 0, { 0x001EF1 }}, /* 1EF0; 1EF1; Case map */ { 0x001EF2, 0, { 0x001EF3 }}, /* 1EF2; 1EF3; Case map */ { 0x001EF4, 0, { 0x001EF5 }}, /* 1EF4; 1EF5; Case map */ { 0x001EF6, 0, { 0x001EF7 }}, /* 1EF6; 1EF7; Case map */ { 0x001EF8, 0, { 0x001EF9 }}, /* 1EF8; 1EF9; Case map */ { 0x001F08, 0, { 0x001F00 }}, /* 1F08; 1F00; Case map */ { 0x001F09, 0, { 0x001F01 }}, /* 1F09; 1F01; Case map */ { 0x001F0A, 0, { 0x001F02 }}, /* 1F0A; 1F02; Case map */ { 0x001F0B, 0, { 0x001F03 }}, /* 1F0B; 1F03; Case map */ { 0x001F0C, 0, { 0x001F04 }}, /* 1F0C; 1F04; Case map */ { 0x001F0D, 0, { 0x001F05 }}, /* 1F0D; 1F05; Case map */ { 0x001F0E, 0, { 0x001F06 }}, /* 1F0E; 1F06; Case map */ { 0x001F0F, 0, { 0x001F07 }}, /* 1F0F; 1F07; Case map */ { 0x001F18, 0, { 0x001F10 }}, /* 1F18; 1F10; Case map */ { 0x001F19, 0, { 0x001F11 }}, /* 1F19; 1F11; Case map */ { 0x001F1A, 0, { 0x001F12 }}, /* 1F1A; 1F12; Case map */ { 0x001F1B, 0, { 0x001F13 }}, /* 1F1B; 1F13; Case map */ { 0x001F1C, 0, { 0x001F14 }}, /* 1F1C; 1F14; Case map */ { 0x001F1D, 0, { 0x001F15 }}, /* 1F1D; 1F15; Case map */ { 0x001F28, 0, { 0x001F20 }}, /* 1F28; 1F20; Case map */ { 0x001F29, 0, { 0x001F21 }}, /* 1F29; 1F21; Case map */ { 0x001F2A, 0, { 0x001F22 }}, /* 1F2A; 1F22; Case map */ { 0x001F2B, 0, { 0x001F23 }}, /* 1F2B; 1F23; Case map */ { 0x001F2C, 0, { 0x001F24 }}, /* 1F2C; 1F24; Case map */ { 0x001F2D, 0, { 0x001F25 }}, /* 1F2D; 1F25; Case map */ { 0x001F2E, 0, { 0x001F26 }}, /* 1F2E; 1F26; Case map */ { 0x001F2F, 0, { 0x001F27 }}, /* 1F2F; 1F27; Case map */ { 0x001F38, 0, { 0x001F30 }}, /* 1F38; 1F30; Case map */ { 0x001F39, 0, { 0x001F31 }}, /* 1F39; 1F31; Case map */ { 0x001F3A, 0, { 0x001F32 }}, /* 1F3A; 1F32; Case map */ { 0x001F3B, 0, { 0x001F33 }}, /* 1F3B; 1F33; Case map */ { 0x001F3C, 0, { 0x001F34 }}, /* 1F3C; 1F34; Case map */ { 0x001F3D, 0, { 0x001F35 }}, /* 1F3D; 1F35; Case map */ { 0x001F3E, 0, { 0x001F36 }}, /* 1F3E; 1F36; Case map */ { 0x001F3F, 0, { 0x001F37 }}, /* 1F3F; 1F37; Case map */ { 0x001F48, 0, { 0x001F40 }}, /* 1F48; 1F40; Case map */ { 0x001F49, 0, { 0x001F41 }}, /* 1F49; 1F41; Case map */ { 0x001F4A, 0, { 0x001F42 }}, /* 1F4A; 1F42; Case map */ { 0x001F4B, 0, { 0x001F43 }}, /* 1F4B; 1F43; Case map */ { 0x001F4C, 0, { 0x001F44 }}, /* 1F4C; 1F44; Case map */ { 0x001F4D, 0, { 0x001F45 }}, /* 1F4D; 1F45; Case map */ { 0x001F50, 0, { 0x0003C5, /* 1F50; 03C5 0313; Case map */ 0x000313 }}, { 0x001F52, 0, { 0x0003C5, /* 1F52; 03C5 0313 0300; Case map */ 0x000313, 0x000300 }}, { 0x001F54, 0, { 0x0003C5, /* 1F54; 03C5 0313 0301; Case map */ 0x000313, 0x000301 }}, { 0x001F56, 0, { 0x0003C5, /* 1F56; 03C5 0313 0342; Case map */ 0x000313, 0x000342 }}, { 0x001F59, 0, { 0x001F51 }}, /* 1F59; 1F51; Case map */ { 0x001F5B, 0, { 0x001F53 }}, /* 1F5B; 1F53; Case map */ { 0x001F5D, 0, { 0x001F55 }}, /* 1F5D; 1F55; Case map */ { 0x001F5F, 0, { 0x001F57 }}, /* 1F5F; 1F57; Case map */ { 0x001F68, 0, { 0x001F60 }}, /* 1F68; 1F60; Case map */ { 0x001F69, 0, { 0x001F61 }}, /* 1F69; 1F61; Case map */ { 0x001F6A, 0, { 0x001F62 }}, /* 1F6A; 1F62; Case map */ { 0x001F6B, 0, { 0x001F63 }}, /* 1F6B; 1F63; Case map */ { 0x001F6C, 0, { 0x001F64 }}, /* 1F6C; 1F64; Case map */ { 0x001F6D, 0, { 0x001F65 }}, /* 1F6D; 1F65; Case map */ { 0x001F6E, 0, { 0x001F66 }}, /* 1F6E; 1F66; Case map */ { 0x001F6F, 0, { 0x001F67 }}, /* 1F6F; 1F67; Case map */ { 0x001F80, 0, { 0x001F00, /* 1F80; 1F00 03B9; Case map */ 0x0003B9 }}, { 0x001F81, 0, { 0x001F01, /* 1F81; 1F01 03B9; Case map */ 0x0003B9 }}, { 0x001F82, 0, { 0x001F02, /* 1F82; 1F02 03B9; Case map */ 0x0003B9 }}, { 0x001F83, 0, { 0x001F03, /* 1F83; 1F03 03B9; Case map */ 0x0003B9 }}, { 0x001F84, 0, { 0x001F04, /* 1F84; 1F04 03B9; Case map */ 0x0003B9 }}, { 0x001F85, 0, { 0x001F05, /* 1F85; 1F05 03B9; Case map */ 0x0003B9 }}, { 0x001F86, 0, { 0x001F06, /* 1F86; 1F06 03B9; Case map */ 0x0003B9 }}, { 0x001F87, 0, { 0x001F07, /* 1F87; 1F07 03B9; Case map */ 0x0003B9 }}, { 0x001F88, 0, { 0x001F00, /* 1F88; 1F00 03B9; Case map */ 0x0003B9 }}, { 0x001F89, 0, { 0x001F01, /* 1F89; 1F01 03B9; Case map */ 0x0003B9 }}, { 0x001F8A, 0, { 0x001F02, /* 1F8A; 1F02 03B9; Case map */ 0x0003B9 }}, { 0x001F8B, 0, { 0x001F03, /* 1F8B; 1F03 03B9; Case map */ 0x0003B9 }}, { 0x001F8C, 0, { 0x001F04, /* 1F8C; 1F04 03B9; Case map */ 0x0003B9 }}, { 0x001F8D, 0, { 0x001F05, /* 1F8D; 1F05 03B9; Case map */ 0x0003B9 }}, { 0x001F8E, 0, { 0x001F06, /* 1F8E; 1F06 03B9; Case map */ 0x0003B9 }}, { 0x001F8F, 0, { 0x001F07, /* 1F8F; 1F07 03B9; Case map */ 0x0003B9 }}, { 0x001F90, 0, { 0x001F20, /* 1F90; 1F20 03B9; Case map */ 0x0003B9 }}, { 0x001F91, 0, { 0x001F21, /* 1F91; 1F21 03B9; Case map */ 0x0003B9 }}, { 0x001F92, 0, { 0x001F22, /* 1F92; 1F22 03B9; Case map */ 0x0003B9 }}, { 0x001F93, 0, { 0x001F23, /* 1F93; 1F23 03B9; Case map */ 0x0003B9 }}, { 0x001F94, 0, { 0x001F24, /* 1F94; 1F24 03B9; Case map */ 0x0003B9 }}, { 0x001F95, 0, { 0x001F25, /* 1F95; 1F25 03B9; Case map */ 0x0003B9 }}, { 0x001F96, 0, { 0x001F26, /* 1F96; 1F26 03B9; Case map */ 0x0003B9 }}, { 0x001F97, 0, { 0x001F27, /* 1F97; 1F27 03B9; Case map */ 0x0003B9 }}, { 0x001F98, 0, { 0x001F20, /* 1F98; 1F20 03B9; Case map */ 0x0003B9 }}, { 0x001F99, 0, { 0x001F21, /* 1F99; 1F21 03B9; Case map */ 0x0003B9 }}, { 0x001F9A, 0, { 0x001F22, /* 1F9A; 1F22 03B9; Case map */ 0x0003B9 }}, { 0x001F9B, 0, { 0x001F23, /* 1F9B; 1F23 03B9; Case map */ 0x0003B9 }}, { 0x001F9C, 0, { 0x001F24, /* 1F9C; 1F24 03B9; Case map */ 0x0003B9 }}, { 0x001F9D, 0, { 0x001F25, /* 1F9D; 1F25 03B9; Case map */ 0x0003B9 }}, { 0x001F9E, 0, { 0x001F26, /* 1F9E; 1F26 03B9; Case map */ 0x0003B9 }}, { 0x001F9F, 0, { 0x001F27, /* 1F9F; 1F27 03B9; Case map */ 0x0003B9 }}, { 0x001FA0, 0, { 0x001F60, /* 1FA0; 1F60 03B9; Case map */ 0x0003B9 }}, { 0x001FA1, 0, { 0x001F61, /* 1FA1; 1F61 03B9; Case map */ 0x0003B9 }}, { 0x001FA2, 0, { 0x001F62, /* 1FA2; 1F62 03B9; Case map */ 0x0003B9 }}, { 0x001FA3, 0, { 0x001F63, /* 1FA3; 1F63 03B9; Case map */ 0x0003B9 }}, { 0x001FA4, 0, { 0x001F64, /* 1FA4; 1F64 03B9; Case map */ 0x0003B9 }}, { 0x001FA5, 0, { 0x001F65, /* 1FA5; 1F65 03B9; Case map */ 0x0003B9 }}, { 0x001FA6, 0, { 0x001F66, /* 1FA6; 1F66 03B9; Case map */ 0x0003B9 }}, { 0x001FA7, 0, { 0x001F67, /* 1FA7; 1F67 03B9; Case map */ 0x0003B9 }}, { 0x001FA8, 0, { 0x001F60, /* 1FA8; 1F60 03B9; Case map */ 0x0003B9 }}, { 0x001FA9, 0, { 0x001F61, /* 1FA9; 1F61 03B9; Case map */ 0x0003B9 }}, { 0x001FAA, 0, { 0x001F62, /* 1FAA; 1F62 03B9; Case map */ 0x0003B9 }}, { 0x001FAB, 0, { 0x001F63, /* 1FAB; 1F63 03B9; Case map */ 0x0003B9 }}, { 0x001FAC, 0, { 0x001F64, /* 1FAC; 1F64 03B9; Case map */ 0x0003B9 }}, { 0x001FAD, 0, { 0x001F65, /* 1FAD; 1F65 03B9; Case map */ 0x0003B9 }}, { 0x001FAE, 0, { 0x001F66, /* 1FAE; 1F66 03B9; Case map */ 0x0003B9 }}, { 0x001FAF, 0, { 0x001F67, /* 1FAF; 1F67 03B9; Case map */ 0x0003B9 }}, { 0x001FB2, 0, { 0x001F70, /* 1FB2; 1F70 03B9; Case map */ 0x0003B9 }}, { 0x001FB3, 0, { 0x0003B1, /* 1FB3; 03B1 03B9; Case map */ 0x0003B9 }}, { 0x001FB4, 0, { 0x0003AC, /* 1FB4; 03AC 03B9; Case map */ 0x0003B9 }}, { 0x001FB6, 0, { 0x0003B1, /* 1FB6; 03B1 0342; Case map */ 0x000342 }}, { 0x001FB7, 0, { 0x0003B1, /* 1FB7; 03B1 0342 03B9; Case map */ 0x000342, 0x0003B9 }}, { 0x001FB8, 0, { 0x001FB0 }}, /* 1FB8; 1FB0; Case map */ { 0x001FB9, 0, { 0x001FB1 }}, /* 1FB9; 1FB1; Case map */ { 0x001FBA, 0, { 0x001F70 }}, /* 1FBA; 1F70; Case map */ { 0x001FBB, 0, { 0x001F71 }}, /* 1FBB; 1F71; Case map */ { 0x001FBC, 0, { 0x0003B1, /* 1FBC; 03B1 03B9; Case map */ 0x0003B9 }}, { 0x001FBE, 0, { 0x0003B9 }}, /* 1FBE; 03B9; Case map */ { 0x001FC2, 0, { 0x001F74, /* 1FC2; 1F74 03B9; Case map */ 0x0003B9 }}, { 0x001FC3, 0, { 0x0003B7, /* 1FC3; 03B7 03B9; Case map */ 0x0003B9 }}, { 0x001FC4, 0, { 0x0003AE, /* 1FC4; 03AE 03B9; Case map */ 0x0003B9 }}, { 0x001FC6, 0, { 0x0003B7, /* 1FC6; 03B7 0342; Case map */ 0x000342 }}, { 0x001FC7, 0, { 0x0003B7, /* 1FC7; 03B7 0342 03B9; Case map */ 0x000342, 0x0003B9 }}, { 0x001FC8, 0, { 0x001F72 }}, /* 1FC8; 1F72; Case map */ { 0x001FC9, 0, { 0x001F73 }}, /* 1FC9; 1F73; Case map */ { 0x001FCA, 0, { 0x001F74 }}, /* 1FCA; 1F74; Case map */ { 0x001FCB, 0, { 0x001F75 }}, /* 1FCB; 1F75; Case map */ { 0x001FCC, 0, { 0x0003B7, /* 1FCC; 03B7 03B9; Case map */ 0x0003B9 }}, { 0x001FD2, 0, { 0x0003B9, /* 1FD2; 03B9 0308 0300; Case map */ 0x000308, 0x000300 }}, { 0x001FD3, 0, { 0x0003B9, /* 1FD3; 03B9 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x001FD6, 0, { 0x0003B9, /* 1FD6; 03B9 0342; Case map */ 0x000342 }}, { 0x001FD7, 0, { 0x0003B9, /* 1FD7; 03B9 0308 0342; Case map */ 0x000308, 0x000342 }}, { 0x001FD8, 0, { 0x001FD0 }}, /* 1FD8; 1FD0; Case map */ { 0x001FD9, 0, { 0x001FD1 }}, /* 1FD9; 1FD1; Case map */ { 0x001FDA, 0, { 0x001F76 }}, /* 1FDA; 1F76; Case map */ { 0x001FDB, 0, { 0x001F77 }}, /* 1FDB; 1F77; Case map */ { 0x001FE2, 0, { 0x0003C5, /* 1FE2; 03C5 0308 0300; Case map */ 0x000308, 0x000300 }}, { 0x001FE3, 0, { 0x0003C5, /* 1FE3; 03C5 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x001FE4, 0, { 0x0003C1, /* 1FE4; 03C1 0313; Case map */ 0x000313 }}, { 0x001FE6, 0, { 0x0003C5, /* 1FE6; 03C5 0342; Case map */ 0x000342 }}, { 0x001FE7, 0, { 0x0003C5, /* 1FE7; 03C5 0308 0342; Case map */ 0x000308, 0x000342 }}, { 0x001FE8, 0, { 0x001FE0 }}, /* 1FE8; 1FE0; Case map */ { 0x001FE9, 0, { 0x001FE1 }}, /* 1FE9; 1FE1; Case map */ { 0x001FEA, 0, { 0x001F7A }}, /* 1FEA; 1F7A; Case map */ { 0x001FEB, 0, { 0x001F7B }}, /* 1FEB; 1F7B; Case map */ { 0x001FEC, 0, { 0x001FE5 }}, /* 1FEC; 1FE5; Case map */ { 0x001FF2, 0, { 0x001F7C, /* 1FF2; 1F7C 03B9; Case map */ 0x0003B9 }}, { 0x001FF3, 0, { 0x0003C9, /* 1FF3; 03C9 03B9; Case map */ 0x0003B9 }}, { 0x001FF4, 0, { 0x0003CE, /* 1FF4; 03CE 03B9; Case map */ 0x0003B9 }}, { 0x001FF6, 0, { 0x0003C9, /* 1FF6; 03C9 0342; Case map */ 0x000342 }}, { 0x001FF7, 0, { 0x0003C9, /* 1FF7; 03C9 0342 03B9; Case map */ 0x000342, 0x0003B9 }}, { 0x001FF8, 0, { 0x001F78 }}, /* 1FF8; 1F78; Case map */ { 0x001FF9, 0, { 0x001F79 }}, /* 1FF9; 1F79; Case map */ { 0x001FFA, 0, { 0x001F7C }}, /* 1FFA; 1F7C; Case map */ { 0x001FFB, 0, { 0x001F7D }}, /* 1FFB; 1F7D; Case map */ { 0x001FFC, 0, { 0x0003C9, /* 1FFC; 03C9 03B9; Case map */ 0x0003B9 }}, { 0x0020A8, 0, { 0x000072, /* 20A8; 0072 0073; Additional folding */ 0x000073 }}, { 0x002102, 0, { 0x000063 }}, /* 2102; 0063; Additional folding */ { 0x002103, 0, { 0x0000B0, /* 2103; 00B0 0063; Additional folding */ 0x000063 }}, { 0x002107, 0, { 0x00025B }}, /* 2107; 025B; Additional folding */ { 0x002109, 0, { 0x0000B0, /* 2109; 00B0 0066; Additional folding */ 0x000066 }}, { 0x00210B, 0, { 0x000068 }}, /* 210B; 0068; Additional folding */ { 0x00210C, 0, { 0x000068 }}, /* 210C; 0068; Additional folding */ { 0x00210D, 0, { 0x000068 }}, /* 210D; 0068; Additional folding */ { 0x002110, 0, { 0x000069 }}, /* 2110; 0069; Additional folding */ { 0x002111, 0, { 0x000069 }}, /* 2111; 0069; Additional folding */ { 0x002112, 0, { 0x00006C }}, /* 2112; 006C; Additional folding */ { 0x002115, 0, { 0x00006E }}, /* 2115; 006E; Additional folding */ { 0x002116, 0, { 0x00006E, /* 2116; 006E 006F; Additional folding */ 0x00006F }}, { 0x002119, 0, { 0x000070 }}, /* 2119; 0070; Additional folding */ { 0x00211A, 0, { 0x000071 }}, /* 211A; 0071; Additional folding */ { 0x00211B, 0, { 0x000072 }}, /* 211B; 0072; Additional folding */ { 0x00211C, 0, { 0x000072 }}, /* 211C; 0072; Additional folding */ { 0x00211D, 0, { 0x000072 }}, /* 211D; 0072; Additional folding */ { 0x002120, 0, { 0x000073, /* 2120; 0073 006D; Additional folding */ 0x00006D }}, { 0x002121, 0, { 0x000074, /* 2121; 0074 0065 006C; Additional folding */ 0x000065, 0x00006C }}, { 0x002122, 0, { 0x000074, /* 2122; 0074 006D; Additional folding */ 0x00006D }}, { 0x002124, 0, { 0x00007A }}, /* 2124; 007A; Additional folding */ { 0x002126, 0, { 0x0003C9 }}, /* 2126; 03C9; Case map */ { 0x002128, 0, { 0x00007A }}, /* 2128; 007A; Additional folding */ { 0x00212A, 0, { 0x00006B }}, /* 212A; 006B; Case map */ { 0x00212B, 0, { 0x0000E5 }}, /* 212B; 00E5; Case map */ { 0x00212C, 0, { 0x000062 }}, /* 212C; 0062; Additional folding */ { 0x00212D, 0, { 0x000063 }}, /* 212D; 0063; Additional folding */ { 0x002130, 0, { 0x000065 }}, /* 2130; 0065; Additional folding */ { 0x002131, 0, { 0x000066 }}, /* 2131; 0066; Additional folding */ { 0x002133, 0, { 0x00006D }}, /* 2133; 006D; Additional folding */ { 0x00213E, 0, { 0x0003B3 }}, /* 213E; 03B3; Additional folding */ { 0x00213F, 0, { 0x0003C0 }}, /* 213F; 03C0; Additional folding */ { 0x002145, 0, { 0x000064 }}, /* 2145; 0064; Additional folding */ { 0x002160, 0, { 0x002170 }}, /* 2160; 2170; Case map */ { 0x002161, 0, { 0x002171 }}, /* 2161; 2171; Case map */ { 0x002162, 0, { 0x002172 }}, /* 2162; 2172; Case map */ { 0x002163, 0, { 0x002173 }}, /* 2163; 2173; Case map */ { 0x002164, 0, { 0x002174 }}, /* 2164; 2174; Case map */ { 0x002165, 0, { 0x002175 }}, /* 2165; 2175; Case map */ { 0x002166, 0, { 0x002176 }}, /* 2166; 2176; Case map */ { 0x002167, 0, { 0x002177 }}, /* 2167; 2177; Case map */ { 0x002168, 0, { 0x002178 }}, /* 2168; 2178; Case map */ { 0x002169, 0, { 0x002179 }}, /* 2169; 2179; Case map */ { 0x00216A, 0, { 0x00217A }}, /* 216A; 217A; Case map */ { 0x00216B, 0, { 0x00217B }}, /* 216B; 217B; Case map */ { 0x00216C, 0, { 0x00217C }}, /* 216C; 217C; Case map */ { 0x00216D, 0, { 0x00217D }}, /* 216D; 217D; Case map */ { 0x00216E, 0, { 0x00217E }}, /* 216E; 217E; Case map */ { 0x00216F, 0, { 0x00217F }}, /* 216F; 217F; Case map */ { 0x0024B6, 0, { 0x0024D0 }}, /* 24B6; 24D0; Case map */ { 0x0024B7, 0, { 0x0024D1 }}, /* 24B7; 24D1; Case map */ { 0x0024B8, 0, { 0x0024D2 }}, /* 24B8; 24D2; Case map */ { 0x0024B9, 0, { 0x0024D3 }}, /* 24B9; 24D3; Case map */ { 0x0024BA, 0, { 0x0024D4 }}, /* 24BA; 24D4; Case map */ { 0x0024BB, 0, { 0x0024D5 }}, /* 24BB; 24D5; Case map */ { 0x0024BC, 0, { 0x0024D6 }}, /* 24BC; 24D6; Case map */ { 0x0024BD, 0, { 0x0024D7 }}, /* 24BD; 24D7; Case map */ { 0x0024BE, 0, { 0x0024D8 }}, /* 24BE; 24D8; Case map */ { 0x0024BF, 0, { 0x0024D9 }}, /* 24BF; 24D9; Case map */ { 0x0024C0, 0, { 0x0024DA }}, /* 24C0; 24DA; Case map */ { 0x0024C1, 0, { 0x0024DB }}, /* 24C1; 24DB; Case map */ { 0x0024C2, 0, { 0x0024DC }}, /* 24C2; 24DC; Case map */ { 0x0024C3, 0, { 0x0024DD }}, /* 24C3; 24DD; Case map */ { 0x0024C4, 0, { 0x0024DE }}, /* 24C4; 24DE; Case map */ { 0x0024C5, 0, { 0x0024DF }}, /* 24C5; 24DF; Case map */ { 0x0024C6, 0, { 0x0024E0 }}, /* 24C6; 24E0; Case map */ { 0x0024C7, 0, { 0x0024E1 }}, /* 24C7; 24E1; Case map */ { 0x0024C8, 0, { 0x0024E2 }}, /* 24C8; 24E2; Case map */ { 0x0024C9, 0, { 0x0024E3 }}, /* 24C9; 24E3; Case map */ { 0x0024CA, 0, { 0x0024E4 }}, /* 24CA; 24E4; Case map */ { 0x0024CB, 0, { 0x0024E5 }}, /* 24CB; 24E5; Case map */ { 0x0024CC, 0, { 0x0024E6 }}, /* 24CC; 24E6; Case map */ { 0x0024CD, 0, { 0x0024E7 }}, /* 24CD; 24E7; Case map */ { 0x0024CE, 0, { 0x0024E8 }}, /* 24CE; 24E8; Case map */ { 0x0024CF, 0, { 0x0024E9 }}, /* 24CF; 24E9; Case map */ { 0x003371, 0, { 0x000068, /* 3371; 0068 0070 0061; Additional folding */ 0x000070, 0x000061 }}, { 0x003373, 0, { 0x000061, /* 3373; 0061 0075; Additional folding */ 0x000075 }}, { 0x003375, 0, { 0x00006F, /* 3375; 006F 0076; Additional folding */ 0x000076 }}, { 0x003380, 0, { 0x000070, /* 3380; 0070 0061; Additional folding */ 0x000061 }}, { 0x003381, 0, { 0x00006E, /* 3381; 006E 0061; Additional folding */ 0x000061 }}, { 0x003382, 0, { 0x0003BC, /* 3382; 03BC 0061; Additional folding */ 0x000061 }}, { 0x003383, 0, { 0x00006D, /* 3383; 006D 0061; Additional folding */ 0x000061 }}, { 0x003384, 0, { 0x00006B, /* 3384; 006B 0061; Additional folding */ 0x000061 }}, { 0x003385, 0, { 0x00006B, /* 3385; 006B 0062; Additional folding */ 0x000062 }}, { 0x003386, 0, { 0x00006D, /* 3386; 006D 0062; Additional folding */ 0x000062 }}, { 0x003387, 0, { 0x000067, /* 3387; 0067 0062; Additional folding */ 0x000062 }}, { 0x00338A, 0, { 0x000070, /* 338A; 0070 0066; Additional folding */ 0x000066 }}, { 0x00338B, 0, { 0x00006E, /* 338B; 006E 0066; Additional folding */ 0x000066 }}, { 0x00338C, 0, { 0x0003BC, /* 338C; 03BC 0066; Additional folding */ 0x000066 }}, { 0x003390, 0, { 0x000068, /* 3390; 0068 007A; Additional folding */ 0x00007A }}, { 0x003391, 0, { 0x00006B, /* 3391; 006B 0068 007A; Additional folding */ 0x000068, 0x00007A }}, { 0x003392, 0, { 0x00006D, /* 3392; 006D 0068 007A; Additional folding */ 0x000068, 0x00007A }}, { 0x003393, 0, { 0x000067, /* 3393; 0067 0068 007A; Additional folding */ 0x000068, 0x00007A }}, { 0x003394, 0, { 0x000074, /* 3394; 0074 0068 007A; Additional folding */ 0x000068, 0x00007A }}, { 0x0033A9, 0, { 0x000070, /* 33A9; 0070 0061; Additional folding */ 0x000061 }}, { 0x0033AA, 0, { 0x00006B, /* 33AA; 006B 0070 0061; Additional folding */ 0x000070, 0x000061 }}, { 0x0033AB, 0, { 0x00006D, /* 33AB; 006D 0070 0061; Additional folding */ 0x000070, 0x000061 }}, { 0x0033AC, 0, { 0x000067, /* 33AC; 0067 0070 0061; Additional folding */ 0x000070, 0x000061 }}, { 0x0033B4, 0, { 0x000070, /* 33B4; 0070 0076; Additional folding */ 0x000076 }}, { 0x0033B5, 0, { 0x00006E, /* 33B5; 006E 0076; Additional folding */ 0x000076 }}, { 0x0033B6, 0, { 0x0003BC, /* 33B6; 03BC 0076; Additional folding */ 0x000076 }}, { 0x0033B7, 0, { 0x00006D, /* 33B7; 006D 0076; Additional folding */ 0x000076 }}, { 0x0033B8, 0, { 0x00006B, /* 33B8; 006B 0076; Additional folding */ 0x000076 }}, { 0x0033B9, 0, { 0x00006D, /* 33B9; 006D 0076; Additional folding */ 0x000076 }}, { 0x0033BA, 0, { 0x000070, /* 33BA; 0070 0077; Additional folding */ 0x000077 }}, { 0x0033BB, 0, { 0x00006E, /* 33BB; 006E 0077; Additional folding */ 0x000077 }}, { 0x0033BC, 0, { 0x0003BC, /* 33BC; 03BC 0077; Additional folding */ 0x000077 }}, { 0x0033BD, 0, { 0x00006D, /* 33BD; 006D 0077; Additional folding */ 0x000077 }}, { 0x0033BE, 0, { 0x00006B, /* 33BE; 006B 0077; Additional folding */ 0x000077 }}, { 0x0033BF, 0, { 0x00006D, /* 33BF; 006D 0077; Additional folding */ 0x000077 }}, { 0x0033C0, 0, { 0x00006B, /* 33C0; 006B 03C9; Additional folding */ 0x0003C9 }}, { 0x0033C1, 0, { 0x00006D, /* 33C1; 006D 03C9; Additional folding */ 0x0003C9 }}, { 0x0033C3, 0, { 0x000062, /* 33C3; 0062 0071; Additional folding */ 0x000071 }}, { 0x0033C6, 0, { 0x000063, /* 33C6; 0063 2215 006B 0067; Additional folding */ 0x002215, 0x00006B, 0x000067 }}, { 0x0033C7, 0, { 0x000063, /* 33C7; 0063 006F 002E; Additional folding */ 0x00006F, 0x00002E }}, { 0x0033C8, 0, { 0x000064, /* 33C8; 0064 0062; Additional folding */ 0x000062 }}, { 0x0033C9, 0, { 0x000067, /* 33C9; 0067 0079; Additional folding */ 0x000079 }}, { 0x0033CB, 0, { 0x000068, /* 33CB; 0068 0070; Additional folding */ 0x000070 }}, { 0x0033CD, 0, { 0x00006B, /* 33CD; 006B 006B; Additional folding */ 0x00006B }}, { 0x0033CE, 0, { 0x00006B, /* 33CE; 006B 006D; Additional folding */ 0x00006D }}, { 0x0033D7, 0, { 0x000070, /* 33D7; 0070 0068; Additional folding */ 0x000068 }}, { 0x0033D9, 0, { 0x000070, /* 33D9; 0070 0070 006D; Additional folding */ 0x000070, 0x00006D }}, { 0x0033DA, 0, { 0x000070, /* 33DA; 0070 0072; Additional folding */ 0x000072 }}, { 0x0033DC, 0, { 0x000073, /* 33DC; 0073 0076; Additional folding */ 0x000076 }}, { 0x0033DD, 0, { 0x000077, /* 33DD; 0077 0062; Additional folding */ 0x000062 }}, { 0x00FB00, 0, { 0x000066, /* FB00; 0066 0066; Case map */ 0x000066 }}, { 0x00FB01, 0, { 0x000066, /* FB01; 0066 0069; Case map */ 0x000069 }}, { 0x00FB02, 0, { 0x000066, /* FB02; 0066 006C; Case map */ 0x00006C }}, { 0x00FB03, 0, { 0x000066, /* FB03; 0066 0066 0069; Case map */ 0x000066, 0x000069 }}, { 0x00FB04, 0, { 0x000066, /* FB04; 0066 0066 006C; Case map */ 0x000066, 0x00006C }}, { 0x00FB05, 0, { 0x000073, /* FB05; 0073 0074; Case map */ 0x000074 }}, { 0x00FB06, 0, { 0x000073, /* FB06; 0073 0074; Case map */ 0x000074 }}, { 0x00FB13, 0, { 0x000574, /* FB13; 0574 0576; Case map */ 0x000576 }}, { 0x00FB14, 0, { 0x000574, /* FB14; 0574 0565; Case map */ 0x000565 }}, { 0x00FB15, 0, { 0x000574, /* FB15; 0574 056B; Case map */ 0x00056B }}, { 0x00FB16, 0, { 0x00057E, /* FB16; 057E 0576; Case map */ 0x000576 }}, { 0x00FB17, 0, { 0x000574, /* FB17; 0574 056D; Case map */ 0x00056D }}, { 0x00FF21, 0, { 0x00FF41 }}, /* FF21; FF41; Case map */ { 0x00FF22, 0, { 0x00FF42 }}, /* FF22; FF42; Case map */ { 0x00FF23, 0, { 0x00FF43 }}, /* FF23; FF43; Case map */ { 0x00FF24, 0, { 0x00FF44 }}, /* FF24; FF44; Case map */ { 0x00FF25, 0, { 0x00FF45 }}, /* FF25; FF45; Case map */ { 0x00FF26, 0, { 0x00FF46 }}, /* FF26; FF46; Case map */ { 0x00FF27, 0, { 0x00FF47 }}, /* FF27; FF47; Case map */ { 0x00FF28, 0, { 0x00FF48 }}, /* FF28; FF48; Case map */ { 0x00FF29, 0, { 0x00FF49 }}, /* FF29; FF49; Case map */ { 0x00FF2A, 0, { 0x00FF4A }}, /* FF2A; FF4A; Case map */ { 0x00FF2B, 0, { 0x00FF4B }}, /* FF2B; FF4B; Case map */ { 0x00FF2C, 0, { 0x00FF4C }}, /* FF2C; FF4C; Case map */ { 0x00FF2D, 0, { 0x00FF4D }}, /* FF2D; FF4D; Case map */ { 0x00FF2E, 0, { 0x00FF4E }}, /* FF2E; FF4E; Case map */ { 0x00FF2F, 0, { 0x00FF4F }}, /* FF2F; FF4F; Case map */ { 0x00FF30, 0, { 0x00FF50 }}, /* FF30; FF50; Case map */ { 0x00FF31, 0, { 0x00FF51 }}, /* FF31; FF51; Case map */ { 0x00FF32, 0, { 0x00FF52 }}, /* FF32; FF52; Case map */ { 0x00FF33, 0, { 0x00FF53 }}, /* FF33; FF53; Case map */ { 0x00FF34, 0, { 0x00FF54 }}, /* FF34; FF54; Case map */ { 0x00FF35, 0, { 0x00FF55 }}, /* FF35; FF55; Case map */ { 0x00FF36, 0, { 0x00FF56 }}, /* FF36; FF56; Case map */ { 0x00FF37, 0, { 0x00FF57 }}, /* FF37; FF57; Case map */ { 0x00FF38, 0, { 0x00FF58 }}, /* FF38; FF58; Case map */ { 0x00FF39, 0, { 0x00FF59 }}, /* FF39; FF59; Case map */ { 0x00FF3A, 0, { 0x00FF5A }}, /* FF3A; FF5A; Case map */ { 0x010400, 0, { 0x010428 }}, /* 10400; 10428; Case map */ { 0x010401, 0, { 0x010429 }}, /* 10401; 10429; Case map */ { 0x010402, 0, { 0x01042A }}, /* 10402; 1042A; Case map */ { 0x010403, 0, { 0x01042B }}, /* 10403; 1042B; Case map */ { 0x010404, 0, { 0x01042C }}, /* 10404; 1042C; Case map */ { 0x010405, 0, { 0x01042D }}, /* 10405; 1042D; Case map */ { 0x010406, 0, { 0x01042E }}, /* 10406; 1042E; Case map */ { 0x010407, 0, { 0x01042F }}, /* 10407; 1042F; Case map */ { 0x010408, 0, { 0x010430 }}, /* 10408; 10430; Case map */ { 0x010409, 0, { 0x010431 }}, /* 10409; 10431; Case map */ { 0x01040A, 0, { 0x010432 }}, /* 1040A; 10432; Case map */ { 0x01040B, 0, { 0x010433 }}, /* 1040B; 10433; Case map */ { 0x01040C, 0, { 0x010434 }}, /* 1040C; 10434; Case map */ { 0x01040D, 0, { 0x010435 }}, /* 1040D; 10435; Case map */ { 0x01040E, 0, { 0x010436 }}, /* 1040E; 10436; Case map */ { 0x01040F, 0, { 0x010437 }}, /* 1040F; 10437; Case map */ { 0x010410, 0, { 0x010438 }}, /* 10410; 10438; Case map */ { 0x010411, 0, { 0x010439 }}, /* 10411; 10439; Case map */ { 0x010412, 0, { 0x01043A }}, /* 10412; 1043A; Case map */ { 0x010413, 0, { 0x01043B }}, /* 10413; 1043B; Case map */ { 0x010414, 0, { 0x01043C }}, /* 10414; 1043C; Case map */ { 0x010415, 0, { 0x01043D }}, /* 10415; 1043D; Case map */ { 0x010416, 0, { 0x01043E }}, /* 10416; 1043E; Case map */ { 0x010417, 0, { 0x01043F }}, /* 10417; 1043F; Case map */ { 0x010418, 0, { 0x010440 }}, /* 10418; 10440; Case map */ { 0x010419, 0, { 0x010441 }}, /* 10419; 10441; Case map */ { 0x01041A, 0, { 0x010442 }}, /* 1041A; 10442; Case map */ { 0x01041B, 0, { 0x010443 }}, /* 1041B; 10443; Case map */ { 0x01041C, 0, { 0x010444 }}, /* 1041C; 10444; Case map */ { 0x01041D, 0, { 0x010445 }}, /* 1041D; 10445; Case map */ { 0x01041E, 0, { 0x010446 }}, /* 1041E; 10446; Case map */ { 0x01041F, 0, { 0x010447 }}, /* 1041F; 10447; Case map */ { 0x010420, 0, { 0x010448 }}, /* 10420; 10448; Case map */ { 0x010421, 0, { 0x010449 }}, /* 10421; 10449; Case map */ { 0x010422, 0, { 0x01044A }}, /* 10422; 1044A; Case map */ { 0x010423, 0, { 0x01044B }}, /* 10423; 1044B; Case map */ { 0x010424, 0, { 0x01044C }}, /* 10424; 1044C; Case map */ { 0x010425, 0, { 0x01044D }}, /* 10425; 1044D; Case map */ { 0x01D400, 0, { 0x000061 }}, /* 1D400; 0061; Additional folding */ { 0x01D401, 0, { 0x000062 }}, /* 1D401; 0062; Additional folding */ { 0x01D402, 0, { 0x000063 }}, /* 1D402; 0063; Additional folding */ { 0x01D403, 0, { 0x000064 }}, /* 1D403; 0064; Additional folding */ { 0x01D404, 0, { 0x000065 }}, /* 1D404; 0065; Additional folding */ { 0x01D405, 0, { 0x000066 }}, /* 1D405; 0066; Additional folding */ { 0x01D406, 0, { 0x000067 }}, /* 1D406; 0067; Additional folding */ { 0x01D407, 0, { 0x000068 }}, /* 1D407; 0068; Additional folding */ { 0x01D408, 0, { 0x000069 }}, /* 1D408; 0069; Additional folding */ { 0x01D409, 0, { 0x00006A }}, /* 1D409; 006A; Additional folding */ { 0x01D40A, 0, { 0x00006B }}, /* 1D40A; 006B; Additional folding */ { 0x01D40B, 0, { 0x00006C }}, /* 1D40B; 006C; Additional folding */ { 0x01D40C, 0, { 0x00006D }}, /* 1D40C; 006D; Additional folding */ { 0x01D40D, 0, { 0x00006E }}, /* 1D40D; 006E; Additional folding */ { 0x01D40E, 0, { 0x00006F }}, /* 1D40E; 006F; Additional folding */ { 0x01D40F, 0, { 0x000070 }}, /* 1D40F; 0070; Additional folding */ { 0x01D410, 0, { 0x000071 }}, /* 1D410; 0071; Additional folding */ { 0x01D411, 0, { 0x000072 }}, /* 1D411; 0072; Additional folding */ { 0x01D412, 0, { 0x000073 }}, /* 1D412; 0073; Additional folding */ { 0x01D413, 0, { 0x000074 }}, /* 1D413; 0074; Additional folding */ { 0x01D414, 0, { 0x000075 }}, /* 1D414; 0075; Additional folding */ { 0x01D415, 0, { 0x000076 }}, /* 1D415; 0076; Additional folding */ { 0x01D416, 0, { 0x000077 }}, /* 1D416; 0077; Additional folding */ { 0x01D417, 0, { 0x000078 }}, /* 1D417; 0078; Additional folding */ { 0x01D418, 0, { 0x000079 }}, /* 1D418; 0079; Additional folding */ { 0x01D419, 0, { 0x00007A }}, /* 1D419; 007A; Additional folding */ { 0x01D434, 0, { 0x000061 }}, /* 1D434; 0061; Additional folding */ { 0x01D435, 0, { 0x000062 }}, /* 1D435; 0062; Additional folding */ { 0x01D436, 0, { 0x000063 }}, /* 1D436; 0063; Additional folding */ { 0x01D437, 0, { 0x000064 }}, /* 1D437; 0064; Additional folding */ { 0x01D438, 0, { 0x000065 }}, /* 1D438; 0065; Additional folding */ { 0x01D439, 0, { 0x000066 }}, /* 1D439; 0066; Additional folding */ { 0x01D43A, 0, { 0x000067 }}, /* 1D43A; 0067; Additional folding */ { 0x01D43B, 0, { 0x000068 }}, /* 1D43B; 0068; Additional folding */ { 0x01D43C, 0, { 0x000069 }}, /* 1D43C; 0069; Additional folding */ { 0x01D43D, 0, { 0x00006A }}, /* 1D43D; 006A; Additional folding */ { 0x01D43E, 0, { 0x00006B }}, /* 1D43E; 006B; Additional folding */ { 0x01D43F, 0, { 0x00006C }}, /* 1D43F; 006C; Additional folding */ { 0x01D440, 0, { 0x00006D }}, /* 1D440; 006D; Additional folding */ { 0x01D441, 0, { 0x00006E }}, /* 1D441; 006E; Additional folding */ { 0x01D442, 0, { 0x00006F }}, /* 1D442; 006F; Additional folding */ { 0x01D443, 0, { 0x000070 }}, /* 1D443; 0070; Additional folding */ { 0x01D444, 0, { 0x000071 }}, /* 1D444; 0071; Additional folding */ { 0x01D445, 0, { 0x000072 }}, /* 1D445; 0072; Additional folding */ { 0x01D446, 0, { 0x000073 }}, /* 1D446; 0073; Additional folding */ { 0x01D447, 0, { 0x000074 }}, /* 1D447; 0074; Additional folding */ { 0x01D448, 0, { 0x000075 }}, /* 1D448; 0075; Additional folding */ { 0x01D449, 0, { 0x000076 }}, /* 1D449; 0076; Additional folding */ { 0x01D44A, 0, { 0x000077 }}, /* 1D44A; 0077; Additional folding */ { 0x01D44B, 0, { 0x000078 }}, /* 1D44B; 0078; Additional folding */ { 0x01D44C, 0, { 0x000079 }}, /* 1D44C; 0079; Additional folding */ { 0x01D44D, 0, { 0x00007A }}, /* 1D44D; 007A; Additional folding */ { 0x01D468, 0, { 0x000061 }}, /* 1D468; 0061; Additional folding */ { 0x01D469, 0, { 0x000062 }}, /* 1D469; 0062; Additional folding */ { 0x01D46A, 0, { 0x000063 }}, /* 1D46A; 0063; Additional folding */ { 0x01D46B, 0, { 0x000064 }}, /* 1D46B; 0064; Additional folding */ { 0x01D46C, 0, { 0x000065 }}, /* 1D46C; 0065; Additional folding */ { 0x01D46D, 0, { 0x000066 }}, /* 1D46D; 0066; Additional folding */ { 0x01D46E, 0, { 0x000067 }}, /* 1D46E; 0067; Additional folding */ { 0x01D46F, 0, { 0x000068 }}, /* 1D46F; 0068; Additional folding */ { 0x01D470, 0, { 0x000069 }}, /* 1D470; 0069; Additional folding */ { 0x01D471, 0, { 0x00006A }}, /* 1D471; 006A; Additional folding */ { 0x01D472, 0, { 0x00006B }}, /* 1D472; 006B; Additional folding */ { 0x01D473, 0, { 0x00006C }}, /* 1D473; 006C; Additional folding */ { 0x01D474, 0, { 0x00006D }}, /* 1D474; 006D; Additional folding */ { 0x01D475, 0, { 0x00006E }}, /* 1D475; 006E; Additional folding */ { 0x01D476, 0, { 0x00006F }}, /* 1D476; 006F; Additional folding */ { 0x01D477, 0, { 0x000070 }}, /* 1D477; 0070; Additional folding */ { 0x01D478, 0, { 0x000071 }}, /* 1D478; 0071; Additional folding */ { 0x01D479, 0, { 0x000072 }}, /* 1D479; 0072; Additional folding */ { 0x01D47A, 0, { 0x000073 }}, /* 1D47A; 0073; Additional folding */ { 0x01D47B, 0, { 0x000074 }}, /* 1D47B; 0074; Additional folding */ { 0x01D47C, 0, { 0x000075 }}, /* 1D47C; 0075; Additional folding */ { 0x01D47D, 0, { 0x000076 }}, /* 1D47D; 0076; Additional folding */ { 0x01D47E, 0, { 0x000077 }}, /* 1D47E; 0077; Additional folding */ { 0x01D47F, 0, { 0x000078 }}, /* 1D47F; 0078; Additional folding */ { 0x01D480, 0, { 0x000079 }}, /* 1D480; 0079; Additional folding */ { 0x01D481, 0, { 0x00007A }}, /* 1D481; 007A; Additional folding */ { 0x01D49C, 0, { 0x000061 }}, /* 1D49C; 0061; Additional folding */ { 0x01D49E, 0, { 0x000063 }}, /* 1D49E; 0063; Additional folding */ { 0x01D49F, 0, { 0x000064 }}, /* 1D49F; 0064; Additional folding */ { 0x01D4A2, 0, { 0x000067 }}, /* 1D4A2; 0067; Additional folding */ { 0x01D4A5, 0, { 0x00006A }}, /* 1D4A5; 006A; Additional folding */ { 0x01D4A6, 0, { 0x00006B }}, /* 1D4A6; 006B; Additional folding */ { 0x01D4A9, 0, { 0x00006E }}, /* 1D4A9; 006E; Additional folding */ { 0x01D4AA, 0, { 0x00006F }}, /* 1D4AA; 006F; Additional folding */ { 0x01D4AB, 0, { 0x000070 }}, /* 1D4AB; 0070; Additional folding */ { 0x01D4AC, 0, { 0x000071 }}, /* 1D4AC; 0071; Additional folding */ { 0x01D4AE, 0, { 0x000073 }}, /* 1D4AE; 0073; Additional folding */ { 0x01D4AF, 0, { 0x000074 }}, /* 1D4AF; 0074; Additional folding */ { 0x01D4B0, 0, { 0x000075 }}, /* 1D4B0; 0075; Additional folding */ { 0x01D4B1, 0, { 0x000076 }}, /* 1D4B1; 0076; Additional folding */ { 0x01D4B2, 0, { 0x000077 }}, /* 1D4B2; 0077; Additional folding */ { 0x01D4B3, 0, { 0x000078 }}, /* 1D4B3; 0078; Additional folding */ { 0x01D4B4, 0, { 0x000079 }}, /* 1D4B4; 0079; Additional folding */ { 0x01D4B5, 0, { 0x00007A }}, /* 1D4B5; 007A; Additional folding */ { 0x01D4D0, 0, { 0x000061 }}, /* 1D4D0; 0061; Additional folding */ { 0x01D4D1, 0, { 0x000062 }}, /* 1D4D1; 0062; Additional folding */ { 0x01D4D2, 0, { 0x000063 }}, /* 1D4D2; 0063; Additional folding */ { 0x01D4D3, 0, { 0x000064 }}, /* 1D4D3; 0064; Additional folding */ { 0x01D4D4, 0, { 0x000065 }}, /* 1D4D4; 0065; Additional folding */ { 0x01D4D5, 0, { 0x000066 }}, /* 1D4D5; 0066; Additional folding */ { 0x01D4D6, 0, { 0x000067 }}, /* 1D4D6; 0067; Additional folding */ { 0x01D4D7, 0, { 0x000068 }}, /* 1D4D7; 0068; Additional folding */ { 0x01D4D8, 0, { 0x000069 }}, /* 1D4D8; 0069; Additional folding */ { 0x01D4D9, 0, { 0x00006A }}, /* 1D4D9; 006A; Additional folding */ { 0x01D4DA, 0, { 0x00006B }}, /* 1D4DA; 006B; Additional folding */ { 0x01D4DB, 0, { 0x00006C }}, /* 1D4DB; 006C; Additional folding */ { 0x01D4DC, 0, { 0x00006D }}, /* 1D4DC; 006D; Additional folding */ { 0x01D4DD, 0, { 0x00006E }}, /* 1D4DD; 006E; Additional folding */ { 0x01D4DE, 0, { 0x00006F }}, /* 1D4DE; 006F; Additional folding */ { 0x01D4DF, 0, { 0x000070 }}, /* 1D4DF; 0070; Additional folding */ { 0x01D4E0, 0, { 0x000071 }}, /* 1D4E0; 0071; Additional folding */ { 0x01D4E1, 0, { 0x000072 }}, /* 1D4E1; 0072; Additional folding */ { 0x01D4E2, 0, { 0x000073 }}, /* 1D4E2; 0073; Additional folding */ { 0x01D4E3, 0, { 0x000074 }}, /* 1D4E3; 0074; Additional folding */ { 0x01D4E4, 0, { 0x000075 }}, /* 1D4E4; 0075; Additional folding */ { 0x01D4E5, 0, { 0x000076 }}, /* 1D4E5; 0076; Additional folding */ { 0x01D4E6, 0, { 0x000077 }}, /* 1D4E6; 0077; Additional folding */ { 0x01D4E7, 0, { 0x000078 }}, /* 1D4E7; 0078; Additional folding */ { 0x01D4E8, 0, { 0x000079 }}, /* 1D4E8; 0079; Additional folding */ { 0x01D4E9, 0, { 0x00007A }}, /* 1D4E9; 007A; Additional folding */ { 0x01D504, 0, { 0x000061 }}, /* 1D504; 0061; Additional folding */ { 0x01D505, 0, { 0x000062 }}, /* 1D505; 0062; Additional folding */ { 0x01D507, 0, { 0x000064 }}, /* 1D507; 0064; Additional folding */ { 0x01D508, 0, { 0x000065 }}, /* 1D508; 0065; Additional folding */ { 0x01D509, 0, { 0x000066 }}, /* 1D509; 0066; Additional folding */ { 0x01D50A, 0, { 0x000067 }}, /* 1D50A; 0067; Additional folding */ { 0x01D50D, 0, { 0x00006A }}, /* 1D50D; 006A; Additional folding */ { 0x01D50E, 0, { 0x00006B }}, /* 1D50E; 006B; Additional folding */ { 0x01D50F, 0, { 0x00006C }}, /* 1D50F; 006C; Additional folding */ { 0x01D510, 0, { 0x00006D }}, /* 1D510; 006D; Additional folding */ { 0x01D511, 0, { 0x00006E }}, /* 1D511; 006E; Additional folding */ { 0x01D512, 0, { 0x00006F }}, /* 1D512; 006F; Additional folding */ { 0x01D513, 0, { 0x000070 }}, /* 1D513; 0070; Additional folding */ { 0x01D514, 0, { 0x000071 }}, /* 1D514; 0071; Additional folding */ { 0x01D516, 0, { 0x000073 }}, /* 1D516; 0073; Additional folding */ { 0x01D517, 0, { 0x000074 }}, /* 1D517; 0074; Additional folding */ { 0x01D518, 0, { 0x000075 }}, /* 1D518; 0075; Additional folding */ { 0x01D519, 0, { 0x000076 }}, /* 1D519; 0076; Additional folding */ { 0x01D51A, 0, { 0x000077 }}, /* 1D51A; 0077; Additional folding */ { 0x01D51B, 0, { 0x000078 }}, /* 1D51B; 0078; Additional folding */ { 0x01D51C, 0, { 0x000079 }}, /* 1D51C; 0079; Additional folding */ { 0x01D538, 0, { 0x000061 }}, /* 1D538; 0061; Additional folding */ { 0x01D539, 0, { 0x000062 }}, /* 1D539; 0062; Additional folding */ { 0x01D53B, 0, { 0x000064 }}, /* 1D53B; 0064; Additional folding */ { 0x01D53C, 0, { 0x000065 }}, /* 1D53C; 0065; Additional folding */ { 0x01D53D, 0, { 0x000066 }}, /* 1D53D; 0066; Additional folding */ { 0x01D53E, 0, { 0x000067 }}, /* 1D53E; 0067; Additional folding */ { 0x01D540, 0, { 0x000069 }}, /* 1D540; 0069; Additional folding */ { 0x01D541, 0, { 0x00006A }}, /* 1D541; 006A; Additional folding */ { 0x01D542, 0, { 0x00006B }}, /* 1D542; 006B; Additional folding */ { 0x01D543, 0, { 0x00006C }}, /* 1D543; 006C; Additional folding */ { 0x01D544, 0, { 0x00006D }}, /* 1D544; 006D; Additional folding */ { 0x01D546, 0, { 0x00006F }}, /* 1D546; 006F; Additional folding */ { 0x01D54A, 0, { 0x000073 }}, /* 1D54A; 0073; Additional folding */ { 0x01D54B, 0, { 0x000074 }}, /* 1D54B; 0074; Additional folding */ { 0x01D54C, 0, { 0x000075 }}, /* 1D54C; 0075; Additional folding */ { 0x01D54D, 0, { 0x000076 }}, /* 1D54D; 0076; Additional folding */ { 0x01D54E, 0, { 0x000077 }}, /* 1D54E; 0077; Additional folding */ { 0x01D54F, 0, { 0x000078 }}, /* 1D54F; 0078; Additional folding */ { 0x01D550, 0, { 0x000079 }}, /* 1D550; 0079; Additional folding */ { 0x01D56C, 0, { 0x000061 }}, /* 1D56C; 0061; Additional folding */ { 0x01D56D, 0, { 0x000062 }}, /* 1D56D; 0062; Additional folding */ { 0x01D56E, 0, { 0x000063 }}, /* 1D56E; 0063; Additional folding */ { 0x01D56F, 0, { 0x000064 }}, /* 1D56F; 0064; Additional folding */ { 0x01D570, 0, { 0x000065 }}, /* 1D570; 0065; Additional folding */ { 0x01D571, 0, { 0x000066 }}, /* 1D571; 0066; Additional folding */ { 0x01D572, 0, { 0x000067 }}, /* 1D572; 0067; Additional folding */ { 0x01D573, 0, { 0x000068 }}, /* 1D573; 0068; Additional folding */ { 0x01D574, 0, { 0x000069 }}, /* 1D574; 0069; Additional folding */ { 0x01D575, 0, { 0x00006A }}, /* 1D575; 006A; Additional folding */ { 0x01D576, 0, { 0x00006B }}, /* 1D576; 006B; Additional folding */ { 0x01D577, 0, { 0x00006C }}, /* 1D577; 006C; Additional folding */ { 0x01D578, 0, { 0x00006D }}, /* 1D578; 006D; Additional folding */ { 0x01D579, 0, { 0x00006E }}, /* 1D579; 006E; Additional folding */ { 0x01D57A, 0, { 0x00006F }}, /* 1D57A; 006F; Additional folding */ { 0x01D57B, 0, { 0x000070 }}, /* 1D57B; 0070; Additional folding */ { 0x01D57C, 0, { 0x000071 }}, /* 1D57C; 0071; Additional folding */ { 0x01D57D, 0, { 0x000072 }}, /* 1D57D; 0072; Additional folding */ { 0x01D57E, 0, { 0x000073 }}, /* 1D57E; 0073; Additional folding */ { 0x01D57F, 0, { 0x000074 }}, /* 1D57F; 0074; Additional folding */ { 0x01D580, 0, { 0x000075 }}, /* 1D580; 0075; Additional folding */ { 0x01D581, 0, { 0x000076 }}, /* 1D581; 0076; Additional folding */ { 0x01D582, 0, { 0x000077 }}, /* 1D582; 0077; Additional folding */ { 0x01D583, 0, { 0x000078 }}, /* 1D583; 0078; Additional folding */ { 0x01D584, 0, { 0x000079 }}, /* 1D584; 0079; Additional folding */ { 0x01D585, 0, { 0x00007A }}, /* 1D585; 007A; Additional folding */ { 0x01D5A0, 0, { 0x000061 }}, /* 1D5A0; 0061; Additional folding */ { 0x01D5A1, 0, { 0x000062 }}, /* 1D5A1; 0062; Additional folding */ { 0x01D5A2, 0, { 0x000063 }}, /* 1D5A2; 0063; Additional folding */ { 0x01D5A3, 0, { 0x000064 }}, /* 1D5A3; 0064; Additional folding */ { 0x01D5A4, 0, { 0x000065 }}, /* 1D5A4; 0065; Additional folding */ { 0x01D5A5, 0, { 0x000066 }}, /* 1D5A5; 0066; Additional folding */ { 0x01D5A6, 0, { 0x000067 }}, /* 1D5A6; 0067; Additional folding */ { 0x01D5A7, 0, { 0x000068 }}, /* 1D5A7; 0068; Additional folding */ { 0x01D5A8, 0, { 0x000069 }}, /* 1D5A8; 0069; Additional folding */ { 0x01D5A9, 0, { 0x00006A }}, /* 1D5A9; 006A; Additional folding */ { 0x01D5AA, 0, { 0x00006B }}, /* 1D5AA; 006B; Additional folding */ { 0x01D5AB, 0, { 0x00006C }}, /* 1D5AB; 006C; Additional folding */ { 0x01D5AC, 0, { 0x00006D }}, /* 1D5AC; 006D; Additional folding */ { 0x01D5AD, 0, { 0x00006E }}, /* 1D5AD; 006E; Additional folding */ { 0x01D5AE, 0, { 0x00006F }}, /* 1D5AE; 006F; Additional folding */ { 0x01D5AF, 0, { 0x000070 }}, /* 1D5AF; 0070; Additional folding */ { 0x01D5B0, 0, { 0x000071 }}, /* 1D5B0; 0071; Additional folding */ { 0x01D5B1, 0, { 0x000072 }}, /* 1D5B1; 0072; Additional folding */ { 0x01D5B2, 0, { 0x000073 }}, /* 1D5B2; 0073; Additional folding */ { 0x01D5B3, 0, { 0x000074 }}, /* 1D5B3; 0074; Additional folding */ { 0x01D5B4, 0, { 0x000075 }}, /* 1D5B4; 0075; Additional folding */ { 0x01D5B5, 0, { 0x000076 }}, /* 1D5B5; 0076; Additional folding */ { 0x01D5B6, 0, { 0x000077 }}, /* 1D5B6; 0077; Additional folding */ { 0x01D5B7, 0, { 0x000078 }}, /* 1D5B7; 0078; Additional folding */ { 0x01D5B8, 0, { 0x000079 }}, /* 1D5B8; 0079; Additional folding */ { 0x01D5B9, 0, { 0x00007A }}, /* 1D5B9; 007A; Additional folding */ { 0x01D5D4, 0, { 0x000061 }}, /* 1D5D4; 0061; Additional folding */ { 0x01D5D5, 0, { 0x000062 }}, /* 1D5D5; 0062; Additional folding */ { 0x01D5D6, 0, { 0x000063 }}, /* 1D5D6; 0063; Additional folding */ { 0x01D5D7, 0, { 0x000064 }}, /* 1D5D7; 0064; Additional folding */ { 0x01D5D8, 0, { 0x000065 }}, /* 1D5D8; 0065; Additional folding */ { 0x01D5D9, 0, { 0x000066 }}, /* 1D5D9; 0066; Additional folding */ { 0x01D5DA, 0, { 0x000067 }}, /* 1D5DA; 0067; Additional folding */ { 0x01D5DB, 0, { 0x000068 }}, /* 1D5DB; 0068; Additional folding */ { 0x01D5DC, 0, { 0x000069 }}, /* 1D5DC; 0069; Additional folding */ { 0x01D5DD, 0, { 0x00006A }}, /* 1D5DD; 006A; Additional folding */ { 0x01D5DE, 0, { 0x00006B }}, /* 1D5DE; 006B; Additional folding */ { 0x01D5DF, 0, { 0x00006C }}, /* 1D5DF; 006C; Additional folding */ { 0x01D5E0, 0, { 0x00006D }}, /* 1D5E0; 006D; Additional folding */ { 0x01D5E1, 0, { 0x00006E }}, /* 1D5E1; 006E; Additional folding */ { 0x01D5E2, 0, { 0x00006F }}, /* 1D5E2; 006F; Additional folding */ { 0x01D5E3, 0, { 0x000070 }}, /* 1D5E3; 0070; Additional folding */ { 0x01D5E4, 0, { 0x000071 }}, /* 1D5E4; 0071; Additional folding */ { 0x01D5E5, 0, { 0x000072 }}, /* 1D5E5; 0072; Additional folding */ { 0x01D5E6, 0, { 0x000073 }}, /* 1D5E6; 0073; Additional folding */ { 0x01D5E7, 0, { 0x000074 }}, /* 1D5E7; 0074; Additional folding */ { 0x01D5E8, 0, { 0x000075 }}, /* 1D5E8; 0075; Additional folding */ { 0x01D5E9, 0, { 0x000076 }}, /* 1D5E9; 0076; Additional folding */ { 0x01D5EA, 0, { 0x000077 }}, /* 1D5EA; 0077; Additional folding */ { 0x01D5EB, 0, { 0x000078 }}, /* 1D5EB; 0078; Additional folding */ { 0x01D5EC, 0, { 0x000079 }}, /* 1D5EC; 0079; Additional folding */ { 0x01D5ED, 0, { 0x00007A }}, /* 1D5ED; 007A; Additional folding */ { 0x01D608, 0, { 0x000061 }}, /* 1D608; 0061; Additional folding */ { 0x01D609, 0, { 0x000062 }}, /* 1D609; 0062; Additional folding */ { 0x01D60A, 0, { 0x000063 }}, /* 1D60A; 0063; Additional folding */ { 0x01D60B, 0, { 0x000064 }}, /* 1D60B; 0064; Additional folding */ { 0x01D60C, 0, { 0x000065 }}, /* 1D60C; 0065; Additional folding */ { 0x01D60D, 0, { 0x000066 }}, /* 1D60D; 0066; Additional folding */ { 0x01D60E, 0, { 0x000067 }}, /* 1D60E; 0067; Additional folding */ { 0x01D60F, 0, { 0x000068 }}, /* 1D60F; 0068; Additional folding */ { 0x01D610, 0, { 0x000069 }}, /* 1D610; 0069; Additional folding */ { 0x01D611, 0, { 0x00006A }}, /* 1D611; 006A; Additional folding */ { 0x01D612, 0, { 0x00006B }}, /* 1D612; 006B; Additional folding */ { 0x01D613, 0, { 0x00006C }}, /* 1D613; 006C; Additional folding */ { 0x01D614, 0, { 0x00006D }}, /* 1D614; 006D; Additional folding */ { 0x01D615, 0, { 0x00006E }}, /* 1D615; 006E; Additional folding */ { 0x01D616, 0, { 0x00006F }}, /* 1D616; 006F; Additional folding */ { 0x01D617, 0, { 0x000070 }}, /* 1D617; 0070; Additional folding */ { 0x01D618, 0, { 0x000071 }}, /* 1D618; 0071; Additional folding */ { 0x01D619, 0, { 0x000072 }}, /* 1D619; 0072; Additional folding */ { 0x01D61A, 0, { 0x000073 }}, /* 1D61A; 0073; Additional folding */ { 0x01D61B, 0, { 0x000074 }}, /* 1D61B; 0074; Additional folding */ { 0x01D61C, 0, { 0x000075 }}, /* 1D61C; 0075; Additional folding */ { 0x01D61D, 0, { 0x000076 }}, /* 1D61D; 0076; Additional folding */ { 0x01D61E, 0, { 0x000077 }}, /* 1D61E; 0077; Additional folding */ { 0x01D61F, 0, { 0x000078 }}, /* 1D61F; 0078; Additional folding */ { 0x01D620, 0, { 0x000079 }}, /* 1D620; 0079; Additional folding */ { 0x01D621, 0, { 0x00007A }}, /* 1D621; 007A; Additional folding */ { 0x01D63C, 0, { 0x000061 }}, /* 1D63C; 0061; Additional folding */ { 0x01D63D, 0, { 0x000062 }}, /* 1D63D; 0062; Additional folding */ { 0x01D63E, 0, { 0x000063 }}, /* 1D63E; 0063; Additional folding */ { 0x01D63F, 0, { 0x000064 }}, /* 1D63F; 0064; Additional folding */ { 0x01D640, 0, { 0x000065 }}, /* 1D640; 0065; Additional folding */ { 0x01D641, 0, { 0x000066 }}, /* 1D641; 0066; Additional folding */ { 0x01D642, 0, { 0x000067 }}, /* 1D642; 0067; Additional folding */ { 0x01D643, 0, { 0x000068 }}, /* 1D643; 0068; Additional folding */ { 0x01D644, 0, { 0x000069 }}, /* 1D644; 0069; Additional folding */ { 0x01D645, 0, { 0x00006A }}, /* 1D645; 006A; Additional folding */ { 0x01D646, 0, { 0x00006B }}, /* 1D646; 006B; Additional folding */ { 0x01D647, 0, { 0x00006C }}, /* 1D647; 006C; Additional folding */ { 0x01D648, 0, { 0x00006D }}, /* 1D648; 006D; Additional folding */ { 0x01D649, 0, { 0x00006E }}, /* 1D649; 006E; Additional folding */ { 0x01D64A, 0, { 0x00006F }}, /* 1D64A; 006F; Additional folding */ { 0x01D64B, 0, { 0x000070 }}, /* 1D64B; 0070; Additional folding */ { 0x01D64C, 0, { 0x000071 }}, /* 1D64C; 0071; Additional folding */ { 0x01D64D, 0, { 0x000072 }}, /* 1D64D; 0072; Additional folding */ { 0x01D64E, 0, { 0x000073 }}, /* 1D64E; 0073; Additional folding */ { 0x01D64F, 0, { 0x000074 }}, /* 1D64F; 0074; Additional folding */ { 0x01D650, 0, { 0x000075 }}, /* 1D650; 0075; Additional folding */ { 0x01D651, 0, { 0x000076 }}, /* 1D651; 0076; Additional folding */ { 0x01D652, 0, { 0x000077 }}, /* 1D652; 0077; Additional folding */ { 0x01D653, 0, { 0x000078 }}, /* 1D653; 0078; Additional folding */ { 0x01D654, 0, { 0x000079 }}, /* 1D654; 0079; Additional folding */ { 0x01D655, 0, { 0x00007A }}, /* 1D655; 007A; Additional folding */ { 0x01D670, 0, { 0x000061 }}, /* 1D670; 0061; Additional folding */ { 0x01D671, 0, { 0x000062 }}, /* 1D671; 0062; Additional folding */ { 0x01D672, 0, { 0x000063 }}, /* 1D672; 0063; Additional folding */ { 0x01D673, 0, { 0x000064 }}, /* 1D673; 0064; Additional folding */ { 0x01D674, 0, { 0x000065 }}, /* 1D674; 0065; Additional folding */ { 0x01D675, 0, { 0x000066 }}, /* 1D675; 0066; Additional folding */ { 0x01D676, 0, { 0x000067 }}, /* 1D676; 0067; Additional folding */ { 0x01D677, 0, { 0x000068 }}, /* 1D677; 0068; Additional folding */ { 0x01D678, 0, { 0x000069 }}, /* 1D678; 0069; Additional folding */ { 0x01D679, 0, { 0x00006A }}, /* 1D679; 006A; Additional folding */ { 0x01D67A, 0, { 0x00006B }}, /* 1D67A; 006B; Additional folding */ { 0x01D67B, 0, { 0x00006C }}, /* 1D67B; 006C; Additional folding */ { 0x01D67C, 0, { 0x00006D }}, /* 1D67C; 006D; Additional folding */ { 0x01D67D, 0, { 0x00006E }}, /* 1D67D; 006E; Additional folding */ { 0x01D67E, 0, { 0x00006F }}, /* 1D67E; 006F; Additional folding */ { 0x01D67F, 0, { 0x000070 }}, /* 1D67F; 0070; Additional folding */ { 0x01D680, 0, { 0x000071 }}, /* 1D680; 0071; Additional folding */ { 0x01D681, 0, { 0x000072 }}, /* 1D681; 0072; Additional folding */ { 0x01D682, 0, { 0x000073 }}, /* 1D682; 0073; Additional folding */ { 0x01D683, 0, { 0x000074 }}, /* 1D683; 0074; Additional folding */ { 0x01D684, 0, { 0x000075 }}, /* 1D684; 0075; Additional folding */ { 0x01D685, 0, { 0x000076 }}, /* 1D685; 0076; Additional folding */ { 0x01D686, 0, { 0x000077 }}, /* 1D686; 0077; Additional folding */ { 0x01D687, 0, { 0x000078 }}, /* 1D687; 0078; Additional folding */ { 0x01D688, 0, { 0x000079 }}, /* 1D688; 0079; Additional folding */ { 0x01D689, 0, { 0x00007A }}, /* 1D689; 007A; Additional folding */ { 0x01D6A8, 0, { 0x0003B1 }}, /* 1D6A8; 03B1; Additional folding */ { 0x01D6A9, 0, { 0x0003B2 }}, /* 1D6A9; 03B2; Additional folding */ { 0x01D6AA, 0, { 0x0003B3 }}, /* 1D6AA; 03B3; Additional folding */ { 0x01D6AB, 0, { 0x0003B4 }}, /* 1D6AB; 03B4; Additional folding */ { 0x01D6AC, 0, { 0x0003B5 }}, /* 1D6AC; 03B5; Additional folding */ { 0x01D6AD, 0, { 0x0003B6 }}, /* 1D6AD; 03B6; Additional folding */ { 0x01D6AE, 0, { 0x0003B7 }}, /* 1D6AE; 03B7; Additional folding */ { 0x01D6AF, 0, { 0x0003B8 }}, /* 1D6AF; 03B8; Additional folding */ { 0x01D6B0, 0, { 0x0003B9 }}, /* 1D6B0; 03B9; Additional folding */ { 0x01D6B1, 0, { 0x0003BA }}, /* 1D6B1; 03BA; Additional folding */ { 0x01D6B2, 0, { 0x0003BB }}, /* 1D6B2; 03BB; Additional folding */ { 0x01D6B3, 0, { 0x0003BC }}, /* 1D6B3; 03BC; Additional folding */ { 0x01D6B4, 0, { 0x0003BD }}, /* 1D6B4; 03BD; Additional folding */ { 0x01D6B5, 0, { 0x0003BE }}, /* 1D6B5; 03BE; Additional folding */ { 0x01D6B6, 0, { 0x0003BF }}, /* 1D6B6; 03BF; Additional folding */ { 0x01D6B7, 0, { 0x0003C0 }}, /* 1D6B7; 03C0; Additional folding */ { 0x01D6B8, 0, { 0x0003C1 }}, /* 1D6B8; 03C1; Additional folding */ { 0x01D6B9, 0, { 0x0003B8 }}, /* 1D6B9; 03B8; Additional folding */ { 0x01D6BA, 0, { 0x0003C3 }}, /* 1D6BA; 03C3; Additional folding */ { 0x01D6BB, 0, { 0x0003C4 }}, /* 1D6BB; 03C4; Additional folding */ { 0x01D6BC, 0, { 0x0003C5 }}, /* 1D6BC; 03C5; Additional folding */ { 0x01D6BD, 0, { 0x0003C6 }}, /* 1D6BD; 03C6; Additional folding */ { 0x01D6BE, 0, { 0x0003C7 }}, /* 1D6BE; 03C7; Additional folding */ { 0x01D6BF, 0, { 0x0003C8 }}, /* 1D6BF; 03C8; Additional folding */ { 0x01D6C0, 0, { 0x0003C9 }}, /* 1D6C0; 03C9; Additional folding */ { 0x01D6D3, 0, { 0x0003C3 }}, /* 1D6D3; 03C3; Additional folding */ { 0x01D6E2, 0, { 0x0003B1 }}, /* 1D6E2; 03B1; Additional folding */ { 0x01D6E3, 0, { 0x0003B2 }}, /* 1D6E3; 03B2; Additional folding */ { 0x01D6E4, 0, { 0x0003B3 }}, /* 1D6E4; 03B3; Additional folding */ { 0x01D6E5, 0, { 0x0003B4 }}, /* 1D6E5; 03B4; Additional folding */ { 0x01D6E6, 0, { 0x0003B5 }}, /* 1D6E6; 03B5; Additional folding */ { 0x01D6E7, 0, { 0x0003B6 }}, /* 1D6E7; 03B6; Additional folding */ { 0x01D6E8, 0, { 0x0003B7 }}, /* 1D6E8; 03B7; Additional folding */ { 0x01D6E9, 0, { 0x0003B8 }}, /* 1D6E9; 03B8; Additional folding */ { 0x01D6EA, 0, { 0x0003B9 }}, /* 1D6EA; 03B9; Additional folding */ { 0x01D6EB, 0, { 0x0003BA }}, /* 1D6EB; 03BA; Additional folding */ { 0x01D6EC, 0, { 0x0003BB }}, /* 1D6EC; 03BB; Additional folding */ { 0x01D6ED, 0, { 0x0003BC }}, /* 1D6ED; 03BC; Additional folding */ { 0x01D6EE, 0, { 0x0003BD }}, /* 1D6EE; 03BD; Additional folding */ { 0x01D6EF, 0, { 0x0003BE }}, /* 1D6EF; 03BE; Additional folding */ { 0x01D6F0, 0, { 0x0003BF }}, /* 1D6F0; 03BF; Additional folding */ { 0x01D6F1, 0, { 0x0003C0 }}, /* 1D6F1; 03C0; Additional folding */ { 0x01D6F2, 0, { 0x0003C1 }}, /* 1D6F2; 03C1; Additional folding */ { 0x01D6F3, 0, { 0x0003B8 }}, /* 1D6F3; 03B8; Additional folding */ { 0x01D6F4, 0, { 0x0003C3 }}, /* 1D6F4; 03C3; Additional folding */ { 0x01D6F5, 0, { 0x0003C4 }}, /* 1D6F5; 03C4; Additional folding */ { 0x01D6F6, 0, { 0x0003C5 }}, /* 1D6F6; 03C5; Additional folding */ { 0x01D6F7, 0, { 0x0003C6 }}, /* 1D6F7; 03C6; Additional folding */ { 0x01D6F8, 0, { 0x0003C7 }}, /* 1D6F8; 03C7; Additional folding */ { 0x01D6F9, 0, { 0x0003C8 }}, /* 1D6F9; 03C8; Additional folding */ { 0x01D6FA, 0, { 0x0003C9 }}, /* 1D6FA; 03C9; Additional folding */ { 0x01D70D, 0, { 0x0003C3 }}, /* 1D70D; 03C3; Additional folding */ { 0x01D71C, 0, { 0x0003B1 }}, /* 1D71C; 03B1; Additional folding */ { 0x01D71D, 0, { 0x0003B2 }}, /* 1D71D; 03B2; Additional folding */ { 0x01D71E, 0, { 0x0003B3 }}, /* 1D71E; 03B3; Additional folding */ { 0x01D71F, 0, { 0x0003B4 }}, /* 1D71F; 03B4; Additional folding */ { 0x01D720, 0, { 0x0003B5 }}, /* 1D720; 03B5; Additional folding */ { 0x01D721, 0, { 0x0003B6 }}, /* 1D721; 03B6; Additional folding */ { 0x01D722, 0, { 0x0003B7 }}, /* 1D722; 03B7; Additional folding */ { 0x01D723, 0, { 0x0003B8 }}, /* 1D723; 03B8; Additional folding */ { 0x01D724, 0, { 0x0003B9 }}, /* 1D724; 03B9; Additional folding */ { 0x01D725, 0, { 0x0003BA }}, /* 1D725; 03BA; Additional folding */ { 0x01D726, 0, { 0x0003BB }}, /* 1D726; 03BB; Additional folding */ { 0x01D727, 0, { 0x0003BC }}, /* 1D727; 03BC; Additional folding */ { 0x01D728, 0, { 0x0003BD }}, /* 1D728; 03BD; Additional folding */ { 0x01D729, 0, { 0x0003BE }}, /* 1D729; 03BE; Additional folding */ { 0x01D72A, 0, { 0x0003BF }}, /* 1D72A; 03BF; Additional folding */ { 0x01D72B, 0, { 0x0003C0 }}, /* 1D72B; 03C0; Additional folding */ { 0x01D72C, 0, { 0x0003C1 }}, /* 1D72C; 03C1; Additional folding */ { 0x01D72D, 0, { 0x0003B8 }}, /* 1D72D; 03B8; Additional folding */ { 0x01D72E, 0, { 0x0003C3 }}, /* 1D72E; 03C3; Additional folding */ { 0x01D72F, 0, { 0x0003C4 }}, /* 1D72F; 03C4; Additional folding */ { 0x01D730, 0, { 0x0003C5 }}, /* 1D730; 03C5; Additional folding */ { 0x01D731, 0, { 0x0003C6 }}, /* 1D731; 03C6; Additional folding */ { 0x01D732, 0, { 0x0003C7 }}, /* 1D732; 03C7; Additional folding */ { 0x01D733, 0, { 0x0003C8 }}, /* 1D733; 03C8; Additional folding */ { 0x01D734, 0, { 0x0003C9 }}, /* 1D734; 03C9; Additional folding */ { 0x01D747, 0, { 0x0003C3 }}, /* 1D747; 03C3; Additional folding */ { 0x01D756, 0, { 0x0003B1 }}, /* 1D756; 03B1; Additional folding */ { 0x01D757, 0, { 0x0003B2 }}, /* 1D757; 03B2; Additional folding */ { 0x01D758, 0, { 0x0003B3 }}, /* 1D758; 03B3; Additional folding */ { 0x01D759, 0, { 0x0003B4 }}, /* 1D759; 03B4; Additional folding */ { 0x01D75A, 0, { 0x0003B5 }}, /* 1D75A; 03B5; Additional folding */ { 0x01D75B, 0, { 0x0003B6 }}, /* 1D75B; 03B6; Additional folding */ { 0x01D75C, 0, { 0x0003B7 }}, /* 1D75C; 03B7; Additional folding */ { 0x01D75D, 0, { 0x0003B8 }}, /* 1D75D; 03B8; Additional folding */ { 0x01D75E, 0, { 0x0003B9 }}, /* 1D75E; 03B9; Additional folding */ { 0x01D75F, 0, { 0x0003BA }}, /* 1D75F; 03BA; Additional folding */ { 0x01D760, 0, { 0x0003BB }}, /* 1D760; 03BB; Additional folding */ { 0x01D761, 0, { 0x0003BC }}, /* 1D761; 03BC; Additional folding */ { 0x01D762, 0, { 0x0003BD }}, /* 1D762; 03BD; Additional folding */ { 0x01D763, 0, { 0x0003BE }}, /* 1D763; 03BE; Additional folding */ { 0x01D764, 0, { 0x0003BF }}, /* 1D764; 03BF; Additional folding */ { 0x01D765, 0, { 0x0003C0 }}, /* 1D765; 03C0; Additional folding */ { 0x01D766, 0, { 0x0003C1 }}, /* 1D766; 03C1; Additional folding */ { 0x01D767, 0, { 0x0003B8 }}, /* 1D767; 03B8; Additional folding */ { 0x01D768, 0, { 0x0003C3 }}, /* 1D768; 03C3; Additional folding */ { 0x01D769, 0, { 0x0003C4 }}, /* 1D769; 03C4; Additional folding */ { 0x01D76A, 0, { 0x0003C5 }}, /* 1D76A; 03C5; Additional folding */ { 0x01D76B, 0, { 0x0003C6 }}, /* 1D76B; 03C6; Additional folding */ { 0x01D76C, 0, { 0x0003C7 }}, /* 1D76C; 03C7; Additional folding */ { 0x01D76D, 0, { 0x0003C8 }}, /* 1D76D; 03C8; Additional folding */ { 0x01D76E, 0, { 0x0003C9 }}, /* 1D76E; 03C9; Additional folding */ { 0x01D781, 0, { 0x0003C3 }}, /* 1D781; 03C3; Additional folding */ { 0x01D790, 0, { 0x0003B1 }}, /* 1D790; 03B1; Additional folding */ { 0x01D791, 0, { 0x0003B2 }}, /* 1D791; 03B2; Additional folding */ { 0x01D792, 0, { 0x0003B3 }}, /* 1D792; 03B3; Additional folding */ { 0x01D793, 0, { 0x0003B4 }}, /* 1D793; 03B4; Additional folding */ { 0x01D794, 0, { 0x0003B5 }}, /* 1D794; 03B5; Additional folding */ { 0x01D795, 0, { 0x0003B6 }}, /* 1D795; 03B6; Additional folding */ { 0x01D796, 0, { 0x0003B7 }}, /* 1D796; 03B7; Additional folding */ { 0x01D797, 0, { 0x0003B8 }}, /* 1D797; 03B8; Additional folding */ { 0x01D798, 0, { 0x0003B9 }}, /* 1D798; 03B9; Additional folding */ { 0x01D799, 0, { 0x0003BA }}, /* 1D799; 03BA; Additional folding */ { 0x01D79A, 0, { 0x0003BB }}, /* 1D79A; 03BB; Additional folding */ { 0x01D79B, 0, { 0x0003BC }}, /* 1D79B; 03BC; Additional folding */ { 0x01D79C, 0, { 0x0003BD }}, /* 1D79C; 03BD; Additional folding */ { 0x01D79D, 0, { 0x0003BE }}, /* 1D79D; 03BE; Additional folding */ { 0x01D79E, 0, { 0x0003BF }}, /* 1D79E; 03BF; Additional folding */ { 0x01D79F, 0, { 0x0003C0 }}, /* 1D79F; 03C0; Additional folding */ { 0x01D7A0, 0, { 0x0003C1 }}, /* 1D7A0; 03C1; Additional folding */ { 0x01D7A1, 0, { 0x0003B8 }}, /* 1D7A1; 03B8; Additional folding */ { 0x01D7A2, 0, { 0x0003C3 }}, /* 1D7A2; 03C3; Additional folding */ { 0x01D7A3, 0, { 0x0003C4 }}, /* 1D7A3; 03C4; Additional folding */ { 0x01D7A4, 0, { 0x0003C5 }}, /* 1D7A4; 03C5; Additional folding */ { 0x01D7A5, 0, { 0x0003C6 }}, /* 1D7A5; 03C6; Additional folding */ { 0x01D7A6, 0, { 0x0003C7 }}, /* 1D7A6; 03C7; Additional folding */ { 0x01D7A7, 0, { 0x0003C8 }}, /* 1D7A7; 03C8; Additional folding */ { 0x01D7A8, 0, { 0x0003C9 }}, /* 1D7A8; 03C9; Additional folding */ { 0x01D7BB, 0, { 0x0003C3 }}, /* 1D7BB; 03C3; Additional folding */ { 0 }, }; /* * B.3 Mapping for case-folding used with no normalization * */ Stringprep_table_element stringprep_rfc3454_B_3[] = { { 0x000041, 0, { 0x000061 }}, /* 0041; 0061; Case map */ { 0x000042, 0, { 0x000062 }}, /* 0042; 0062; Case map */ { 0x000043, 0, { 0x000063 }}, /* 0043; 0063; Case map */ { 0x000044, 0, { 0x000064 }}, /* 0044; 0064; Case map */ { 0x000045, 0, { 0x000065 }}, /* 0045; 0065; Case map */ { 0x000046, 0, { 0x000066 }}, /* 0046; 0066; Case map */ { 0x000047, 0, { 0x000067 }}, /* 0047; 0067; Case map */ { 0x000048, 0, { 0x000068 }}, /* 0048; 0068; Case map */ { 0x000049, 0, { 0x000069 }}, /* 0049; 0069; Case map */ { 0x00004A, 0, { 0x00006A }}, /* 004A; 006A; Case map */ { 0x00004B, 0, { 0x00006B }}, /* 004B; 006B; Case map */ { 0x00004C, 0, { 0x00006C }}, /* 004C; 006C; Case map */ { 0x00004D, 0, { 0x00006D }}, /* 004D; 006D; Case map */ { 0x00004E, 0, { 0x00006E }}, /* 004E; 006E; Case map */ { 0x00004F, 0, { 0x00006F }}, /* 004F; 006F; Case map */ { 0x000050, 0, { 0x000070 }}, /* 0050; 0070; Case map */ { 0x000051, 0, { 0x000071 }}, /* 0051; 0071; Case map */ { 0x000052, 0, { 0x000072 }}, /* 0052; 0072; Case map */ { 0x000053, 0, { 0x000073 }}, /* 0053; 0073; Case map */ { 0x000054, 0, { 0x000074 }}, /* 0054; 0074; Case map */ { 0x000055, 0, { 0x000075 }}, /* 0055; 0075; Case map */ { 0x000056, 0, { 0x000076 }}, /* 0056; 0076; Case map */ { 0x000057, 0, { 0x000077 }}, /* 0057; 0077; Case map */ { 0x000058, 0, { 0x000078 }}, /* 0058; 0078; Case map */ { 0x000059, 0, { 0x000079 }}, /* 0059; 0079; Case map */ { 0x00005A, 0, { 0x00007A }}, /* 005A; 007A; Case map */ { 0x0000B5, 0, { 0x0003BC }}, /* 00B5; 03BC; Case map */ { 0x0000C0, 0, { 0x0000E0 }}, /* 00C0; 00E0; Case map */ { 0x0000C1, 0, { 0x0000E1 }}, /* 00C1; 00E1; Case map */ { 0x0000C2, 0, { 0x0000E2 }}, /* 00C2; 00E2; Case map */ { 0x0000C3, 0, { 0x0000E3 }}, /* 00C3; 00E3; Case map */ { 0x0000C4, 0, { 0x0000E4 }}, /* 00C4; 00E4; Case map */ { 0x0000C5, 0, { 0x0000E5 }}, /* 00C5; 00E5; Case map */ { 0x0000C6, 0, { 0x0000E6 }}, /* 00C6; 00E6; Case map */ { 0x0000C7, 0, { 0x0000E7 }}, /* 00C7; 00E7; Case map */ { 0x0000C8, 0, { 0x0000E8 }}, /* 00C8; 00E8; Case map */ { 0x0000C9, 0, { 0x0000E9 }}, /* 00C9; 00E9; Case map */ { 0x0000CA, 0, { 0x0000EA }}, /* 00CA; 00EA; Case map */ { 0x0000CB, 0, { 0x0000EB }}, /* 00CB; 00EB; Case map */ { 0x0000CC, 0, { 0x0000EC }}, /* 00CC; 00EC; Case map */ { 0x0000CD, 0, { 0x0000ED }}, /* 00CD; 00ED; Case map */ { 0x0000CE, 0, { 0x0000EE }}, /* 00CE; 00EE; Case map */ { 0x0000CF, 0, { 0x0000EF }}, /* 00CF; 00EF; Case map */ { 0x0000D0, 0, { 0x0000F0 }}, /* 00D0; 00F0; Case map */ { 0x0000D1, 0, { 0x0000F1 }}, /* 00D1; 00F1; Case map */ { 0x0000D2, 0, { 0x0000F2 }}, /* 00D2; 00F2; Case map */ { 0x0000D3, 0, { 0x0000F3 }}, /* 00D3; 00F3; Case map */ { 0x0000D4, 0, { 0x0000F4 }}, /* 00D4; 00F4; Case map */ { 0x0000D5, 0, { 0x0000F5 }}, /* 00D5; 00F5; Case map */ { 0x0000D6, 0, { 0x0000F6 }}, /* 00D6; 00F6; Case map */ { 0x0000D8, 0, { 0x0000F8 }}, /* 00D8; 00F8; Case map */ { 0x0000D9, 0, { 0x0000F9 }}, /* 00D9; 00F9; Case map */ { 0x0000DA, 0, { 0x0000FA }}, /* 00DA; 00FA; Case map */ { 0x0000DB, 0, { 0x0000FB }}, /* 00DB; 00FB; Case map */ { 0x0000DC, 0, { 0x0000FC }}, /* 00DC; 00FC; Case map */ { 0x0000DD, 0, { 0x0000FD }}, /* 00DD; 00FD; Case map */ { 0x0000DE, 0, { 0x0000FE }}, /* 00DE; 00FE; Case map */ { 0x0000DF, 0, { 0x000073, /* 00DF; 0073 0073; Case map */ 0x000073 }}, { 0x000100, 0, { 0x000101 }}, /* 0100; 0101; Case map */ { 0x000102, 0, { 0x000103 }}, /* 0102; 0103; Case map */ { 0x000104, 0, { 0x000105 }}, /* 0104; 0105; Case map */ { 0x000106, 0, { 0x000107 }}, /* 0106; 0107; Case map */ { 0x000108, 0, { 0x000109 }}, /* 0108; 0109; Case map */ { 0x00010A, 0, { 0x00010B }}, /* 010A; 010B; Case map */ { 0x00010C, 0, { 0x00010D }}, /* 010C; 010D; Case map */ { 0x00010E, 0, { 0x00010F }}, /* 010E; 010F; Case map */ { 0x000110, 0, { 0x000111 }}, /* 0110; 0111; Case map */ { 0x000112, 0, { 0x000113 }}, /* 0112; 0113; Case map */ { 0x000114, 0, { 0x000115 }}, /* 0114; 0115; Case map */ { 0x000116, 0, { 0x000117 }}, /* 0116; 0117; Case map */ { 0x000118, 0, { 0x000119 }}, /* 0118; 0119; Case map */ { 0x00011A, 0, { 0x00011B }}, /* 011A; 011B; Case map */ { 0x00011C, 0, { 0x00011D }}, /* 011C; 011D; Case map */ { 0x00011E, 0, { 0x00011F }}, /* 011E; 011F; Case map */ { 0x000120, 0, { 0x000121 }}, /* 0120; 0121; Case map */ { 0x000122, 0, { 0x000123 }}, /* 0122; 0123; Case map */ { 0x000124, 0, { 0x000125 }}, /* 0124; 0125; Case map */ { 0x000126, 0, { 0x000127 }}, /* 0126; 0127; Case map */ { 0x000128, 0, { 0x000129 }}, /* 0128; 0129; Case map */ { 0x00012A, 0, { 0x00012B }}, /* 012A; 012B; Case map */ { 0x00012C, 0, { 0x00012D }}, /* 012C; 012D; Case map */ { 0x00012E, 0, { 0x00012F }}, /* 012E; 012F; Case map */ { 0x000130, 0, { 0x000069, /* 0130; 0069 0307; Case map */ 0x000307 }}, { 0x000132, 0, { 0x000133 }}, /* 0132; 0133; Case map */ { 0x000134, 0, { 0x000135 }}, /* 0134; 0135; Case map */ { 0x000136, 0, { 0x000137 }}, /* 0136; 0137; Case map */ { 0x000139, 0, { 0x00013A }}, /* 0139; 013A; Case map */ { 0x00013B, 0, { 0x00013C }}, /* 013B; 013C; Case map */ { 0x00013D, 0, { 0x00013E }}, /* 013D; 013E; Case map */ { 0x00013F, 0, { 0x000140 }}, /* 013F; 0140; Case map */ { 0x000141, 0, { 0x000142 }}, /* 0141; 0142; Case map */ { 0x000143, 0, { 0x000144 }}, /* 0143; 0144; Case map */ { 0x000145, 0, { 0x000146 }}, /* 0145; 0146; Case map */ { 0x000147, 0, { 0x000148 }}, /* 0147; 0148; Case map */ { 0x000149, 0, { 0x0002BC, /* 0149; 02BC 006E; Case map */ 0x00006E }}, { 0x00014A, 0, { 0x00014B }}, /* 014A; 014B; Case map */ { 0x00014C, 0, { 0x00014D }}, /* 014C; 014D; Case map */ { 0x00014E, 0, { 0x00014F }}, /* 014E; 014F; Case map */ { 0x000150, 0, { 0x000151 }}, /* 0150; 0151; Case map */ { 0x000152, 0, { 0x000153 }}, /* 0152; 0153; Case map */ { 0x000154, 0, { 0x000155 }}, /* 0154; 0155; Case map */ { 0x000156, 0, { 0x000157 }}, /* 0156; 0157; Case map */ { 0x000158, 0, { 0x000159 }}, /* 0158; 0159; Case map */ { 0x00015A, 0, { 0x00015B }}, /* 015A; 015B; Case map */ { 0x00015C, 0, { 0x00015D }}, /* 015C; 015D; Case map */ { 0x00015E, 0, { 0x00015F }}, /* 015E; 015F; Case map */ { 0x000160, 0, { 0x000161 }}, /* 0160; 0161; Case map */ { 0x000162, 0, { 0x000163 }}, /* 0162; 0163; Case map */ { 0x000164, 0, { 0x000165 }}, /* 0164; 0165; Case map */ { 0x000166, 0, { 0x000167 }}, /* 0166; 0167; Case map */ { 0x000168, 0, { 0x000169 }}, /* 0168; 0169; Case map */ { 0x00016A, 0, { 0x00016B }}, /* 016A; 016B; Case map */ { 0x00016C, 0, { 0x00016D }}, /* 016C; 016D; Case map */ { 0x00016E, 0, { 0x00016F }}, /* 016E; 016F; Case map */ { 0x000170, 0, { 0x000171 }}, /* 0170; 0171; Case map */ { 0x000172, 0, { 0x000173 }}, /* 0172; 0173; Case map */ { 0x000174, 0, { 0x000175 }}, /* 0174; 0175; Case map */ { 0x000176, 0, { 0x000177 }}, /* 0176; 0177; Case map */ { 0x000178, 0, { 0x0000FF }}, /* 0178; 00FF; Case map */ { 0x000179, 0, { 0x00017A }}, /* 0179; 017A; Case map */ { 0x00017B, 0, { 0x00017C }}, /* 017B; 017C; Case map */ { 0x00017D, 0, { 0x00017E }}, /* 017D; 017E; Case map */ { 0x00017F, 0, { 0x000073 }}, /* 017F; 0073; Case map */ { 0x000181, 0, { 0x000253 }}, /* 0181; 0253; Case map */ { 0x000182, 0, { 0x000183 }}, /* 0182; 0183; Case map */ { 0x000184, 0, { 0x000185 }}, /* 0184; 0185; Case map */ { 0x000186, 0, { 0x000254 }}, /* 0186; 0254; Case map */ { 0x000187, 0, { 0x000188 }}, /* 0187; 0188; Case map */ { 0x000189, 0, { 0x000256 }}, /* 0189; 0256; Case map */ { 0x00018A, 0, { 0x000257 }}, /* 018A; 0257; Case map */ { 0x00018B, 0, { 0x00018C }}, /* 018B; 018C; Case map */ { 0x00018E, 0, { 0x0001DD }}, /* 018E; 01DD; Case map */ { 0x00018F, 0, { 0x000259 }}, /* 018F; 0259; Case map */ { 0x000190, 0, { 0x00025B }}, /* 0190; 025B; Case map */ { 0x000191, 0, { 0x000192 }}, /* 0191; 0192; Case map */ { 0x000193, 0, { 0x000260 }}, /* 0193; 0260; Case map */ { 0x000194, 0, { 0x000263 }}, /* 0194; 0263; Case map */ { 0x000196, 0, { 0x000269 }}, /* 0196; 0269; Case map */ { 0x000197, 0, { 0x000268 }}, /* 0197; 0268; Case map */ { 0x000198, 0, { 0x000199 }}, /* 0198; 0199; Case map */ { 0x00019C, 0, { 0x00026F }}, /* 019C; 026F; Case map */ { 0x00019D, 0, { 0x000272 }}, /* 019D; 0272; Case map */ { 0x00019F, 0, { 0x000275 }}, /* 019F; 0275; Case map */ { 0x0001A0, 0, { 0x0001A1 }}, /* 01A0; 01A1; Case map */ { 0x0001A2, 0, { 0x0001A3 }}, /* 01A2; 01A3; Case map */ { 0x0001A4, 0, { 0x0001A5 }}, /* 01A4; 01A5; Case map */ { 0x0001A6, 0, { 0x000280 }}, /* 01A6; 0280; Case map */ { 0x0001A7, 0, { 0x0001A8 }}, /* 01A7; 01A8; Case map */ { 0x0001A9, 0, { 0x000283 }}, /* 01A9; 0283; Case map */ { 0x0001AC, 0, { 0x0001AD }}, /* 01AC; 01AD; Case map */ { 0x0001AE, 0, { 0x000288 }}, /* 01AE; 0288; Case map */ { 0x0001AF, 0, { 0x0001B0 }}, /* 01AF; 01B0; Case map */ { 0x0001B1, 0, { 0x00028A }}, /* 01B1; 028A; Case map */ { 0x0001B2, 0, { 0x00028B }}, /* 01B2; 028B; Case map */ { 0x0001B3, 0, { 0x0001B4 }}, /* 01B3; 01B4; Case map */ { 0x0001B5, 0, { 0x0001B6 }}, /* 01B5; 01B6; Case map */ { 0x0001B7, 0, { 0x000292 }}, /* 01B7; 0292; Case map */ { 0x0001B8, 0, { 0x0001B9 }}, /* 01B8; 01B9; Case map */ { 0x0001BC, 0, { 0x0001BD }}, /* 01BC; 01BD; Case map */ { 0x0001C4, 0, { 0x0001C6 }}, /* 01C4; 01C6; Case map */ { 0x0001C5, 0, { 0x0001C6 }}, /* 01C5; 01C6; Case map */ { 0x0001C7, 0, { 0x0001C9 }}, /* 01C7; 01C9; Case map */ { 0x0001C8, 0, { 0x0001C9 }}, /* 01C8; 01C9; Case map */ { 0x0001CA, 0, { 0x0001CC }}, /* 01CA; 01CC; Case map */ { 0x0001CB, 0, { 0x0001CC }}, /* 01CB; 01CC; Case map */ { 0x0001CD, 0, { 0x0001CE }}, /* 01CD; 01CE; Case map */ { 0x0001CF, 0, { 0x0001D0 }}, /* 01CF; 01D0; Case map */ { 0x0001D1, 0, { 0x0001D2 }}, /* 01D1; 01D2; Case map */ { 0x0001D3, 0, { 0x0001D4 }}, /* 01D3; 01D4; Case map */ { 0x0001D5, 0, { 0x0001D6 }}, /* 01D5; 01D6; Case map */ { 0x0001D7, 0, { 0x0001D8 }}, /* 01D7; 01D8; Case map */ { 0x0001D9, 0, { 0x0001DA }}, /* 01D9; 01DA; Case map */ { 0x0001DB, 0, { 0x0001DC }}, /* 01DB; 01DC; Case map */ { 0x0001DE, 0, { 0x0001DF }}, /* 01DE; 01DF; Case map */ { 0x0001E0, 0, { 0x0001E1 }}, /* 01E0; 01E1; Case map */ { 0x0001E2, 0, { 0x0001E3 }}, /* 01E2; 01E3; Case map */ { 0x0001E4, 0, { 0x0001E5 }}, /* 01E4; 01E5; Case map */ { 0x0001E6, 0, { 0x0001E7 }}, /* 01E6; 01E7; Case map */ { 0x0001E8, 0, { 0x0001E9 }}, /* 01E8; 01E9; Case map */ { 0x0001EA, 0, { 0x0001EB }}, /* 01EA; 01EB; Case map */ { 0x0001EC, 0, { 0x0001ED }}, /* 01EC; 01ED; Case map */ { 0x0001EE, 0, { 0x0001EF }}, /* 01EE; 01EF; Case map */ { 0x0001F0, 0, { 0x00006A, /* 01F0; 006A 030C; Case map */ 0x00030C }}, { 0x0001F1, 0, { 0x0001F3 }}, /* 01F1; 01F3; Case map */ { 0x0001F2, 0, { 0x0001F3 }}, /* 01F2; 01F3; Case map */ { 0x0001F4, 0, { 0x0001F5 }}, /* 01F4; 01F5; Case map */ { 0x0001F6, 0, { 0x000195 }}, /* 01F6; 0195; Case map */ { 0x0001F7, 0, { 0x0001BF }}, /* 01F7; 01BF; Case map */ { 0x0001F8, 0, { 0x0001F9 }}, /* 01F8; 01F9; Case map */ { 0x0001FA, 0, { 0x0001FB }}, /* 01FA; 01FB; Case map */ { 0x0001FC, 0, { 0x0001FD }}, /* 01FC; 01FD; Case map */ { 0x0001FE, 0, { 0x0001FF }}, /* 01FE; 01FF; Case map */ { 0x000200, 0, { 0x000201 }}, /* 0200; 0201; Case map */ { 0x000202, 0, { 0x000203 }}, /* 0202; 0203; Case map */ { 0x000204, 0, { 0x000205 }}, /* 0204; 0205; Case map */ { 0x000206, 0, { 0x000207 }}, /* 0206; 0207; Case map */ { 0x000208, 0, { 0x000209 }}, /* 0208; 0209; Case map */ { 0x00020A, 0, { 0x00020B }}, /* 020A; 020B; Case map */ { 0x00020C, 0, { 0x00020D }}, /* 020C; 020D; Case map */ { 0x00020E, 0, { 0x00020F }}, /* 020E; 020F; Case map */ { 0x000210, 0, { 0x000211 }}, /* 0210; 0211; Case map */ { 0x000212, 0, { 0x000213 }}, /* 0212; 0213; Case map */ { 0x000214, 0, { 0x000215 }}, /* 0214; 0215; Case map */ { 0x000216, 0, { 0x000217 }}, /* 0216; 0217; Case map */ { 0x000218, 0, { 0x000219 }}, /* 0218; 0219; Case map */ { 0x00021A, 0, { 0x00021B }}, /* 021A; 021B; Case map */ { 0x00021C, 0, { 0x00021D }}, /* 021C; 021D; Case map */ { 0x00021E, 0, { 0x00021F }}, /* 021E; 021F; Case map */ { 0x000220, 0, { 0x00019E }}, /* 0220; 019E; Case map */ { 0x000222, 0, { 0x000223 }}, /* 0222; 0223; Case map */ { 0x000224, 0, { 0x000225 }}, /* 0224; 0225; Case map */ { 0x000226, 0, { 0x000227 }}, /* 0226; 0227; Case map */ { 0x000228, 0, { 0x000229 }}, /* 0228; 0229; Case map */ { 0x00022A, 0, { 0x00022B }}, /* 022A; 022B; Case map */ { 0x00022C, 0, { 0x00022D }}, /* 022C; 022D; Case map */ { 0x00022E, 0, { 0x00022F }}, /* 022E; 022F; Case map */ { 0x000230, 0, { 0x000231 }}, /* 0230; 0231; Case map */ { 0x000232, 0, { 0x000233 }}, /* 0232; 0233; Case map */ { 0x000345, 0, { 0x0003B9 }}, /* 0345; 03B9; Case map */ { 0x000386, 0, { 0x0003AC }}, /* 0386; 03AC; Case map */ { 0x000388, 0, { 0x0003AD }}, /* 0388; 03AD; Case map */ { 0x000389, 0, { 0x0003AE }}, /* 0389; 03AE; Case map */ { 0x00038A, 0, { 0x0003AF }}, /* 038A; 03AF; Case map */ { 0x00038C, 0, { 0x0003CC }}, /* 038C; 03CC; Case map */ { 0x00038E, 0, { 0x0003CD }}, /* 038E; 03CD; Case map */ { 0x00038F, 0, { 0x0003CE }}, /* 038F; 03CE; Case map */ { 0x000390, 0, { 0x0003B9, /* 0390; 03B9 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x000391, 0, { 0x0003B1 }}, /* 0391; 03B1; Case map */ { 0x000392, 0, { 0x0003B2 }}, /* 0392; 03B2; Case map */ { 0x000393, 0, { 0x0003B3 }}, /* 0393; 03B3; Case map */ { 0x000394, 0, { 0x0003B4 }}, /* 0394; 03B4; Case map */ { 0x000395, 0, { 0x0003B5 }}, /* 0395; 03B5; Case map */ { 0x000396, 0, { 0x0003B6 }}, /* 0396; 03B6; Case map */ { 0x000397, 0, { 0x0003B7 }}, /* 0397; 03B7; Case map */ { 0x000398, 0, { 0x0003B8 }}, /* 0398; 03B8; Case map */ { 0x000399, 0, { 0x0003B9 }}, /* 0399; 03B9; Case map */ { 0x00039A, 0, { 0x0003BA }}, /* 039A; 03BA; Case map */ { 0x00039B, 0, { 0x0003BB }}, /* 039B; 03BB; Case map */ { 0x00039C, 0, { 0x0003BC }}, /* 039C; 03BC; Case map */ { 0x00039D, 0, { 0x0003BD }}, /* 039D; 03BD; Case map */ { 0x00039E, 0, { 0x0003BE }}, /* 039E; 03BE; Case map */ { 0x00039F, 0, { 0x0003BF }}, /* 039F; 03BF; Case map */ { 0x0003A0, 0, { 0x0003C0 }}, /* 03A0; 03C0; Case map */ { 0x0003A1, 0, { 0x0003C1 }}, /* 03A1; 03C1; Case map */ { 0x0003A3, 0, { 0x0003C3 }}, /* 03A3; 03C3; Case map */ { 0x0003A4, 0, { 0x0003C4 }}, /* 03A4; 03C4; Case map */ { 0x0003A5, 0, { 0x0003C5 }}, /* 03A5; 03C5; Case map */ { 0x0003A6, 0, { 0x0003C6 }}, /* 03A6; 03C6; Case map */ { 0x0003A7, 0, { 0x0003C7 }}, /* 03A7; 03C7; Case map */ { 0x0003A8, 0, { 0x0003C8 }}, /* 03A8; 03C8; Case map */ { 0x0003A9, 0, { 0x0003C9 }}, /* 03A9; 03C9; Case map */ { 0x0003AA, 0, { 0x0003CA }}, /* 03AA; 03CA; Case map */ { 0x0003AB, 0, { 0x0003CB }}, /* 03AB; 03CB; Case map */ { 0x0003B0, 0, { 0x0003C5, /* 03B0; 03C5 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x0003C2, 0, { 0x0003C3 }}, /* 03C2; 03C3; Case map */ { 0x0003D0, 0, { 0x0003B2 }}, /* 03D0; 03B2; Case map */ { 0x0003D1, 0, { 0x0003B8 }}, /* 03D1; 03B8; Case map */ { 0x0003D5, 0, { 0x0003C6 }}, /* 03D5; 03C6; Case map */ { 0x0003D6, 0, { 0x0003C0 }}, /* 03D6; 03C0; Case map */ { 0x0003D8, 0, { 0x0003D9 }}, /* 03D8; 03D9; Case map */ { 0x0003DA, 0, { 0x0003DB }}, /* 03DA; 03DB; Case map */ { 0x0003DC, 0, { 0x0003DD }}, /* 03DC; 03DD; Case map */ { 0x0003DE, 0, { 0x0003DF }}, /* 03DE; 03DF; Case map */ { 0x0003E0, 0, { 0x0003E1 }}, /* 03E0; 03E1; Case map */ { 0x0003E2, 0, { 0x0003E3 }}, /* 03E2; 03E3; Case map */ { 0x0003E4, 0, { 0x0003E5 }}, /* 03E4; 03E5; Case map */ { 0x0003E6, 0, { 0x0003E7 }}, /* 03E6; 03E7; Case map */ { 0x0003E8, 0, { 0x0003E9 }}, /* 03E8; 03E9; Case map */ { 0x0003EA, 0, { 0x0003EB }}, /* 03EA; 03EB; Case map */ { 0x0003EC, 0, { 0x0003ED }}, /* 03EC; 03ED; Case map */ { 0x0003EE, 0, { 0x0003EF }}, /* 03EE; 03EF; Case map */ { 0x0003F0, 0, { 0x0003BA }}, /* 03F0; 03BA; Case map */ { 0x0003F1, 0, { 0x0003C1 }}, /* 03F1; 03C1; Case map */ { 0x0003F2, 0, { 0x0003C3 }}, /* 03F2; 03C3; Case map */ { 0x0003F4, 0, { 0x0003B8 }}, /* 03F4; 03B8; Case map */ { 0x0003F5, 0, { 0x0003B5 }}, /* 03F5; 03B5; Case map */ { 0x000400, 0, { 0x000450 }}, /* 0400; 0450; Case map */ { 0x000401, 0, { 0x000451 }}, /* 0401; 0451; Case map */ { 0x000402, 0, { 0x000452 }}, /* 0402; 0452; Case map */ { 0x000403, 0, { 0x000453 }}, /* 0403; 0453; Case map */ { 0x000404, 0, { 0x000454 }}, /* 0404; 0454; Case map */ { 0x000405, 0, { 0x000455 }}, /* 0405; 0455; Case map */ { 0x000406, 0, { 0x000456 }}, /* 0406; 0456; Case map */ { 0x000407, 0, { 0x000457 }}, /* 0407; 0457; Case map */ { 0x000408, 0, { 0x000458 }}, /* 0408; 0458; Case map */ { 0x000409, 0, { 0x000459 }}, /* 0409; 0459; Case map */ { 0x00040A, 0, { 0x00045A }}, /* 040A; 045A; Case map */ { 0x00040B, 0, { 0x00045B }}, /* 040B; 045B; Case map */ { 0x00040C, 0, { 0x00045C }}, /* 040C; 045C; Case map */ { 0x00040D, 0, { 0x00045D }}, /* 040D; 045D; Case map */ { 0x00040E, 0, { 0x00045E }}, /* 040E; 045E; Case map */ { 0x00040F, 0, { 0x00045F }}, /* 040F; 045F; Case map */ { 0x000410, 0, { 0x000430 }}, /* 0410; 0430; Case map */ { 0x000411, 0, { 0x000431 }}, /* 0411; 0431; Case map */ { 0x000412, 0, { 0x000432 }}, /* 0412; 0432; Case map */ { 0x000413, 0, { 0x000433 }}, /* 0413; 0433; Case map */ { 0x000414, 0, { 0x000434 }}, /* 0414; 0434; Case map */ { 0x000415, 0, { 0x000435 }}, /* 0415; 0435; Case map */ { 0x000416, 0, { 0x000436 }}, /* 0416; 0436; Case map */ { 0x000417, 0, { 0x000437 }}, /* 0417; 0437; Case map */ { 0x000418, 0, { 0x000438 }}, /* 0418; 0438; Case map */ { 0x000419, 0, { 0x000439 }}, /* 0419; 0439; Case map */ { 0x00041A, 0, { 0x00043A }}, /* 041A; 043A; Case map */ { 0x00041B, 0, { 0x00043B }}, /* 041B; 043B; Case map */ { 0x00041C, 0, { 0x00043C }}, /* 041C; 043C; Case map */ { 0x00041D, 0, { 0x00043D }}, /* 041D; 043D; Case map */ { 0x00041E, 0, { 0x00043E }}, /* 041E; 043E; Case map */ { 0x00041F, 0, { 0x00043F }}, /* 041F; 043F; Case map */ { 0x000420, 0, { 0x000440 }}, /* 0420; 0440; Case map */ { 0x000421, 0, { 0x000441 }}, /* 0421; 0441; Case map */ { 0x000422, 0, { 0x000442 }}, /* 0422; 0442; Case map */ { 0x000423, 0, { 0x000443 }}, /* 0423; 0443; Case map */ { 0x000424, 0, { 0x000444 }}, /* 0424; 0444; Case map */ { 0x000425, 0, { 0x000445 }}, /* 0425; 0445; Case map */ { 0x000426, 0, { 0x000446 }}, /* 0426; 0446; Case map */ { 0x000427, 0, { 0x000447 }}, /* 0427; 0447; Case map */ { 0x000428, 0, { 0x000448 }}, /* 0428; 0448; Case map */ { 0x000429, 0, { 0x000449 }}, /* 0429; 0449; Case map */ { 0x00042A, 0, { 0x00044A }}, /* 042A; 044A; Case map */ { 0x00042B, 0, { 0x00044B }}, /* 042B; 044B; Case map */ { 0x00042C, 0, { 0x00044C }}, /* 042C; 044C; Case map */ { 0x00042D, 0, { 0x00044D }}, /* 042D; 044D; Case map */ { 0x00042E, 0, { 0x00044E }}, /* 042E; 044E; Case map */ { 0x00042F, 0, { 0x00044F }}, /* 042F; 044F; Case map */ { 0x000460, 0, { 0x000461 }}, /* 0460; 0461; Case map */ { 0x000462, 0, { 0x000463 }}, /* 0462; 0463; Case map */ { 0x000464, 0, { 0x000465 }}, /* 0464; 0465; Case map */ { 0x000466, 0, { 0x000467 }}, /* 0466; 0467; Case map */ { 0x000468, 0, { 0x000469 }}, /* 0468; 0469; Case map */ { 0x00046A, 0, { 0x00046B }}, /* 046A; 046B; Case map */ { 0x00046C, 0, { 0x00046D }}, /* 046C; 046D; Case map */ { 0x00046E, 0, { 0x00046F }}, /* 046E; 046F; Case map */ { 0x000470, 0, { 0x000471 }}, /* 0470; 0471; Case map */ { 0x000472, 0, { 0x000473 }}, /* 0472; 0473; Case map */ { 0x000474, 0, { 0x000475 }}, /* 0474; 0475; Case map */ { 0x000476, 0, { 0x000477 }}, /* 0476; 0477; Case map */ { 0x000478, 0, { 0x000479 }}, /* 0478; 0479; Case map */ { 0x00047A, 0, { 0x00047B }}, /* 047A; 047B; Case map */ { 0x00047C, 0, { 0x00047D }}, /* 047C; 047D; Case map */ { 0x00047E, 0, { 0x00047F }}, /* 047E; 047F; Case map */ { 0x000480, 0, { 0x000481 }}, /* 0480; 0481; Case map */ { 0x00048A, 0, { 0x00048B }}, /* 048A; 048B; Case map */ { 0x00048C, 0, { 0x00048D }}, /* 048C; 048D; Case map */ { 0x00048E, 0, { 0x00048F }}, /* 048E; 048F; Case map */ { 0x000490, 0, { 0x000491 }}, /* 0490; 0491; Case map */ { 0x000492, 0, { 0x000493 }}, /* 0492; 0493; Case map */ { 0x000494, 0, { 0x000495 }}, /* 0494; 0495; Case map */ { 0x000496, 0, { 0x000497 }}, /* 0496; 0497; Case map */ { 0x000498, 0, { 0x000499 }}, /* 0498; 0499; Case map */ { 0x00049A, 0, { 0x00049B }}, /* 049A; 049B; Case map */ { 0x00049C, 0, { 0x00049D }}, /* 049C; 049D; Case map */ { 0x00049E, 0, { 0x00049F }}, /* 049E; 049F; Case map */ { 0x0004A0, 0, { 0x0004A1 }}, /* 04A0; 04A1; Case map */ { 0x0004A2, 0, { 0x0004A3 }}, /* 04A2; 04A3; Case map */ { 0x0004A4, 0, { 0x0004A5 }}, /* 04A4; 04A5; Case map */ { 0x0004A6, 0, { 0x0004A7 }}, /* 04A6; 04A7; Case map */ { 0x0004A8, 0, { 0x0004A9 }}, /* 04A8; 04A9; Case map */ { 0x0004AA, 0, { 0x0004AB }}, /* 04AA; 04AB; Case map */ { 0x0004AC, 0, { 0x0004AD }}, /* 04AC; 04AD; Case map */ { 0x0004AE, 0, { 0x0004AF }}, /* 04AE; 04AF; Case map */ { 0x0004B0, 0, { 0x0004B1 }}, /* 04B0; 04B1; Case map */ { 0x0004B2, 0, { 0x0004B3 }}, /* 04B2; 04B3; Case map */ { 0x0004B4, 0, { 0x0004B5 }}, /* 04B4; 04B5; Case map */ { 0x0004B6, 0, { 0x0004B7 }}, /* 04B6; 04B7; Case map */ { 0x0004B8, 0, { 0x0004B9 }}, /* 04B8; 04B9; Case map */ { 0x0004BA, 0, { 0x0004BB }}, /* 04BA; 04BB; Case map */ { 0x0004BC, 0, { 0x0004BD }}, /* 04BC; 04BD; Case map */ { 0x0004BE, 0, { 0x0004BF }}, /* 04BE; 04BF; Case map */ { 0x0004C1, 0, { 0x0004C2 }}, /* 04C1; 04C2; Case map */ { 0x0004C3, 0, { 0x0004C4 }}, /* 04C3; 04C4; Case map */ { 0x0004C5, 0, { 0x0004C6 }}, /* 04C5; 04C6; Case map */ { 0x0004C7, 0, { 0x0004C8 }}, /* 04C7; 04C8; Case map */ { 0x0004C9, 0, { 0x0004CA }}, /* 04C9; 04CA; Case map */ { 0x0004CB, 0, { 0x0004CC }}, /* 04CB; 04CC; Case map */ { 0x0004CD, 0, { 0x0004CE }}, /* 04CD; 04CE; Case map */ { 0x0004D0, 0, { 0x0004D1 }}, /* 04D0; 04D1; Case map */ { 0x0004D2, 0, { 0x0004D3 }}, /* 04D2; 04D3; Case map */ { 0x0004D4, 0, { 0x0004D5 }}, /* 04D4; 04D5; Case map */ { 0x0004D6, 0, { 0x0004D7 }}, /* 04D6; 04D7; Case map */ { 0x0004D8, 0, { 0x0004D9 }}, /* 04D8; 04D9; Case map */ { 0x0004DA, 0, { 0x0004DB }}, /* 04DA; 04DB; Case map */ { 0x0004DC, 0, { 0x0004DD }}, /* 04DC; 04DD; Case map */ { 0x0004DE, 0, { 0x0004DF }}, /* 04DE; 04DF; Case map */ { 0x0004E0, 0, { 0x0004E1 }}, /* 04E0; 04E1; Case map */ { 0x0004E2, 0, { 0x0004E3 }}, /* 04E2; 04E3; Case map */ { 0x0004E4, 0, { 0x0004E5 }}, /* 04E4; 04E5; Case map */ { 0x0004E6, 0, { 0x0004E7 }}, /* 04E6; 04E7; Case map */ { 0x0004E8, 0, { 0x0004E9 }}, /* 04E8; 04E9; Case map */ { 0x0004EA, 0, { 0x0004EB }}, /* 04EA; 04EB; Case map */ { 0x0004EC, 0, { 0x0004ED }}, /* 04EC; 04ED; Case map */ { 0x0004EE, 0, { 0x0004EF }}, /* 04EE; 04EF; Case map */ { 0x0004F0, 0, { 0x0004F1 }}, /* 04F0; 04F1; Case map */ { 0x0004F2, 0, { 0x0004F3 }}, /* 04F2; 04F3; Case map */ { 0x0004F4, 0, { 0x0004F5 }}, /* 04F4; 04F5; Case map */ { 0x0004F8, 0, { 0x0004F9 }}, /* 04F8; 04F9; Case map */ { 0x000500, 0, { 0x000501 }}, /* 0500; 0501; Case map */ { 0x000502, 0, { 0x000503 }}, /* 0502; 0503; Case map */ { 0x000504, 0, { 0x000505 }}, /* 0504; 0505; Case map */ { 0x000506, 0, { 0x000507 }}, /* 0506; 0507; Case map */ { 0x000508, 0, { 0x000509 }}, /* 0508; 0509; Case map */ { 0x00050A, 0, { 0x00050B }}, /* 050A; 050B; Case map */ { 0x00050C, 0, { 0x00050D }}, /* 050C; 050D; Case map */ { 0x00050E, 0, { 0x00050F }}, /* 050E; 050F; Case map */ { 0x000531, 0, { 0x000561 }}, /* 0531; 0561; Case map */ { 0x000532, 0, { 0x000562 }}, /* 0532; 0562; Case map */ { 0x000533, 0, { 0x000563 }}, /* 0533; 0563; Case map */ { 0x000534, 0, { 0x000564 }}, /* 0534; 0564; Case map */ { 0x000535, 0, { 0x000565 }}, /* 0535; 0565; Case map */ { 0x000536, 0, { 0x000566 }}, /* 0536; 0566; Case map */ { 0x000537, 0, { 0x000567 }}, /* 0537; 0567; Case map */ { 0x000538, 0, { 0x000568 }}, /* 0538; 0568; Case map */ { 0x000539, 0, { 0x000569 }}, /* 0539; 0569; Case map */ { 0x00053A, 0, { 0x00056A }}, /* 053A; 056A; Case map */ { 0x00053B, 0, { 0x00056B }}, /* 053B; 056B; Case map */ { 0x00053C, 0, { 0x00056C }}, /* 053C; 056C; Case map */ { 0x00053D, 0, { 0x00056D }}, /* 053D; 056D; Case map */ { 0x00053E, 0, { 0x00056E }}, /* 053E; 056E; Case map */ { 0x00053F, 0, { 0x00056F }}, /* 053F; 056F; Case map */ { 0x000540, 0, { 0x000570 }}, /* 0540; 0570; Case map */ { 0x000541, 0, { 0x000571 }}, /* 0541; 0571; Case map */ { 0x000542, 0, { 0x000572 }}, /* 0542; 0572; Case map */ { 0x000543, 0, { 0x000573 }}, /* 0543; 0573; Case map */ { 0x000544, 0, { 0x000574 }}, /* 0544; 0574; Case map */ { 0x000545, 0, { 0x000575 }}, /* 0545; 0575; Case map */ { 0x000546, 0, { 0x000576 }}, /* 0546; 0576; Case map */ { 0x000547, 0, { 0x000577 }}, /* 0547; 0577; Case map */ { 0x000548, 0, { 0x000578 }}, /* 0548; 0578; Case map */ { 0x000549, 0, { 0x000579 }}, /* 0549; 0579; Case map */ { 0x00054A, 0, { 0x00057A }}, /* 054A; 057A; Case map */ { 0x00054B, 0, { 0x00057B }}, /* 054B; 057B; Case map */ { 0x00054C, 0, { 0x00057C }}, /* 054C; 057C; Case map */ { 0x00054D, 0, { 0x00057D }}, /* 054D; 057D; Case map */ { 0x00054E, 0, { 0x00057E }}, /* 054E; 057E; Case map */ { 0x00054F, 0, { 0x00057F }}, /* 054F; 057F; Case map */ { 0x000550, 0, { 0x000580 }}, /* 0550; 0580; Case map */ { 0x000551, 0, { 0x000581 }}, /* 0551; 0581; Case map */ { 0x000552, 0, { 0x000582 }}, /* 0552; 0582; Case map */ { 0x000553, 0, { 0x000583 }}, /* 0553; 0583; Case map */ { 0x000554, 0, { 0x000584 }}, /* 0554; 0584; Case map */ { 0x000555, 0, { 0x000585 }}, /* 0555; 0585; Case map */ { 0x000556, 0, { 0x000586 }}, /* 0556; 0586; Case map */ { 0x000587, 0, { 0x000565, /* 0587; 0565 0582; Case map */ 0x000582 }}, { 0x001E00, 0, { 0x001E01 }}, /* 1E00; 1E01; Case map */ { 0x001E02, 0, { 0x001E03 }}, /* 1E02; 1E03; Case map */ { 0x001E04, 0, { 0x001E05 }}, /* 1E04; 1E05; Case map */ { 0x001E06, 0, { 0x001E07 }}, /* 1E06; 1E07; Case map */ { 0x001E08, 0, { 0x001E09 }}, /* 1E08; 1E09; Case map */ { 0x001E0A, 0, { 0x001E0B }}, /* 1E0A; 1E0B; Case map */ { 0x001E0C, 0, { 0x001E0D }}, /* 1E0C; 1E0D; Case map */ { 0x001E0E, 0, { 0x001E0F }}, /* 1E0E; 1E0F; Case map */ { 0x001E10, 0, { 0x001E11 }}, /* 1E10; 1E11; Case map */ { 0x001E12, 0, { 0x001E13 }}, /* 1E12; 1E13; Case map */ { 0x001E14, 0, { 0x001E15 }}, /* 1E14; 1E15; Case map */ { 0x001E16, 0, { 0x001E17 }}, /* 1E16; 1E17; Case map */ { 0x001E18, 0, { 0x001E19 }}, /* 1E18; 1E19; Case map */ { 0x001E1A, 0, { 0x001E1B }}, /* 1E1A; 1E1B; Case map */ { 0x001E1C, 0, { 0x001E1D }}, /* 1E1C; 1E1D; Case map */ { 0x001E1E, 0, { 0x001E1F }}, /* 1E1E; 1E1F; Case map */ { 0x001E20, 0, { 0x001E21 }}, /* 1E20; 1E21; Case map */ { 0x001E22, 0, { 0x001E23 }}, /* 1E22; 1E23; Case map */ { 0x001E24, 0, { 0x001E25 }}, /* 1E24; 1E25; Case map */ { 0x001E26, 0, { 0x001E27 }}, /* 1E26; 1E27; Case map */ { 0x001E28, 0, { 0x001E29 }}, /* 1E28; 1E29; Case map */ { 0x001E2A, 0, { 0x001E2B }}, /* 1E2A; 1E2B; Case map */ { 0x001E2C, 0, { 0x001E2D }}, /* 1E2C; 1E2D; Case map */ { 0x001E2E, 0, { 0x001E2F }}, /* 1E2E; 1E2F; Case map */ { 0x001E30, 0, { 0x001E31 }}, /* 1E30; 1E31; Case map */ { 0x001E32, 0, { 0x001E33 }}, /* 1E32; 1E33; Case map */ { 0x001E34, 0, { 0x001E35 }}, /* 1E34; 1E35; Case map */ { 0x001E36, 0, { 0x001E37 }}, /* 1E36; 1E37; Case map */ { 0x001E38, 0, { 0x001E39 }}, /* 1E38; 1E39; Case map */ { 0x001E3A, 0, { 0x001E3B }}, /* 1E3A; 1E3B; Case map */ { 0x001E3C, 0, { 0x001E3D }}, /* 1E3C; 1E3D; Case map */ { 0x001E3E, 0, { 0x001E3F }}, /* 1E3E; 1E3F; Case map */ { 0x001E40, 0, { 0x001E41 }}, /* 1E40; 1E41; Case map */ { 0x001E42, 0, { 0x001E43 }}, /* 1E42; 1E43; Case map */ { 0x001E44, 0, { 0x001E45 }}, /* 1E44; 1E45; Case map */ { 0x001E46, 0, { 0x001E47 }}, /* 1E46; 1E47; Case map */ { 0x001E48, 0, { 0x001E49 }}, /* 1E48; 1E49; Case map */ { 0x001E4A, 0, { 0x001E4B }}, /* 1E4A; 1E4B; Case map */ { 0x001E4C, 0, { 0x001E4D }}, /* 1E4C; 1E4D; Case map */ { 0x001E4E, 0, { 0x001E4F }}, /* 1E4E; 1E4F; Case map */ { 0x001E50, 0, { 0x001E51 }}, /* 1E50; 1E51; Case map */ { 0x001E52, 0, { 0x001E53 }}, /* 1E52; 1E53; Case map */ { 0x001E54, 0, { 0x001E55 }}, /* 1E54; 1E55; Case map */ { 0x001E56, 0, { 0x001E57 }}, /* 1E56; 1E57; Case map */ { 0x001E58, 0, { 0x001E59 }}, /* 1E58; 1E59; Case map */ { 0x001E5A, 0, { 0x001E5B }}, /* 1E5A; 1E5B; Case map */ { 0x001E5C, 0, { 0x001E5D }}, /* 1E5C; 1E5D; Case map */ { 0x001E5E, 0, { 0x001E5F }}, /* 1E5E; 1E5F; Case map */ { 0x001E60, 0, { 0x001E61 }}, /* 1E60; 1E61; Case map */ { 0x001E62, 0, { 0x001E63 }}, /* 1E62; 1E63; Case map */ { 0x001E64, 0, { 0x001E65 }}, /* 1E64; 1E65; Case map */ { 0x001E66, 0, { 0x001E67 }}, /* 1E66; 1E67; Case map */ { 0x001E68, 0, { 0x001E69 }}, /* 1E68; 1E69; Case map */ { 0x001E6A, 0, { 0x001E6B }}, /* 1E6A; 1E6B; Case map */ { 0x001E6C, 0, { 0x001E6D }}, /* 1E6C; 1E6D; Case map */ { 0x001E6E, 0, { 0x001E6F }}, /* 1E6E; 1E6F; Case map */ { 0x001E70, 0, { 0x001E71 }}, /* 1E70; 1E71; Case map */ { 0x001E72, 0, { 0x001E73 }}, /* 1E72; 1E73; Case map */ { 0x001E74, 0, { 0x001E75 }}, /* 1E74; 1E75; Case map */ { 0x001E76, 0, { 0x001E77 }}, /* 1E76; 1E77; Case map */ { 0x001E78, 0, { 0x001E79 }}, /* 1E78; 1E79; Case map */ { 0x001E7A, 0, { 0x001E7B }}, /* 1E7A; 1E7B; Case map */ { 0x001E7C, 0, { 0x001E7D }}, /* 1E7C; 1E7D; Case map */ { 0x001E7E, 0, { 0x001E7F }}, /* 1E7E; 1E7F; Case map */ { 0x001E80, 0, { 0x001E81 }}, /* 1E80; 1E81; Case map */ { 0x001E82, 0, { 0x001E83 }}, /* 1E82; 1E83; Case map */ { 0x001E84, 0, { 0x001E85 }}, /* 1E84; 1E85; Case map */ { 0x001E86, 0, { 0x001E87 }}, /* 1E86; 1E87; Case map */ { 0x001E88, 0, { 0x001E89 }}, /* 1E88; 1E89; Case map */ { 0x001E8A, 0, { 0x001E8B }}, /* 1E8A; 1E8B; Case map */ { 0x001E8C, 0, { 0x001E8D }}, /* 1E8C; 1E8D; Case map */ { 0x001E8E, 0, { 0x001E8F }}, /* 1E8E; 1E8F; Case map */ { 0x001E90, 0, { 0x001E91 }}, /* 1E90; 1E91; Case map */ { 0x001E92, 0, { 0x001E93 }}, /* 1E92; 1E93; Case map */ { 0x001E94, 0, { 0x001E95 }}, /* 1E94; 1E95; Case map */ { 0x001E96, 0, { 0x000068, /* 1E96; 0068 0331; Case map */ 0x000331 }}, { 0x001E97, 0, { 0x000074, /* 1E97; 0074 0308; Case map */ 0x000308 }}, { 0x001E98, 0, { 0x000077, /* 1E98; 0077 030A; Case map */ 0x00030A }}, { 0x001E99, 0, { 0x000079, /* 1E99; 0079 030A; Case map */ 0x00030A }}, { 0x001E9A, 0, { 0x000061, /* 1E9A; 0061 02BE; Case map */ 0x0002BE }}, { 0x001E9B, 0, { 0x001E61 }}, /* 1E9B; 1E61; Case map */ { 0x001EA0, 0, { 0x001EA1 }}, /* 1EA0; 1EA1; Case map */ { 0x001EA2, 0, { 0x001EA3 }}, /* 1EA2; 1EA3; Case map */ { 0x001EA4, 0, { 0x001EA5 }}, /* 1EA4; 1EA5; Case map */ { 0x001EA6, 0, { 0x001EA7 }}, /* 1EA6; 1EA7; Case map */ { 0x001EA8, 0, { 0x001EA9 }}, /* 1EA8; 1EA9; Case map */ { 0x001EAA, 0, { 0x001EAB }}, /* 1EAA; 1EAB; Case map */ { 0x001EAC, 0, { 0x001EAD }}, /* 1EAC; 1EAD; Case map */ { 0x001EAE, 0, { 0x001EAF }}, /* 1EAE; 1EAF; Case map */ { 0x001EB0, 0, { 0x001EB1 }}, /* 1EB0; 1EB1; Case map */ { 0x001EB2, 0, { 0x001EB3 }}, /* 1EB2; 1EB3; Case map */ { 0x001EB4, 0, { 0x001EB5 }}, /* 1EB4; 1EB5; Case map */ { 0x001EB6, 0, { 0x001EB7 }}, /* 1EB6; 1EB7; Case map */ { 0x001EB8, 0, { 0x001EB9 }}, /* 1EB8; 1EB9; Case map */ { 0x001EBA, 0, { 0x001EBB }}, /* 1EBA; 1EBB; Case map */ { 0x001EBC, 0, { 0x001EBD }}, /* 1EBC; 1EBD; Case map */ { 0x001EBE, 0, { 0x001EBF }}, /* 1EBE; 1EBF; Case map */ { 0x001EC0, 0, { 0x001EC1 }}, /* 1EC0; 1EC1; Case map */ { 0x001EC2, 0, { 0x001EC3 }}, /* 1EC2; 1EC3; Case map */ { 0x001EC4, 0, { 0x001EC5 }}, /* 1EC4; 1EC5; Case map */ { 0x001EC6, 0, { 0x001EC7 }}, /* 1EC6; 1EC7; Case map */ { 0x001EC8, 0, { 0x001EC9 }}, /* 1EC8; 1EC9; Case map */ { 0x001ECA, 0, { 0x001ECB }}, /* 1ECA; 1ECB; Case map */ { 0x001ECC, 0, { 0x001ECD }}, /* 1ECC; 1ECD; Case map */ { 0x001ECE, 0, { 0x001ECF }}, /* 1ECE; 1ECF; Case map */ { 0x001ED0, 0, { 0x001ED1 }}, /* 1ED0; 1ED1; Case map */ { 0x001ED2, 0, { 0x001ED3 }}, /* 1ED2; 1ED3; Case map */ { 0x001ED4, 0, { 0x001ED5 }}, /* 1ED4; 1ED5; Case map */ { 0x001ED6, 0, { 0x001ED7 }}, /* 1ED6; 1ED7; Case map */ { 0x001ED8, 0, { 0x001ED9 }}, /* 1ED8; 1ED9; Case map */ { 0x001EDA, 0, { 0x001EDB }}, /* 1EDA; 1EDB; Case map */ { 0x001EDC, 0, { 0x001EDD }}, /* 1EDC; 1EDD; Case map */ { 0x001EDE, 0, { 0x001EDF }}, /* 1EDE; 1EDF; Case map */ { 0x001EE0, 0, { 0x001EE1 }}, /* 1EE0; 1EE1; Case map */ { 0x001EE2, 0, { 0x001EE3 }}, /* 1EE2; 1EE3; Case map */ { 0x001EE4, 0, { 0x001EE5 }}, /* 1EE4; 1EE5; Case map */ { 0x001EE6, 0, { 0x001EE7 }}, /* 1EE6; 1EE7; Case map */ { 0x001EE8, 0, { 0x001EE9 }}, /* 1EE8; 1EE9; Case map */ { 0x001EEA, 0, { 0x001EEB }}, /* 1EEA; 1EEB; Case map */ { 0x001EEC, 0, { 0x001EED }}, /* 1EEC; 1EED; Case map */ { 0x001EEE, 0, { 0x001EEF }}, /* 1EEE; 1EEF; Case map */ { 0x001EF0, 0, { 0x001EF1 }}, /* 1EF0; 1EF1; Case map */ { 0x001EF2, 0, { 0x001EF3 }}, /* 1EF2; 1EF3; Case map */ { 0x001EF4, 0, { 0x001EF5 }}, /* 1EF4; 1EF5; Case map */ { 0x001EF6, 0, { 0x001EF7 }}, /* 1EF6; 1EF7; Case map */ { 0x001EF8, 0, { 0x001EF9 }}, /* 1EF8; 1EF9; Case map */ { 0x001F08, 0, { 0x001F00 }}, /* 1F08; 1F00; Case map */ { 0x001F09, 0, { 0x001F01 }}, /* 1F09; 1F01; Case map */ { 0x001F0A, 0, { 0x001F02 }}, /* 1F0A; 1F02; Case map */ { 0x001F0B, 0, { 0x001F03 }}, /* 1F0B; 1F03; Case map */ { 0x001F0C, 0, { 0x001F04 }}, /* 1F0C; 1F04; Case map */ { 0x001F0D, 0, { 0x001F05 }}, /* 1F0D; 1F05; Case map */ { 0x001F0E, 0, { 0x001F06 }}, /* 1F0E; 1F06; Case map */ { 0x001F0F, 0, { 0x001F07 }}, /* 1F0F; 1F07; Case map */ { 0x001F18, 0, { 0x001F10 }}, /* 1F18; 1F10; Case map */ { 0x001F19, 0, { 0x001F11 }}, /* 1F19; 1F11; Case map */ { 0x001F1A, 0, { 0x001F12 }}, /* 1F1A; 1F12; Case map */ { 0x001F1B, 0, { 0x001F13 }}, /* 1F1B; 1F13; Case map */ { 0x001F1C, 0, { 0x001F14 }}, /* 1F1C; 1F14; Case map */ { 0x001F1D, 0, { 0x001F15 }}, /* 1F1D; 1F15; Case map */ { 0x001F28, 0, { 0x001F20 }}, /* 1F28; 1F20; Case map */ { 0x001F29, 0, { 0x001F21 }}, /* 1F29; 1F21; Case map */ { 0x001F2A, 0, { 0x001F22 }}, /* 1F2A; 1F22; Case map */ { 0x001F2B, 0, { 0x001F23 }}, /* 1F2B; 1F23; Case map */ { 0x001F2C, 0, { 0x001F24 }}, /* 1F2C; 1F24; Case map */ { 0x001F2D, 0, { 0x001F25 }}, /* 1F2D; 1F25; Case map */ { 0x001F2E, 0, { 0x001F26 }}, /* 1F2E; 1F26; Case map */ { 0x001F2F, 0, { 0x001F27 }}, /* 1F2F; 1F27; Case map */ { 0x001F38, 0, { 0x001F30 }}, /* 1F38; 1F30; Case map */ { 0x001F39, 0, { 0x001F31 }}, /* 1F39; 1F31; Case map */ { 0x001F3A, 0, { 0x001F32 }}, /* 1F3A; 1F32; Case map */ { 0x001F3B, 0, { 0x001F33 }}, /* 1F3B; 1F33; Case map */ { 0x001F3C, 0, { 0x001F34 }}, /* 1F3C; 1F34; Case map */ { 0x001F3D, 0, { 0x001F35 }}, /* 1F3D; 1F35; Case map */ { 0x001F3E, 0, { 0x001F36 }}, /* 1F3E; 1F36; Case map */ { 0x001F3F, 0, { 0x001F37 }}, /* 1F3F; 1F37; Case map */ { 0x001F48, 0, { 0x001F40 }}, /* 1F48; 1F40; Case map */ { 0x001F49, 0, { 0x001F41 }}, /* 1F49; 1F41; Case map */ { 0x001F4A, 0, { 0x001F42 }}, /* 1F4A; 1F42; Case map */ { 0x001F4B, 0, { 0x001F43 }}, /* 1F4B; 1F43; Case map */ { 0x001F4C, 0, { 0x001F44 }}, /* 1F4C; 1F44; Case map */ { 0x001F4D, 0, { 0x001F45 }}, /* 1F4D; 1F45; Case map */ { 0x001F50, 0, { 0x0003C5, /* 1F50; 03C5 0313; Case map */ 0x000313 }}, { 0x001F52, 0, { 0x0003C5, /* 1F52; 03C5 0313 0300; Case map */ 0x000313, 0x000300 }}, { 0x001F54, 0, { 0x0003C5, /* 1F54; 03C5 0313 0301; Case map */ 0x000313, 0x000301 }}, { 0x001F56, 0, { 0x0003C5, /* 1F56; 03C5 0313 0342; Case map */ 0x000313, 0x000342 }}, { 0x001F59, 0, { 0x001F51 }}, /* 1F59; 1F51; Case map */ { 0x001F5B, 0, { 0x001F53 }}, /* 1F5B; 1F53; Case map */ { 0x001F5D, 0, { 0x001F55 }}, /* 1F5D; 1F55; Case map */ { 0x001F5F, 0, { 0x001F57 }}, /* 1F5F; 1F57; Case map */ { 0x001F68, 0, { 0x001F60 }}, /* 1F68; 1F60; Case map */ { 0x001F69, 0, { 0x001F61 }}, /* 1F69; 1F61; Case map */ { 0x001F6A, 0, { 0x001F62 }}, /* 1F6A; 1F62; Case map */ { 0x001F6B, 0, { 0x001F63 }}, /* 1F6B; 1F63; Case map */ { 0x001F6C, 0, { 0x001F64 }}, /* 1F6C; 1F64; Case map */ { 0x001F6D, 0, { 0x001F65 }}, /* 1F6D; 1F65; Case map */ { 0x001F6E, 0, { 0x001F66 }}, /* 1F6E; 1F66; Case map */ { 0x001F6F, 0, { 0x001F67 }}, /* 1F6F; 1F67; Case map */ { 0x001F80, 0, { 0x001F00, /* 1F80; 1F00 03B9; Case map */ 0x0003B9 }}, { 0x001F81, 0, { 0x001F01, /* 1F81; 1F01 03B9; Case map */ 0x0003B9 }}, { 0x001F82, 0, { 0x001F02, /* 1F82; 1F02 03B9; Case map */ 0x0003B9 }}, { 0x001F83, 0, { 0x001F03, /* 1F83; 1F03 03B9; Case map */ 0x0003B9 }}, { 0x001F84, 0, { 0x001F04, /* 1F84; 1F04 03B9; Case map */ 0x0003B9 }}, { 0x001F85, 0, { 0x001F05, /* 1F85; 1F05 03B9; Case map */ 0x0003B9 }}, { 0x001F86, 0, { 0x001F06, /* 1F86; 1F06 03B9; Case map */ 0x0003B9 }}, { 0x001F87, 0, { 0x001F07, /* 1F87; 1F07 03B9; Case map */ 0x0003B9 }}, { 0x001F88, 0, { 0x001F00, /* 1F88; 1F00 03B9; Case map */ 0x0003B9 }}, { 0x001F89, 0, { 0x001F01, /* 1F89; 1F01 03B9; Case map */ 0x0003B9 }}, { 0x001F8A, 0, { 0x001F02, /* 1F8A; 1F02 03B9; Case map */ 0x0003B9 }}, { 0x001F8B, 0, { 0x001F03, /* 1F8B; 1F03 03B9; Case map */ 0x0003B9 }}, { 0x001F8C, 0, { 0x001F04, /* 1F8C; 1F04 03B9; Case map */ 0x0003B9 }}, { 0x001F8D, 0, { 0x001F05, /* 1F8D; 1F05 03B9; Case map */ 0x0003B9 }}, { 0x001F8E, 0, { 0x001F06, /* 1F8E; 1F06 03B9; Case map */ 0x0003B9 }}, { 0x001F8F, 0, { 0x001F07, /* 1F8F; 1F07 03B9; Case map */ 0x0003B9 }}, { 0x001F90, 0, { 0x001F20, /* 1F90; 1F20 03B9; Case map */ 0x0003B9 }}, { 0x001F91, 0, { 0x001F21, /* 1F91; 1F21 03B9; Case map */ 0x0003B9 }}, { 0x001F92, 0, { 0x001F22, /* 1F92; 1F22 03B9; Case map */ 0x0003B9 }}, { 0x001F93, 0, { 0x001F23, /* 1F93; 1F23 03B9; Case map */ 0x0003B9 }}, { 0x001F94, 0, { 0x001F24, /* 1F94; 1F24 03B9; Case map */ 0x0003B9 }}, { 0x001F95, 0, { 0x001F25, /* 1F95; 1F25 03B9; Case map */ 0x0003B9 }}, { 0x001F96, 0, { 0x001F26, /* 1F96; 1F26 03B9; Case map */ 0x0003B9 }}, { 0x001F97, 0, { 0x001F27, /* 1F97; 1F27 03B9; Case map */ 0x0003B9 }}, { 0x001F98, 0, { 0x001F20, /* 1F98; 1F20 03B9; Case map */ 0x0003B9 }}, { 0x001F99, 0, { 0x001F21, /* 1F99; 1F21 03B9; Case map */ 0x0003B9 }}, { 0x001F9A, 0, { 0x001F22, /* 1F9A; 1F22 03B9; Case map */ 0x0003B9 }}, { 0x001F9B, 0, { 0x001F23, /* 1F9B; 1F23 03B9; Case map */ 0x0003B9 }}, { 0x001F9C, 0, { 0x001F24, /* 1F9C; 1F24 03B9; Case map */ 0x0003B9 }}, { 0x001F9D, 0, { 0x001F25, /* 1F9D; 1F25 03B9; Case map */ 0x0003B9 }}, { 0x001F9E, 0, { 0x001F26, /* 1F9E; 1F26 03B9; Case map */ 0x0003B9 }}, { 0x001F9F, 0, { 0x001F27, /* 1F9F; 1F27 03B9; Case map */ 0x0003B9 }}, { 0x001FA0, 0, { 0x001F60, /* 1FA0; 1F60 03B9; Case map */ 0x0003B9 }}, { 0x001FA1, 0, { 0x001F61, /* 1FA1; 1F61 03B9; Case map */ 0x0003B9 }}, { 0x001FA2, 0, { 0x001F62, /* 1FA2; 1F62 03B9; Case map */ 0x0003B9 }}, { 0x001FA3, 0, { 0x001F63, /* 1FA3; 1F63 03B9; Case map */ 0x0003B9 }}, { 0x001FA4, 0, { 0x001F64, /* 1FA4; 1F64 03B9; Case map */ 0x0003B9 }}, { 0x001FA5, 0, { 0x001F65, /* 1FA5; 1F65 03B9; Case map */ 0x0003B9 }}, { 0x001FA6, 0, { 0x001F66, /* 1FA6; 1F66 03B9; Case map */ 0x0003B9 }}, { 0x001FA7, 0, { 0x001F67, /* 1FA7; 1F67 03B9; Case map */ 0x0003B9 }}, { 0x001FA8, 0, { 0x001F60, /* 1FA8; 1F60 03B9; Case map */ 0x0003B9 }}, { 0x001FA9, 0, { 0x001F61, /* 1FA9; 1F61 03B9; Case map */ 0x0003B9 }}, { 0x001FAA, 0, { 0x001F62, /* 1FAA; 1F62 03B9; Case map */ 0x0003B9 }}, { 0x001FAB, 0, { 0x001F63, /* 1FAB; 1F63 03B9; Case map */ 0x0003B9 }}, { 0x001FAC, 0, { 0x001F64, /* 1FAC; 1F64 03B9; Case map */ 0x0003B9 }}, { 0x001FAD, 0, { 0x001F65, /* 1FAD; 1F65 03B9; Case map */ 0x0003B9 }}, { 0x001FAE, 0, { 0x001F66, /* 1FAE; 1F66 03B9; Case map */ 0x0003B9 }}, { 0x001FAF, 0, { 0x001F67, /* 1FAF; 1F67 03B9; Case map */ 0x0003B9 }}, { 0x001FB2, 0, { 0x001F70, /* 1FB2; 1F70 03B9; Case map */ 0x0003B9 }}, { 0x001FB3, 0, { 0x0003B1, /* 1FB3; 03B1 03B9; Case map */ 0x0003B9 }}, { 0x001FB4, 0, { 0x0003AC, /* 1FB4; 03AC 03B9; Case map */ 0x0003B9 }}, { 0x001FB6, 0, { 0x0003B1, /* 1FB6; 03B1 0342; Case map */ 0x000342 }}, { 0x001FB7, 0, { 0x0003B1, /* 1FB7; 03B1 0342 03B9; Case map */ 0x000342, 0x0003B9 }}, { 0x001FB8, 0, { 0x001FB0 }}, /* 1FB8; 1FB0; Case map */ { 0x001FB9, 0, { 0x001FB1 }}, /* 1FB9; 1FB1; Case map */ { 0x001FBA, 0, { 0x001F70 }}, /* 1FBA; 1F70; Case map */ { 0x001FBB, 0, { 0x001F71 }}, /* 1FBB; 1F71; Case map */ { 0x001FBC, 0, { 0x0003B1, /* 1FBC; 03B1 03B9; Case map */ 0x0003B9 }}, { 0x001FBE, 0, { 0x0003B9 }}, /* 1FBE; 03B9; Case map */ { 0x001FC2, 0, { 0x001F74, /* 1FC2; 1F74 03B9; Case map */ 0x0003B9 }}, { 0x001FC3, 0, { 0x0003B7, /* 1FC3; 03B7 03B9; Case map */ 0x0003B9 }}, { 0x001FC4, 0, { 0x0003AE, /* 1FC4; 03AE 03B9; Case map */ 0x0003B9 }}, { 0x001FC6, 0, { 0x0003B7, /* 1FC6; 03B7 0342; Case map */ 0x000342 }}, { 0x001FC7, 0, { 0x0003B7, /* 1FC7; 03B7 0342 03B9; Case map */ 0x000342, 0x0003B9 }}, { 0x001FC8, 0, { 0x001F72 }}, /* 1FC8; 1F72; Case map */ { 0x001FC9, 0, { 0x001F73 }}, /* 1FC9; 1F73; Case map */ { 0x001FCA, 0, { 0x001F74 }}, /* 1FCA; 1F74; Case map */ { 0x001FCB, 0, { 0x001F75 }}, /* 1FCB; 1F75; Case map */ { 0x001FCC, 0, { 0x0003B7, /* 1FCC; 03B7 03B9; Case map */ 0x0003B9 }}, { 0x001FD2, 0, { 0x0003B9, /* 1FD2; 03B9 0308 0300; Case map */ 0x000308, 0x000300 }}, { 0x001FD3, 0, { 0x0003B9, /* 1FD3; 03B9 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x001FD6, 0, { 0x0003B9, /* 1FD6; 03B9 0342; Case map */ 0x000342 }}, { 0x001FD7, 0, { 0x0003B9, /* 1FD7; 03B9 0308 0342; Case map */ 0x000308, 0x000342 }}, { 0x001FD8, 0, { 0x001FD0 }}, /* 1FD8; 1FD0; Case map */ { 0x001FD9, 0, { 0x001FD1 }}, /* 1FD9; 1FD1; Case map */ { 0x001FDA, 0, { 0x001F76 }}, /* 1FDA; 1F76; Case map */ { 0x001FDB, 0, { 0x001F77 }}, /* 1FDB; 1F77; Case map */ { 0x001FE2, 0, { 0x0003C5, /* 1FE2; 03C5 0308 0300; Case map */ 0x000308, 0x000300 }}, { 0x001FE3, 0, { 0x0003C5, /* 1FE3; 03C5 0308 0301; Case map */ 0x000308, 0x000301 }}, { 0x001FE4, 0, { 0x0003C1, /* 1FE4; 03C1 0313; Case map */ 0x000313 }}, { 0x001FE6, 0, { 0x0003C5, /* 1FE6; 03C5 0342; Case map */ 0x000342 }}, { 0x001FE7, 0, { 0x0003C5, /* 1FE7; 03C5 0308 0342; Case map */ 0x000308, 0x000342 }}, { 0x001FE8, 0, { 0x001FE0 }}, /* 1FE8; 1FE0; Case map */ { 0x001FE9, 0, { 0x001FE1 }}, /* 1FE9; 1FE1; Case map */ { 0x001FEA, 0, { 0x001F7A }}, /* 1FEA; 1F7A; Case map */ { 0x001FEB, 0, { 0x001F7B }}, /* 1FEB; 1F7B; Case map */ { 0x001FEC, 0, { 0x001FE5 }}, /* 1FEC; 1FE5; Case map */ { 0x001FF2, 0, { 0x001F7C, /* 1FF2; 1F7C 03B9; Case map */ 0x0003B9 }}, { 0x001FF3, 0, { 0x0003C9, /* 1FF3; 03C9 03B9; Case map */ 0x0003B9 }}, { 0x001FF4, 0, { 0x0003CE, /* 1FF4; 03CE 03B9; Case map */ 0x0003B9 }}, { 0x001FF6, 0, { 0x0003C9, /* 1FF6; 03C9 0342; Case map */ 0x000342 }}, { 0x001FF7, 0, { 0x0003C9, /* 1FF7; 03C9 0342 03B9; Case map */ 0x000342, 0x0003B9 }}, { 0x001FF8, 0, { 0x001F78 }}, /* 1FF8; 1F78; Case map */ { 0x001FF9, 0, { 0x001F79 }}, /* 1FF9; 1F79; Case map */ { 0x001FFA, 0, { 0x001F7C }}, /* 1FFA; 1F7C; Case map */ { 0x001FFB, 0, { 0x001F7D }}, /* 1FFB; 1F7D; Case map */ { 0x001FFC, 0, { 0x0003C9, /* 1FFC; 03C9 03B9; Case map */ 0x0003B9 }}, { 0x002126, 0, { 0x0003C9 }}, /* 2126; 03C9; Case map */ { 0x00212A, 0, { 0x00006B }}, /* 212A; 006B; Case map */ { 0x00212B, 0, { 0x0000E5 }}, /* 212B; 00E5; Case map */ { 0x002160, 0, { 0x002170 }}, /* 2160; 2170; Case map */ { 0x002161, 0, { 0x002171 }}, /* 2161; 2171; Case map */ { 0x002162, 0, { 0x002172 }}, /* 2162; 2172; Case map */ { 0x002163, 0, { 0x002173 }}, /* 2163; 2173; Case map */ { 0x002164, 0, { 0x002174 }}, /* 2164; 2174; Case map */ { 0x002165, 0, { 0x002175 }}, /* 2165; 2175; Case map */ { 0x002166, 0, { 0x002176 }}, /* 2166; 2176; Case map */ { 0x002167, 0, { 0x002177 }}, /* 2167; 2177; Case map */ { 0x002168, 0, { 0x002178 }}, /* 2168; 2178; Case map */ { 0x002169, 0, { 0x002179 }}, /* 2169; 2179; Case map */ { 0x00216A, 0, { 0x00217A }}, /* 216A; 217A; Case map */ { 0x00216B, 0, { 0x00217B }}, /* 216B; 217B; Case map */ { 0x00216C, 0, { 0x00217C }}, /* 216C; 217C; Case map */ { 0x00216D, 0, { 0x00217D }}, /* 216D; 217D; Case map */ { 0x00216E, 0, { 0x00217E }}, /* 216E; 217E; Case map */ { 0x00216F, 0, { 0x00217F }}, /* 216F; 217F; Case map */ { 0x0024B6, 0, { 0x0024D0 }}, /* 24B6; 24D0; Case map */ { 0x0024B7, 0, { 0x0024D1 }}, /* 24B7; 24D1; Case map */ { 0x0024B8, 0, { 0x0024D2 }}, /* 24B8; 24D2; Case map */ { 0x0024B9, 0, { 0x0024D3 }}, /* 24B9; 24D3; Case map */ { 0x0024BA, 0, { 0x0024D4 }}, /* 24BA; 24D4; Case map */ { 0x0024BB, 0, { 0x0024D5 }}, /* 24BB; 24D5; Case map */ { 0x0024BC, 0, { 0x0024D6 }}, /* 24BC; 24D6; Case map */ { 0x0024BD, 0, { 0x0024D7 }}, /* 24BD; 24D7; Case map */ { 0x0024BE, 0, { 0x0024D8 }}, /* 24BE; 24D8; Case map */ { 0x0024BF, 0, { 0x0024D9 }}, /* 24BF; 24D9; Case map */ { 0x0024C0, 0, { 0x0024DA }}, /* 24C0; 24DA; Case map */ { 0x0024C1, 0, { 0x0024DB }}, /* 24C1; 24DB; Case map */ { 0x0024C2, 0, { 0x0024DC }}, /* 24C2; 24DC; Case map */ { 0x0024C3, 0, { 0x0024DD }}, /* 24C3; 24DD; Case map */ { 0x0024C4, 0, { 0x0024DE }}, /* 24C4; 24DE; Case map */ { 0x0024C5, 0, { 0x0024DF }}, /* 24C5; 24DF; Case map */ { 0x0024C6, 0, { 0x0024E0 }}, /* 24C6; 24E0; Case map */ { 0x0024C7, 0, { 0x0024E1 }}, /* 24C7; 24E1; Case map */ { 0x0024C8, 0, { 0x0024E2 }}, /* 24C8; 24E2; Case map */ { 0x0024C9, 0, { 0x0024E3 }}, /* 24C9; 24E3; Case map */ { 0x0024CA, 0, { 0x0024E4 }}, /* 24CA; 24E4; Case map */ { 0x0024CB, 0, { 0x0024E5 }}, /* 24CB; 24E5; Case map */ { 0x0024CC, 0, { 0x0024E6 }}, /* 24CC; 24E6; Case map */ { 0x0024CD, 0, { 0x0024E7 }}, /* 24CD; 24E7; Case map */ { 0x0024CE, 0, { 0x0024E8 }}, /* 24CE; 24E8; Case map */ { 0x0024CF, 0, { 0x0024E9 }}, /* 24CF; 24E9; Case map */ { 0x00FB00, 0, { 0x000066, /* FB00; 0066 0066; Case map */ 0x000066 }}, { 0x00FB01, 0, { 0x000066, /* FB01; 0066 0069; Case map */ 0x000069 }}, { 0x00FB02, 0, { 0x000066, /* FB02; 0066 006C; Case map */ 0x00006C }}, { 0x00FB03, 0, { 0x000066, /* FB03; 0066 0066 0069; Case map */ 0x000066, 0x000069 }}, { 0x00FB04, 0, { 0x000066, /* FB04; 0066 0066 006C; Case map */ 0x000066, 0x00006C }}, { 0x00FB05, 0, { 0x000073, /* FB05; 0073 0074; Case map */ 0x000074 }}, { 0x00FB06, 0, { 0x000073, /* FB06; 0073 0074; Case map */ 0x000074 }}, { 0x00FB13, 0, { 0x000574, /* FB13; 0574 0576; Case map */ 0x000576 }}, { 0x00FB14, 0, { 0x000574, /* FB14; 0574 0565; Case map */ 0x000565 }}, { 0x00FB15, 0, { 0x000574, /* FB15; 0574 056B; Case map */ 0x00056B }}, { 0x00FB16, 0, { 0x00057E, /* FB16; 057E 0576; Case map */ 0x000576 }}, { 0x00FB17, 0, { 0x000574, /* FB17; 0574 056D; Case map */ 0x00056D }}, { 0x00FF21, 0, { 0x00FF41 }}, /* FF21; FF41; Case map */ { 0x00FF22, 0, { 0x00FF42 }}, /* FF22; FF42; Case map */ { 0x00FF23, 0, { 0x00FF43 }}, /* FF23; FF43; Case map */ { 0x00FF24, 0, { 0x00FF44 }}, /* FF24; FF44; Case map */ { 0x00FF25, 0, { 0x00FF45 }}, /* FF25; FF45; Case map */ { 0x00FF26, 0, { 0x00FF46 }}, /* FF26; FF46; Case map */ { 0x00FF27, 0, { 0x00FF47 }}, /* FF27; FF47; Case map */ { 0x00FF28, 0, { 0x00FF48 }}, /* FF28; FF48; Case map */ { 0x00FF29, 0, { 0x00FF49 }}, /* FF29; FF49; Case map */ { 0x00FF2A, 0, { 0x00FF4A }}, /* FF2A; FF4A; Case map */ { 0x00FF2B, 0, { 0x00FF4B }}, /* FF2B; FF4B; Case map */ { 0x00FF2C, 0, { 0x00FF4C }}, /* FF2C; FF4C; Case map */ { 0x00FF2D, 0, { 0x00FF4D }}, /* FF2D; FF4D; Case map */ { 0x00FF2E, 0, { 0x00FF4E }}, /* FF2E; FF4E; Case map */ { 0x00FF2F, 0, { 0x00FF4F }}, /* FF2F; FF4F; Case map */ { 0x00FF30, 0, { 0x00FF50 }}, /* FF30; FF50; Case map */ { 0x00FF31, 0, { 0x00FF51 }}, /* FF31; FF51; Case map */ { 0x00FF32, 0, { 0x00FF52 }}, /* FF32; FF52; Case map */ { 0x00FF33, 0, { 0x00FF53 }}, /* FF33; FF53; Case map */ { 0x00FF34, 0, { 0x00FF54 }}, /* FF34; FF54; Case map */ { 0x00FF35, 0, { 0x00FF55 }}, /* FF35; FF55; Case map */ { 0x00FF36, 0, { 0x00FF56 }}, /* FF36; FF56; Case map */ { 0x00FF37, 0, { 0x00FF57 }}, /* FF37; FF57; Case map */ { 0x00FF38, 0, { 0x00FF58 }}, /* FF38; FF58; Case map */ { 0x00FF39, 0, { 0x00FF59 }}, /* FF39; FF59; Case map */ { 0x00FF3A, 0, { 0x00FF5A }}, /* FF3A; FF5A; Case map */ { 0x010400, 0, { 0x010428 }}, /* 10400; 10428; Case map */ { 0x010401, 0, { 0x010429 }}, /* 10401; 10429; Case map */ { 0x010402, 0, { 0x01042A }}, /* 10402; 1042A; Case map */ { 0x010403, 0, { 0x01042B }}, /* 10403; 1042B; Case map */ { 0x010404, 0, { 0x01042C }}, /* 10404; 1042C; Case map */ { 0x010405, 0, { 0x01042D }}, /* 10405; 1042D; Case map */ { 0x010406, 0, { 0x01042E }}, /* 10406; 1042E; Case map */ { 0x010407, 0, { 0x01042F }}, /* 10407; 1042F; Case map */ { 0x010408, 0, { 0x010430 }}, /* 10408; 10430; Case map */ { 0x010409, 0, { 0x010431 }}, /* 10409; 10431; Case map */ { 0x01040A, 0, { 0x010432 }}, /* 1040A; 10432; Case map */ { 0x01040B, 0, { 0x010433 }}, /* 1040B; 10433; Case map */ { 0x01040C, 0, { 0x010434 }}, /* 1040C; 10434; Case map */ { 0x01040D, 0, { 0x010435 }}, /* 1040D; 10435; Case map */ { 0x01040E, 0, { 0x010436 }}, /* 1040E; 10436; Case map */ { 0x01040F, 0, { 0x010437 }}, /* 1040F; 10437; Case map */ { 0x010410, 0, { 0x010438 }}, /* 10410; 10438; Case map */ { 0x010411, 0, { 0x010439 }}, /* 10411; 10439; Case map */ { 0x010412, 0, { 0x01043A }}, /* 10412; 1043A; Case map */ { 0x010413, 0, { 0x01043B }}, /* 10413; 1043B; Case map */ { 0x010414, 0, { 0x01043C }}, /* 10414; 1043C; Case map */ { 0x010415, 0, { 0x01043D }}, /* 10415; 1043D; Case map */ { 0x010416, 0, { 0x01043E }}, /* 10416; 1043E; Case map */ { 0x010417, 0, { 0x01043F }}, /* 10417; 1043F; Case map */ { 0x010418, 0, { 0x010440 }}, /* 10418; 10440; Case map */ { 0x010419, 0, { 0x010441 }}, /* 10419; 10441; Case map */ { 0x01041A, 0, { 0x010442 }}, /* 1041A; 10442; Case map */ { 0x01041B, 0, { 0x010443 }}, /* 1041B; 10443; Case map */ { 0x01041C, 0, { 0x010444 }}, /* 1041C; 10444; Case map */ { 0x01041D, 0, { 0x010445 }}, /* 1041D; 10445; Case map */ { 0x01041E, 0, { 0x010446 }}, /* 1041E; 10446; Case map */ { 0x01041F, 0, { 0x010447 }}, /* 1041F; 10447; Case map */ { 0x010420, 0, { 0x010448 }}, /* 10420; 10448; Case map */ { 0x010421, 0, { 0x010449 }}, /* 10421; 10449; Case map */ { 0x010422, 0, { 0x01044A }}, /* 10422; 1044A; Case map */ { 0x010423, 0, { 0x01044B }}, /* 10423; 1044B; Case map */ { 0x010424, 0, { 0x01044C }}, /* 10424; 1044C; Case map */ { 0x010425, 0, { 0x01044D }}, /* 10425; 1044D; Case map */ { 0 }, }; /* * C.1.1 ASCII space characters * */ Stringprep_table_element stringprep_rfc3454_C_1_1[] = { { 0x000020 }, /* 0020; SPACE */ { 0 }, }; /* * C.1.2 Non-ASCII space characters * */ Stringprep_table_element stringprep_rfc3454_C_1_2[] = { { 0x0000A0 }, /* 00A0; NO-BREAK SPACE */ { 0x001680 }, /* 1680; OGHAM SPACE MARK */ { 0x002000 }, /* 2000; EN QUAD */ { 0x002001 }, /* 2001; EM QUAD */ { 0x002002 }, /* 2002; EN SPACE */ { 0x002003 }, /* 2003; EM SPACE */ { 0x002004 }, /* 2004; THREE-PER-EM SPACE */ { 0x002005 }, /* 2005; FOUR-PER-EM SPACE */ { 0x002006 }, /* 2006; SIX-PER-EM SPACE */ { 0x002007 }, /* 2007; FIGURE SPACE */ { 0x002008 }, /* 2008; PUNCTUATION SPACE */ { 0x002009 }, /* 2009; THIN SPACE */ { 0x00200A }, /* 200A; HAIR SPACE */ { 0x00200B }, /* 200B; ZERO WIDTH SPACE */ { 0x00202F }, /* 202F; NARROW NO-BREAK SPACE */ { 0x00205F }, /* 205F; MEDIUM MATHEMATICAL SPACE */ { 0x003000 }, /* 3000; IDEOGRAPHIC SPACE */ { 0 }, }; /* * C.2.1 ASCII control characters * */ Stringprep_table_element stringprep_rfc3454_C_2_1[] = { { 0x000000, 0x00001F }, /* 0000-001F; [CONTROL CHARACTERS] */ { 0x00007F }, /* 007F; DELETE */ { 0 }, }; /* * C.2.2 Non-ASCII control characters * */ Stringprep_table_element stringprep_rfc3454_C_2_2[] = { { 0x000080, 0x00009F }, /* 0080-009F; [CONTROL CHARACTERS] */ { 0x0006DD }, /* 06DD; ARABIC END OF AYAH */ { 0x00070F }, /* 070F; SYRIAC ABBREVIATION MARK */ { 0x00180E }, /* 180E; MONGOLIAN VOWEL SEPARATOR */ { 0x00200C }, /* 200C; ZERO WIDTH NON-JOINER */ { 0x00200D }, /* 200D; ZERO WIDTH JOINER */ { 0x002028 }, /* 2028; LINE SEPARATOR */ { 0x002029 }, /* 2029; PARAGRAPH SEPARATOR */ { 0x002060 }, /* 2060; WORD JOINER */ { 0x002061 }, /* 2061; FUNCTION APPLICATION */ { 0x002062 }, /* 2062; INVISIBLE TIMES */ { 0x002063 }, /* 2063; INVISIBLE SEPARATOR */ { 0x00206A, 0x00206F }, /* 206A-206F; [CONTROL CHARACTERS] */ { 0x00FEFF }, /* FEFF; ZERO WIDTH NO-BREAK SPACE */ { 0x00FFF9, 0x00FFFC }, /* FFF9-FFFC; [CONTROL CHARACTERS] */ { 0x01D173, 0x01D17A }, /* 1D173-1D17A; [MUSICAL CONTROL CHARACTERS] */ { 0 }, }; /* * C.3 Private use * */ Stringprep_table_element stringprep_rfc3454_C_3[] = { { 0x00E000, 0x00F8FF }, /* E000-F8FF; [PRIVATE USE, PLANE 0] */ { 0x0F0000, 0x0FFFFD }, /* F0000-FFFFD; [PRIVATE USE, PLANE 15] */ { 0x100000, 0x10FFFD }, /* 100000-10FFFD; [PRIVATE USE, PLANE 16] */ { 0 }, }; /* * C.4 Non-character code points * */ Stringprep_table_element stringprep_rfc3454_C_4[] = { { 0x00FDD0, 0x00FDEF }, /* FDD0-FDEF; [NONCHARACTER CODE POINTS] */ { 0x00FFFE, 0x00FFFF }, /* FFFE-FFFF; [NONCHARACTER CODE POINTS] */ { 0x01FFFE, 0x01FFFF }, /* 1FFFE-1FFFF; [NONCHARACTER CODE POINTS] */ { 0x02FFFE, 0x02FFFF }, /* 2FFFE-2FFFF; [NONCHARACTER CODE POINTS] */ { 0x03FFFE, 0x03FFFF }, /* 3FFFE-3FFFF; [NONCHARACTER CODE POINTS] */ { 0x04FFFE, 0x04FFFF }, /* 4FFFE-4FFFF; [NONCHARACTER CODE POINTS] */ { 0x05FFFE, 0x05FFFF }, /* 5FFFE-5FFFF; [NONCHARACTER CODE POINTS] */ { 0x06FFFE, 0x06FFFF }, /* 6FFFE-6FFFF; [NONCHARACTER CODE POINTS] */ { 0x07FFFE, 0x07FFFF }, /* 7FFFE-7FFFF; [NONCHARACTER CODE POINTS] */ { 0x08FFFE, 0x08FFFF }, /* 8FFFE-8FFFF; [NONCHARACTER CODE POINTS] */ { 0x09FFFE, 0x09FFFF }, /* 9FFFE-9FFFF; [NONCHARACTER CODE POINTS] */ { 0x0AFFFE, 0x0AFFFF }, /* AFFFE-AFFFF; [NONCHARACTER CODE POINTS] */ { 0x0BFFFE, 0x0BFFFF }, /* BFFFE-BFFFF; [NONCHARACTER CODE POINTS] */ { 0x0CFFFE, 0x0CFFFF }, /* CFFFE-CFFFF; [NONCHARACTER CODE POINTS] */ { 0x0DFFFE, 0x0DFFFF }, /* DFFFE-DFFFF; [NONCHARACTER CODE POINTS] */ { 0x0EFFFE, 0x0EFFFF }, /* EFFFE-EFFFF; [NONCHARACTER CODE POINTS] */ { 0x0FFFFE, 0x0FFFFF }, /* FFFFE-FFFFF; [NONCHARACTER CODE POINTS] */ { 0x10FFFE, 0x10FFFF }, /* 10FFFE-10FFFF; [NONCHARACTER CODE POINTS] */ { 0 }, }; /* * C.5 Surrogate codes * */ Stringprep_table_element stringprep_rfc3454_C_5[] = { { 0x00D800, 0x00DFFF }, /* D800-DFFF; [SURROGATE CODES] */ { 0 }, }; /* * C.6 Inappropriate for plain text * */ Stringprep_table_element stringprep_rfc3454_C_6[] = { { 0x00FFF9 }, /* FFF9; INTERLINEAR ANNOTATION ANCHOR */ { 0x00FFFA }, /* FFFA; INTERLINEAR ANNOTATION SEPARATOR */ { 0x00FFFB }, /* FFFB; INTERLINEAR ANNOTATION TERMINATOR */ { 0x00FFFC }, /* FFFC; OBJECT REPLACEMENT CHARACTER */ { 0x00FFFD }, /* FFFD; REPLACEMENT CHARACTER */ { 0 }, }; /* * C.7 Inappropriate for canonical representation * */ Stringprep_table_element stringprep_rfc3454_C_7[] = { { 0x002FF0, 0x002FFB }, /* 2FF0-2FFB; [IDEOGRAPHIC DESCRIPTION CHARACTERS] */ { 0 }, }; /* * C.8 Change display properties or are deprecated * */ Stringprep_table_element stringprep_rfc3454_C_8[] = { { 0x000340 }, /* 0340; COMBINING GRAVE TONE MARK */ { 0x000341 }, /* 0341; COMBINING ACUTE TONE MARK */ { 0x00200E }, /* 200E; LEFT-TO-RIGHT MARK */ { 0x00200F }, /* 200F; RIGHT-TO-LEFT MARK */ { 0x00202A }, /* 202A; LEFT-TO-RIGHT EMBEDDING */ { 0x00202B }, /* 202B; RIGHT-TO-LEFT EMBEDDING */ { 0x00202C }, /* 202C; POP DIRECTIONAL FORMATTING */ { 0x00202D }, /* 202D; LEFT-TO-RIGHT OVERRIDE */ { 0x00202E }, /* 202E; RIGHT-TO-LEFT OVERRIDE */ { 0x00206A }, /* 206A; INHIBIT SYMMETRIC SWAPPING */ { 0x00206B }, /* 206B; ACTIVATE SYMMETRIC SWAPPING */ { 0x00206C }, /* 206C; INHIBIT ARABIC FORM SHAPING */ { 0x00206D }, /* 206D; ACTIVATE ARABIC FORM SHAPING */ { 0x00206E }, /* 206E; NATIONAL DIGIT SHAPES */ { 0x00206F }, /* 206F; NOMINAL DIGIT SHAPES */ { 0 }, }; /* * C.9 Tagging characters * */ Stringprep_table_element stringprep_rfc3454_C_9[] = { { 0x0E0001 }, /* E0001; LANGUAGE TAG */ { 0x0E0020, 0x0E007F }, /* E0020-E007F; [TAGGING CHARACTERS] */ { 0 }, }; /* * D.1 Characters with bidirectional property "R" or "AL" * */ Stringprep_table_element stringprep_rfc3454_D_1[] = { { 0x0005BE }, /* 05BE */ { 0x0005C0 }, /* 05C0 */ { 0x0005C3 }, /* 05C3 */ { 0x0005D0, 0x0005EA }, /* 05D0-05EA */ { 0x0005F0, 0x0005F4 }, /* 05F0-05F4 */ { 0x00061B }, /* 061B */ { 0x00061F }, /* 061F */ { 0x000621, 0x00063A }, /* 0621-063A */ { 0x000640, 0x00064A }, /* 0640-064A */ { 0x00066D, 0x00066F }, /* 066D-066F */ { 0x000671, 0x0006D5 }, /* 0671-06D5 */ { 0x0006DD }, /* 06DD */ { 0x0006E5, 0x0006E6 }, /* 06E5-06E6 */ { 0x0006FA, 0x0006FE }, /* 06FA-06FE */ { 0x000700, 0x00070D }, /* 0700-070D */ { 0x000710 }, /* 0710 */ { 0x000712, 0x00072C }, /* 0712-072C */ { 0x000780, 0x0007A5 }, /* 0780-07A5 */ { 0x0007B1 }, /* 07B1 */ { 0x00200F }, /* 200F */ { 0x00FB1D }, /* FB1D */ { 0x00FB1F, 0x00FB28 }, /* FB1F-FB28 */ { 0x00FB2A, 0x00FB36 }, /* FB2A-FB36 */ { 0x00FB38, 0x00FB3C }, /* FB38-FB3C */ { 0x00FB3E }, /* FB3E */ { 0x00FB40, 0x00FB41 }, /* FB40-FB41 */ { 0x00FB43, 0x00FB44 }, /* FB43-FB44 */ { 0x00FB46, 0x00FBB1 }, /* FB46-FBB1 */ { 0x00FBD3, 0x00FD3D }, /* FBD3-FD3D */ { 0x00FD50, 0x00FD8F }, /* FD50-FD8F */ { 0x00FD92, 0x00FDC7 }, /* FD92-FDC7 */ { 0x00FDF0, 0x00FDFC }, /* FDF0-FDFC */ { 0x00FE70, 0x00FE74 }, /* FE70-FE74 */ { 0x00FE76, 0x00FEFC }, /* FE76-FEFC */ { 0 }, }; /* * D.2 Characters with bidirectional property "L" * */ Stringprep_table_element stringprep_rfc3454_D_2[] = { { 0x000041, 0x00005A }, /* 0041-005A */ { 0x000061, 0x00007A }, /* 0061-007A */ { 0x0000AA }, /* 00AA */ { 0x0000B5 }, /* 00B5 */ { 0x0000BA }, /* 00BA */ { 0x0000C0, 0x0000D6 }, /* 00C0-00D6 */ { 0x0000D8, 0x0000F6 }, /* 00D8-00F6 */ { 0x0000F8, 0x000220 }, /* 00F8-0220 */ { 0x000222, 0x000233 }, /* 0222-0233 */ { 0x000250, 0x0002AD }, /* 0250-02AD */ { 0x0002B0, 0x0002B8 }, /* 02B0-02B8 */ { 0x0002BB, 0x0002C1 }, /* 02BB-02C1 */ { 0x0002D0, 0x0002D1 }, /* 02D0-02D1 */ { 0x0002E0, 0x0002E4 }, /* 02E0-02E4 */ { 0x0002EE }, /* 02EE */ { 0x00037A }, /* 037A */ { 0x000386 }, /* 0386 */ { 0x000388, 0x00038A }, /* 0388-038A */ { 0x00038C }, /* 038C */ { 0x00038E, 0x0003A1 }, /* 038E-03A1 */ { 0x0003A3, 0x0003CE }, /* 03A3-03CE */ { 0x0003D0, 0x0003F5 }, /* 03D0-03F5 */ { 0x000400, 0x000482 }, /* 0400-0482 */ { 0x00048A, 0x0004CE }, /* 048A-04CE */ { 0x0004D0, 0x0004F5 }, /* 04D0-04F5 */ { 0x0004F8, 0x0004F9 }, /* 04F8-04F9 */ { 0x000500, 0x00050F }, /* 0500-050F */ { 0x000531, 0x000556 }, /* 0531-0556 */ { 0x000559, 0x00055F }, /* 0559-055F */ { 0x000561, 0x000587 }, /* 0561-0587 */ { 0x000589 }, /* 0589 */ { 0x000903 }, /* 0903 */ { 0x000905, 0x000939 }, /* 0905-0939 */ { 0x00093D, 0x000940 }, /* 093D-0940 */ { 0x000949, 0x00094C }, /* 0949-094C */ { 0x000950 }, /* 0950 */ { 0x000958, 0x000961 }, /* 0958-0961 */ { 0x000964, 0x000970 }, /* 0964-0970 */ { 0x000982, 0x000983 }, /* 0982-0983 */ { 0x000985, 0x00098C }, /* 0985-098C */ { 0x00098F, 0x000990 }, /* 098F-0990 */ { 0x000993, 0x0009A8 }, /* 0993-09A8 */ { 0x0009AA, 0x0009B0 }, /* 09AA-09B0 */ { 0x0009B2 }, /* 09B2 */ { 0x0009B6, 0x0009B9 }, /* 09B6-09B9 */ { 0x0009BE, 0x0009C0 }, /* 09BE-09C0 */ { 0x0009C7, 0x0009C8 }, /* 09C7-09C8 */ { 0x0009CB, 0x0009CC }, /* 09CB-09CC */ { 0x0009D7 }, /* 09D7 */ { 0x0009DC, 0x0009DD }, /* 09DC-09DD */ { 0x0009DF, 0x0009E1 }, /* 09DF-09E1 */ { 0x0009E6, 0x0009F1 }, /* 09E6-09F1 */ { 0x0009F4, 0x0009FA }, /* 09F4-09FA */ { 0x000A05, 0x000A0A }, /* 0A05-0A0A */ { 0x000A0F, 0x000A10 }, /* 0A0F-0A10 */ { 0x000A13, 0x000A28 }, /* 0A13-0A28 */ { 0x000A2A, 0x000A30 }, /* 0A2A-0A30 */ { 0x000A32, 0x000A33 }, /* 0A32-0A33 */ { 0x000A35, 0x000A36 }, /* 0A35-0A36 */ { 0x000A38, 0x000A39 }, /* 0A38-0A39 */ { 0x000A3E, 0x000A40 }, /* 0A3E-0A40 */ { 0x000A59, 0x000A5C }, /* 0A59-0A5C */ { 0x000A5E }, /* 0A5E */ { 0x000A66, 0x000A6F }, /* 0A66-0A6F */ { 0x000A72, 0x000A74 }, /* 0A72-0A74 */ { 0x000A83 }, /* 0A83 */ { 0x000A85, 0x000A8B }, /* 0A85-0A8B */ { 0x000A8D }, /* 0A8D */ { 0x000A8F, 0x000A91 }, /* 0A8F-0A91 */ { 0x000A93, 0x000AA8 }, /* 0A93-0AA8 */ { 0x000AAA, 0x000AB0 }, /* 0AAA-0AB0 */ { 0x000AB2, 0x000AB3 }, /* 0AB2-0AB3 */ { 0x000AB5, 0x000AB9 }, /* 0AB5-0AB9 */ { 0x000ABD, 0x000AC0 }, /* 0ABD-0AC0 */ { 0x000AC9 }, /* 0AC9 */ { 0x000ACB, 0x000ACC }, /* 0ACB-0ACC */ { 0x000AD0 }, /* 0AD0 */ { 0x000AE0 }, /* 0AE0 */ { 0x000AE6, 0x000AEF }, /* 0AE6-0AEF */ { 0x000B02, 0x000B03 }, /* 0B02-0B03 */ { 0x000B05, 0x000B0C }, /* 0B05-0B0C */ { 0x000B0F, 0x000B10 }, /* 0B0F-0B10 */ { 0x000B13, 0x000B28 }, /* 0B13-0B28 */ { 0x000B2A, 0x000B30 }, /* 0B2A-0B30 */ { 0x000B32, 0x000B33 }, /* 0B32-0B33 */ { 0x000B36, 0x000B39 }, /* 0B36-0B39 */ { 0x000B3D, 0x000B3E }, /* 0B3D-0B3E */ { 0x000B40 }, /* 0B40 */ { 0x000B47, 0x000B48 }, /* 0B47-0B48 */ { 0x000B4B, 0x000B4C }, /* 0B4B-0B4C */ { 0x000B57 }, /* 0B57 */ { 0x000B5C, 0x000B5D }, /* 0B5C-0B5D */ { 0x000B5F, 0x000B61 }, /* 0B5F-0B61 */ { 0x000B66, 0x000B70 }, /* 0B66-0B70 */ { 0x000B83 }, /* 0B83 */ { 0x000B85, 0x000B8A }, /* 0B85-0B8A */ { 0x000B8E, 0x000B90 }, /* 0B8E-0B90 */ { 0x000B92, 0x000B95 }, /* 0B92-0B95 */ { 0x000B99, 0x000B9A }, /* 0B99-0B9A */ { 0x000B9C }, /* 0B9C */ { 0x000B9E, 0x000B9F }, /* 0B9E-0B9F */ { 0x000BA3, 0x000BA4 }, /* 0BA3-0BA4 */ { 0x000BA8, 0x000BAA }, /* 0BA8-0BAA */ { 0x000BAE, 0x000BB5 }, /* 0BAE-0BB5 */ { 0x000BB7, 0x000BB9 }, /* 0BB7-0BB9 */ { 0x000BBE, 0x000BBF }, /* 0BBE-0BBF */ { 0x000BC1, 0x000BC2 }, /* 0BC1-0BC2 */ { 0x000BC6, 0x000BC8 }, /* 0BC6-0BC8 */ { 0x000BCA, 0x000BCC }, /* 0BCA-0BCC */ { 0x000BD7 }, /* 0BD7 */ { 0x000BE7, 0x000BF2 }, /* 0BE7-0BF2 */ { 0x000C01, 0x000C03 }, /* 0C01-0C03 */ { 0x000C05, 0x000C0C }, /* 0C05-0C0C */ { 0x000C0E, 0x000C10 }, /* 0C0E-0C10 */ { 0x000C12, 0x000C28 }, /* 0C12-0C28 */ { 0x000C2A, 0x000C33 }, /* 0C2A-0C33 */ { 0x000C35, 0x000C39 }, /* 0C35-0C39 */ { 0x000C41, 0x000C44 }, /* 0C41-0C44 */ { 0x000C60, 0x000C61 }, /* 0C60-0C61 */ { 0x000C66, 0x000C6F }, /* 0C66-0C6F */ { 0x000C82, 0x000C83 }, /* 0C82-0C83 */ { 0x000C85, 0x000C8C }, /* 0C85-0C8C */ { 0x000C8E, 0x000C90 }, /* 0C8E-0C90 */ { 0x000C92, 0x000CA8 }, /* 0C92-0CA8 */ { 0x000CAA, 0x000CB3 }, /* 0CAA-0CB3 */ { 0x000CB5, 0x000CB9 }, /* 0CB5-0CB9 */ { 0x000CBE }, /* 0CBE */ { 0x000CC0, 0x000CC4 }, /* 0CC0-0CC4 */ { 0x000CC7, 0x000CC8 }, /* 0CC7-0CC8 */ { 0x000CCA, 0x000CCB }, /* 0CCA-0CCB */ { 0x000CD5, 0x000CD6 }, /* 0CD5-0CD6 */ { 0x000CDE }, /* 0CDE */ { 0x000CE0, 0x000CE1 }, /* 0CE0-0CE1 */ { 0x000CE6, 0x000CEF }, /* 0CE6-0CEF */ { 0x000D02, 0x000D03 }, /* 0D02-0D03 */ { 0x000D05, 0x000D0C }, /* 0D05-0D0C */ { 0x000D0E, 0x000D10 }, /* 0D0E-0D10 */ { 0x000D12, 0x000D28 }, /* 0D12-0D28 */ { 0x000D2A, 0x000D39 }, /* 0D2A-0D39 */ { 0x000D3E, 0x000D40 }, /* 0D3E-0D40 */ { 0x000D46, 0x000D48 }, /* 0D46-0D48 */ { 0x000D4A, 0x000D4C }, /* 0D4A-0D4C */ { 0x000D57 }, /* 0D57 */ { 0x000D60, 0x000D61 }, /* 0D60-0D61 */ { 0x000D66, 0x000D6F }, /* 0D66-0D6F */ { 0x000D82, 0x000D83 }, /* 0D82-0D83 */ { 0x000D85, 0x000D96 }, /* 0D85-0D96 */ { 0x000D9A, 0x000DB1 }, /* 0D9A-0DB1 */ { 0x000DB3, 0x000DBB }, /* 0DB3-0DBB */ { 0x000DBD }, /* 0DBD */ { 0x000DC0, 0x000DC6 }, /* 0DC0-0DC6 */ { 0x000DCF, 0x000DD1 }, /* 0DCF-0DD1 */ { 0x000DD8, 0x000DDF }, /* 0DD8-0DDF */ { 0x000DF2, 0x000DF4 }, /* 0DF2-0DF4 */ { 0x000E01, 0x000E30 }, /* 0E01-0E30 */ { 0x000E32, 0x000E33 }, /* 0E32-0E33 */ { 0x000E40, 0x000E46 }, /* 0E40-0E46 */ { 0x000E4F, 0x000E5B }, /* 0E4F-0E5B */ { 0x000E81, 0x000E82 }, /* 0E81-0E82 */ { 0x000E84 }, /* 0E84 */ { 0x000E87, 0x000E88 }, /* 0E87-0E88 */ { 0x000E8A }, /* 0E8A */ { 0x000E8D }, /* 0E8D */ { 0x000E94, 0x000E97 }, /* 0E94-0E97 */ { 0x000E99, 0x000E9F }, /* 0E99-0E9F */ { 0x000EA1, 0x000EA3 }, /* 0EA1-0EA3 */ { 0x000EA5 }, /* 0EA5 */ { 0x000EA7 }, /* 0EA7 */ { 0x000EAA, 0x000EAB }, /* 0EAA-0EAB */ { 0x000EAD, 0x000EB0 }, /* 0EAD-0EB0 */ { 0x000EB2, 0x000EB3 }, /* 0EB2-0EB3 */ { 0x000EBD }, /* 0EBD */ { 0x000EC0, 0x000EC4 }, /* 0EC0-0EC4 */ { 0x000EC6 }, /* 0EC6 */ { 0x000ED0, 0x000ED9 }, /* 0ED0-0ED9 */ { 0x000EDC, 0x000EDD }, /* 0EDC-0EDD */ { 0x000F00, 0x000F17 }, /* 0F00-0F17 */ { 0x000F1A, 0x000F34 }, /* 0F1A-0F34 */ { 0x000F36 }, /* 0F36 */ { 0x000F38 }, /* 0F38 */ { 0x000F3E, 0x000F47 }, /* 0F3E-0F47 */ { 0x000F49, 0x000F6A }, /* 0F49-0F6A */ { 0x000F7F }, /* 0F7F */ { 0x000F85 }, /* 0F85 */ { 0x000F88, 0x000F8B }, /* 0F88-0F8B */ { 0x000FBE, 0x000FC5 }, /* 0FBE-0FC5 */ { 0x000FC7, 0x000FCC }, /* 0FC7-0FCC */ { 0x000FCF }, /* 0FCF */ { 0x001000, 0x001021 }, /* 1000-1021 */ { 0x001023, 0x001027 }, /* 1023-1027 */ { 0x001029, 0x00102A }, /* 1029-102A */ { 0x00102C }, /* 102C */ { 0x001031 }, /* 1031 */ { 0x001038 }, /* 1038 */ { 0x001040, 0x001057 }, /* 1040-1057 */ { 0x0010A0, 0x0010C5 }, /* 10A0-10C5 */ { 0x0010D0, 0x0010F8 }, /* 10D0-10F8 */ { 0x0010FB }, /* 10FB */ { 0x001100, 0x001159 }, /* 1100-1159 */ { 0x00115F, 0x0011A2 }, /* 115F-11A2 */ { 0x0011A8, 0x0011F9 }, /* 11A8-11F9 */ { 0x001200, 0x001206 }, /* 1200-1206 */ { 0x001208, 0x001246 }, /* 1208-1246 */ { 0x001248 }, /* 1248 */ { 0x00124A, 0x00124D }, /* 124A-124D */ { 0x001250, 0x001256 }, /* 1250-1256 */ { 0x001258 }, /* 1258 */ { 0x00125A, 0x00125D }, /* 125A-125D */ { 0x001260, 0x001286 }, /* 1260-1286 */ { 0x001288 }, /* 1288 */ { 0x00128A, 0x00128D }, /* 128A-128D */ { 0x001290, 0x0012AE }, /* 1290-12AE */ { 0x0012B0 }, /* 12B0 */ { 0x0012B2, 0x0012B5 }, /* 12B2-12B5 */ { 0x0012B8, 0x0012BE }, /* 12B8-12BE */ { 0x0012C0 }, /* 12C0 */ { 0x0012C2, 0x0012C5 }, /* 12C2-12C5 */ { 0x0012C8, 0x0012CE }, /* 12C8-12CE */ { 0x0012D0, 0x0012D6 }, /* 12D0-12D6 */ { 0x0012D8, 0x0012EE }, /* 12D8-12EE */ { 0x0012F0, 0x00130E }, /* 12F0-130E */ { 0x001310 }, /* 1310 */ { 0x001312, 0x001315 }, /* 1312-1315 */ { 0x001318, 0x00131E }, /* 1318-131E */ { 0x001320, 0x001346 }, /* 1320-1346 */ { 0x001348, 0x00135A }, /* 1348-135A */ { 0x001361, 0x00137C }, /* 1361-137C */ { 0x0013A0, 0x0013F4 }, /* 13A0-13F4 */ { 0x001401, 0x001676 }, /* 1401-1676 */ { 0x001681, 0x00169A }, /* 1681-169A */ { 0x0016A0, 0x0016F0 }, /* 16A0-16F0 */ { 0x001700, 0x00170C }, /* 1700-170C */ { 0x00170E, 0x001711 }, /* 170E-1711 */ { 0x001720, 0x001731 }, /* 1720-1731 */ { 0x001735, 0x001736 }, /* 1735-1736 */ { 0x001740, 0x001751 }, /* 1740-1751 */ { 0x001760, 0x00176C }, /* 1760-176C */ { 0x00176E, 0x001770 }, /* 176E-1770 */ { 0x001780, 0x0017B6 }, /* 1780-17B6 */ { 0x0017BE, 0x0017C5 }, /* 17BE-17C5 */ { 0x0017C7, 0x0017C8 }, /* 17C7-17C8 */ { 0x0017D4, 0x0017DA }, /* 17D4-17DA */ { 0x0017DC }, /* 17DC */ { 0x0017E0, 0x0017E9 }, /* 17E0-17E9 */ { 0x001810, 0x001819 }, /* 1810-1819 */ { 0x001820, 0x001877 }, /* 1820-1877 */ { 0x001880, 0x0018A8 }, /* 1880-18A8 */ { 0x001E00, 0x001E9B }, /* 1E00-1E9B */ { 0x001EA0, 0x001EF9 }, /* 1EA0-1EF9 */ { 0x001F00, 0x001F15 }, /* 1F00-1F15 */ { 0x001F18, 0x001F1D }, /* 1F18-1F1D */ { 0x001F20, 0x001F45 }, /* 1F20-1F45 */ { 0x001F48, 0x001F4D }, /* 1F48-1F4D */ { 0x001F50, 0x001F57 }, /* 1F50-1F57 */ { 0x001F59 }, /* 1F59 */ { 0x001F5B }, /* 1F5B */ { 0x001F5D }, /* 1F5D */ { 0x001F5F, 0x001F7D }, /* 1F5F-1F7D */ { 0x001F80, 0x001FB4 }, /* 1F80-1FB4 */ { 0x001FB6, 0x001FBC }, /* 1FB6-1FBC */ { 0x001FBE }, /* 1FBE */ { 0x001FC2, 0x001FC4 }, /* 1FC2-1FC4 */ { 0x001FC6, 0x001FCC }, /* 1FC6-1FCC */ { 0x001FD0, 0x001FD3 }, /* 1FD0-1FD3 */ { 0x001FD6, 0x001FDB }, /* 1FD6-1FDB */ { 0x001FE0, 0x001FEC }, /* 1FE0-1FEC */ { 0x001FF2, 0x001FF4 }, /* 1FF2-1FF4 */ { 0x001FF6, 0x001FFC }, /* 1FF6-1FFC */ { 0x00200E }, /* 200E */ { 0x002071 }, /* 2071 */ { 0x00207F }, /* 207F */ { 0x002102 }, /* 2102 */ { 0x002107 }, /* 2107 */ { 0x00210A, 0x002113 }, /* 210A-2113 */ { 0x002115 }, /* 2115 */ { 0x002119, 0x00211D }, /* 2119-211D */ { 0x002124 }, /* 2124 */ { 0x002126 }, /* 2126 */ { 0x002128 }, /* 2128 */ { 0x00212A, 0x00212D }, /* 212A-212D */ { 0x00212F, 0x002131 }, /* 212F-2131 */ { 0x002133, 0x002139 }, /* 2133-2139 */ { 0x00213D, 0x00213F }, /* 213D-213F */ { 0x002145, 0x002149 }, /* 2145-2149 */ { 0x002160, 0x002183 }, /* 2160-2183 */ { 0x002336, 0x00237A }, /* 2336-237A */ { 0x002395 }, /* 2395 */ { 0x00249C, 0x0024E9 }, /* 249C-24E9 */ { 0x003005, 0x003007 }, /* 3005-3007 */ { 0x003021, 0x003029 }, /* 3021-3029 */ { 0x003031, 0x003035 }, /* 3031-3035 */ { 0x003038, 0x00303C }, /* 3038-303C */ { 0x003041, 0x003096 }, /* 3041-3096 */ { 0x00309D, 0x00309F }, /* 309D-309F */ { 0x0030A1, 0x0030FA }, /* 30A1-30FA */ { 0x0030FC, 0x0030FF }, /* 30FC-30FF */ { 0x003105, 0x00312C }, /* 3105-312C */ { 0x003131, 0x00318E }, /* 3131-318E */ { 0x003190, 0x0031B7 }, /* 3190-31B7 */ { 0x0031F0, 0x00321C }, /* 31F0-321C */ { 0x003220, 0x003243 }, /* 3220-3243 */ { 0x003260, 0x00327B }, /* 3260-327B */ { 0x00327F, 0x0032B0 }, /* 327F-32B0 */ { 0x0032C0, 0x0032CB }, /* 32C0-32CB */ { 0x0032D0, 0x0032FE }, /* 32D0-32FE */ { 0x003300, 0x003376 }, /* 3300-3376 */ { 0x00337B, 0x0033DD }, /* 337B-33DD */ { 0x0033E0, 0x0033FE }, /* 33E0-33FE */ { 0x003400, 0x004DB5 }, /* 3400-4DB5 */ { 0x004E00, 0x009FA5 }, /* 4E00-9FA5 */ { 0x00A000, 0x00A48C }, /* A000-A48C */ { 0x00AC00, 0x00D7A3 }, /* AC00-D7A3 */ { 0x00D800, 0x00FA2D }, /* D800-FA2D */ { 0x00FA30, 0x00FA6A }, /* FA30-FA6A */ { 0x00FB00, 0x00FB06 }, /* FB00-FB06 */ { 0x00FB13, 0x00FB17 }, /* FB13-FB17 */ { 0x00FF21, 0x00FF3A }, /* FF21-FF3A */ { 0x00FF41, 0x00FF5A }, /* FF41-FF5A */ { 0x00FF66, 0x00FFBE }, /* FF66-FFBE */ { 0x00FFC2, 0x00FFC7 }, /* FFC2-FFC7 */ { 0x00FFCA, 0x00FFCF }, /* FFCA-FFCF */ { 0x00FFD2, 0x00FFD7 }, /* FFD2-FFD7 */ { 0x00FFDA, 0x00FFDC }, /* FFDA-FFDC */ { 0x010300, 0x01031E }, /* 10300-1031E */ { 0x010320, 0x010323 }, /* 10320-10323 */ { 0x010330, 0x01034A }, /* 10330-1034A */ { 0x010400, 0x010425 }, /* 10400-10425 */ { 0x010428, 0x01044D }, /* 10428-1044D */ { 0x01D000, 0x01D0F5 }, /* 1D000-1D0F5 */ { 0x01D100, 0x01D126 }, /* 1D100-1D126 */ { 0x01D12A, 0x01D166 }, /* 1D12A-1D166 */ { 0x01D16A, 0x01D172 }, /* 1D16A-1D172 */ { 0x01D183, 0x01D184 }, /* 1D183-1D184 */ { 0x01D18C, 0x01D1A9 }, /* 1D18C-1D1A9 */ { 0x01D1AE, 0x01D1DD }, /* 1D1AE-1D1DD */ { 0x01D400, 0x01D454 }, /* 1D400-1D454 */ { 0x01D456, 0x01D49C }, /* 1D456-1D49C */ { 0x01D49E, 0x01D49F }, /* 1D49E-1D49F */ { 0x01D4A2 }, /* 1D4A2 */ { 0x01D4A5, 0x01D4A6 }, /* 1D4A5-1D4A6 */ { 0x01D4A9, 0x01D4AC }, /* 1D4A9-1D4AC */ { 0x01D4AE, 0x01D4B9 }, /* 1D4AE-1D4B9 */ { 0x01D4BB }, /* 1D4BB */ { 0x01D4BD, 0x01D4C0 }, /* 1D4BD-1D4C0 */ { 0x01D4C2, 0x01D4C3 }, /* 1D4C2-1D4C3 */ { 0x01D4C5, 0x01D505 }, /* 1D4C5-1D505 */ { 0x01D507, 0x01D50A }, /* 1D507-1D50A */ { 0x01D50D, 0x01D514 }, /* 1D50D-1D514 */ { 0x01D516, 0x01D51C }, /* 1D516-1D51C */ { 0x01D51E, 0x01D539 }, /* 1D51E-1D539 */ { 0x01D53B, 0x01D53E }, /* 1D53B-1D53E */ { 0x01D540, 0x01D544 }, /* 1D540-1D544 */ { 0x01D546 }, /* 1D546 */ { 0x01D54A, 0x01D550 }, /* 1D54A-1D550 */ { 0x01D552, 0x01D6A3 }, /* 1D552-1D6A3 */ { 0x01D6A8, 0x01D7C9 }, /* 1D6A8-1D7C9 */ { 0x020000, 0x02A6D6 }, /* 20000-2A6D6 */ { 0x02F800, 0x02FA1D }, /* 2F800-2FA1D */ { 0x0F0000, 0x0FFFFD }, /* F0000-FFFFD */ { 0x100000, 0x10FFFD }, /* 100000-10FFFD */ { 0 }, }; psi-0.14/iris/src/libidn/idna.h0000644000175000017500000000517211305557616014433 0ustar janjan/* idna.h Declarations for IDNA. * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _IDNA_H #define _IDNA_H #ifdef __cplusplus extern "C" { #endif #include /* size_t */ #include /* my_uint32_t */ /* Error codes. */ typedef enum { IDNA_SUCCESS = 0, IDNA_STRINGPREP_ERROR = 1, IDNA_PUNYCODE_ERROR = 2, IDNA_CONTAINS_LDH = 3, IDNA_CONTAINS_MINUS = 4, IDNA_INVALID_LENGTH = 5, IDNA_NO_ACE_PREFIX = 6, IDNA_ROUNDTRIP_VERIFY_ERROR = 7, IDNA_CONTAINS_ACE_PREFIX = 8, IDNA_ICONV_ERROR = 9, /* Internal errors. */ IDNA_MALLOC_ERROR = 201 } Idna_rc; /* IDNA flags */ typedef enum { IDNA_ALLOW_UNASSIGNED = 0x0001, IDNA_USE_STD3_ASCII_RULES = 0x0002 } Idna_flags; #ifndef IDNA_ACE_PREFIX #define IDNA_ACE_PREFIX "xn--" #endif /* Core functions */ extern int idna_to_ascii_4i (const my_uint32_t * in, size_t inlen, char *out, int flags); extern int idna_to_unicode_44i (const my_uint32_t * in, size_t inlen, my_uint32_t * out, size_t * outlen, int flags); /* Wrappers that handle several labels */ extern int idna_to_ascii_4z (const my_uint32_t * input, char **output, int flags); extern int idna_to_ascii_8z (const char *input, char **output, int flags); extern int idna_to_ascii_lz (const char *input, char **output, int flags); extern int idna_to_unicode_4z4z (const my_uint32_t * input, my_uint32_t ** output, int flags); extern int idna_to_unicode_8z4z (const char *input, my_uint32_t ** output, int flags); extern int idna_to_unicode_8z8z (const char *input, char **output, int flags); extern int idna_to_unicode_8zlz (const char *input, char **output, int flags); extern int idna_to_unicode_lzlz (const char *input, char **output, int flags); #ifdef __cplusplus } #endif #endif /* _PUNYCODE_H */ psi-0.14/iris/src/libidn/profiles.c0000644000175000017500000003557511305557616015350 0ustar janjan/* profiles.c Definitions of stringprep profiles. * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "internal.h" Stringprep_profiles stringprep_profiles[] = { {"generic", stringprep_generic} , {"Nameprep", stringprep_nameprep} , {"KRBprep", stringprep_kerberos5} , {"Nodeprep", stringprep_xmpp_nodeprep} , {"Resourceprep", stringprep_xmpp_resourceprep} , {"plain", stringprep_plain} , {"SASLprep", stringprep_saslprep} , {"ISCSIprep", stringprep_iscsi} , {NULL, NULL} }; Stringprep_profile stringprep_generic[] = { /* 1) Map -- For each character in the input, check if it has a mapping and, if so, replace it with its mapping. This is described in section 3. */ {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_MAP_TABLE, ~STRINGPREP_NO_NFKC, stringprep_rfc3454_B_2, "B.2"} , {STRINGPREP_MAP_TABLE, STRINGPREP_NO_NFKC, stringprep_rfc3454_B_3, "B.3"} , /* 2) Normalize -- Possibly normalize the result of step 1 using Unicode normalization. This is described in section 4. */ {STRINGPREP_NFKC, ~STRINGPREP_NO_NFKC, 0, "NFKC"} , /* 3) Prohibit -- Check for any characters that are not allowed in the output. If any are found, return an error. This is described in section 5. */ {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1, "C.1.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.2.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7, "C.7"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , /* 4) Check bidi -- Possibly check for right-to-left characters, and if any are found, make sure that the whole string satisfies the requirements for bidirectional strings. If the string does not satisfy the requirements for bidirectional strings, return an error. This is described in section 6. */ {STRINGPREP_BIDI, ~STRINGPREP_NO_BIDI, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_2, "D.2"} , /* 5) Check unassigned code points -- Possibly check the output for unassigned code points, according to the profile. This is described in section 7. */ {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; Stringprep_profile stringprep_nameprep[] = { {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2, "B.2"} , {STRINGPREP_NFKC, 0, 0, "NFKC"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7, "C.7"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, 0, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, 0, stringprep_rfc3454_D_2, "D.2"} , {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; Stringprep_profile stringprep_kerberos5[] = { /* XXX this is likely to be wrong as the specification is a rough draft. */ {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_3, "B.2"} , {STRINGPREP_NFKC, 0, 0, "NFKC"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7, "C.7"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, 0, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, 0, stringprep_rfc3454_D_2, "D.2"} , {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; Stringprep_table_element stringprep_xmpp_nodeprep_prohibit[] = { {0x000022} , /* #x22 (") */ {0x000026} , /* #x26 (&) */ {0x000027} , /* #x27 (') */ {0x00002F} , /* #x2F (/) */ {0x00003A} , /* #x3A (:) */ {0x00003C} , /* #x3C (<) */ {0x00003E} , /* #x3E (>) */ {0x000040} /* #x40 (@) */ , {0} }; Stringprep_profile stringprep_xmpp_nodeprep[] = { {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2, "B.2"} , {STRINGPREP_NFKC, 0, 0, "NFKC"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1, "C.1.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.2.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7, "C.7"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_xmpp_nodeprep_prohibit, "XMPP-PROHIBIT"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, 0, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, 0, stringprep_rfc3454_D_2, "D.2"} , {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; Stringprep_profile stringprep_xmpp_resourceprep[] = { {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_NFKC, 0, 0, "NFKC"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.2.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7, "C.7"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_2, "D.2"} , {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; Stringprep_profile stringprep_plain[] = { {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.2.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_2, "D.2"} , {0} }; Stringprep_table_element stringprep_iscsi_prohibit[] = { {0x0000} , /* [ASCII CONTROL CHARACTERS and SPACE through ,] */ {0x0001} , {0x0002} , {0x0003} , {0x0004} , {0x0005} , {0x0006} , {0x0007} , {0x0008} , {0x0009} , {0x000A} , {0x000B} , {0x000C} , {0x000D} , {0x000E} , {0x000F} , {0x0010} , {0x0011} , {0x0012} , {0x0013} , {0x0014} , {0x0015} , {0x0016} , {0x0017} , {0x0018} , {0x0019} , {0x001A} , {0x001B} , {0x001C} , {0x001D} , {0x001E} , {0x001F} , {0x0020} , {0x0021} , {0x0022} , {0x0023} , {0x0024} , {0x0025} , {0x0026} , {0x0027} , {0x0028} , {0x0029} , {0x002A} , {0x002B} , {0x002C} , {0x002F} , /* [ASCII /] */ {0x003B} , /* [ASCII ; through @] */ {0x003C} , {0x003D} , {0x003E} , {0x003F} , {0x0040} , {0x005B} , /* [ASCII [ through `] */ {0x005C} , {0x005D} , {0x005E} , {0x005F} , {0x0060} , {0x007B} , /* [ASCII { through DEL] */ {0x007C} , {0x007D} , {0x007E} , {0x007F} , {0x3002} , /* ideographic full stop */ {0} }; Stringprep_profile stringprep_iscsi[] = { {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2, "B.2"} , {STRINGPREP_NFKC, 0, 0, "NFKC"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.1.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.2.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_iscsi_prohibit, "ISCSI-PROHIBIT"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_2, "D.2"} , {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; Stringprep_table_element stringprep_saslprep_space_map[] = { {0x0000A0, 0, {0x0020} } , /* 00A0; NO-BREAK SPACE */ {0x001680, 0, {0x0020} } , /* 1680; OGHAM SPACE MARK */ {0x002000, 0, {0x0020} } , /* 2000; EN QUAD */ {0x002001, 0, {0x0020} } , /* 2001; EM QUAD */ {0x002002, 0, {0x0020} } , /* 2002; EN SPACE */ {0x002003, 0, {0x0020} } , /* 2003; EM SPACE */ {0x002004, 0, {0x0020} } , /* 2004; THREE-PER-EM SPACE */ {0x002005, 0, {0x0020} } , /* 2005; FOUR-PER-EM SPACE */ {0x002006, 0, {0x0020} } , /* 2006; SIX-PER-EM SPACE */ {0x002007, 0, {0x0020} } , /* 2007; FIGURE SPACE */ {0x002008, 0, {0x0020} } , /* 2008; PUNCTUATION SPACE */ {0x002009, 0, {0x0020} } , /* 2009; THIN SPACE */ {0x00200A, 0, {0x0020} } , /* 200A; HAIR SPACE */ {0x00200B, 0, {0x0020} } , /* 200B; ZERO WIDTH SPACE */ {0x00202F, 0, {0x0020} } , /* 202F; NARROW NO-BREAK SPACE */ {0x00205F, 0, {0x0020} } , /* 205F; MEDIUM MATHEMATICAL SPACE */ {0x003000, 0, {0x0020} } , /* 3000; IDEOGRAPHIC SPACE */ {0} }; Stringprep_profile stringprep_saslprep[] = { {STRINGPREP_MAP_TABLE, 0, stringprep_saslprep_space_map, "SASL-SPACE-MAP"} , {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1, "B.1"} , {STRINGPREP_NFKC, 0, 0, "NFKC"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.1.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1, "C.2.1"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2, "C.2.2"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3, "C.3"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4, "C.4"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5, "C.5"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6, "C.6"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7, "C.7"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9, "C.9"} , {STRINGPREP_BIDI, 0, 0, "BIDI"} , {STRINGPREP_BIDI_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8, "C.8"} , {STRINGPREP_BIDI_RAL_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_1, "D.1"} , {STRINGPREP_BIDI_L_TABLE, ~STRINGPREP_NO_BIDI, stringprep_rfc3454_D_2, "D.2"} , {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED, stringprep_rfc3454_A_1, "A.1"} , {0} }; psi-0.14/iris/src/libidn/internal.h0000644000175000017500000001062011305557616015326 0ustar janjan/* internal.h Internal header file for libidn. * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _INTERNAL_H #define _INTERNAL_H #define STDC_HEADERS 1 #ifdef _LIBC # include # include # include # include # include //# define HAVE_ICONV 1 //# define LOCALE_WORKS 1 //# define ICONV_CONST #else /* _LIBC */ # if HAVE_CONFIG_H # include "config.h" # endif # if STDC_HEADERS # include # include # include # include # include # endif # if HAVE_UNISTD_H # include # endif # if HAVE_ERRNO_H # include # endif # if defined(WITH_DMALLOC) && WITH_DMALLOC # include # endif #endif /* _LIBC */ #include "libidn/stringprep.h" #include "libidn/punycode.h" #include "libidn/idna.h" /*! \mainpage GNU Internationalized Domain Name Library * * \section intro Introduction * * GNU Libidn is an implementation of the Stringprep, Punycode and IDNA * specifications defined by the IETF Internationalized Domain Names * (IDN) working group, used for internationalized domain names. The * package is available under the GNU Lesser General Public License. * * The library contains a generic Stringprep implementation that does * Unicode 3.2 NFKC normalization, mapping and prohibitation of * characters, and bidirectional character handling. Profiles for iSCSI, * Kerberos 5, Nameprep, SASL and XMPP are included. Punycode and ASCII * Compatible Encoding (ACE) via IDNA are supported. * * The Stringprep API consists of two main functions, one for converting * data from the system's native representation into UTF-8, and one * function to perform the Stringprep processing. Adding a new * Stringprep profile for your application within the API is * straightforward. The Punycode API consists of one encoding function * and one decoding function. The IDNA API consists of the ToASCII and * ToUnicode functions, as well as an high-level interface for converting * entire domain names to and from the ACE encoded form. * * The library is used by, e.g., GNU SASL and Shishi to process user * names and passwords. Libidn can be built into GNU Libc to enable a * new system-wide getaddrinfo() flag for IDN processing. * * Libidn is developed for the GNU/Linux system, but runs on over 20 Unix * platforms (including Solaris, IRIX, AIX, and Tru64) and Windows. * Libidn is written in C and (parts of) the API is accessible from C, * C++, Emacs Lisp, Python and Java. * * The project web page:\n * http://www.gnu.org/software/libidn/ * * The software archive:\n * ftp://alpha.gnu.org/pub/gnu/libidn/ * * For more information see:\n * http://www.ietf.org/html.charters/idn-charter.html\n * http://www.ietf.org/rfc/rfc3454.txt (stringprep specification)\n * http://www.ietf.org/rfc/rfc3490.txt (idna specification)\n * http://www.ietf.org/rfc/rfc3491.txt (nameprep specification)\n * http://www.ietf.org/rfc/rfc3492.txt (punycode specification)\n * http://www.ietf.org/internet-drafts/draft-ietf-ips-iscsi-string-prep-04.txt\n * http://www.ietf.org/internet-drafts/draft-ietf-krb-wg-utf8-profile-01.txt\n * http://www.ietf.org/internet-drafts/draft-ietf-sasl-anon-00.txt\n * http://www.ietf.org/internet-drafts/draft-ietf-sasl-saslprep-00.txt\n * http://www.ietf.org/internet-drafts/draft-ietf-xmpp-nodeprep-01.txt\n * http://www.ietf.org/internet-drafts/draft-ietf-xmpp-resourceprep-01.txt\n * * Further information and paid contract development:\n * Simon Josefsson * * \section examples Examples * * \include example.c * \include example3.c * \include example4.c */ #endif /* _INTERNAL_H */ psi-0.14/iris/src/libidn/nfkc.c0000644000175000017500000006253011305557616014435 0ustar janjan/* nfkc.c Unicode normalization utilities. * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "internal.h" /* This file contains functions from GLIB, including gutf8.c and * gunidecomp.c, all licensed under LGPL and copyright hold by: * * Copyright (C) 1999, 2000 Tom Tromey * Copyright 2000 Red Hat, Inc. */ /* Hacks to make syncing with GLIB code easier. */ #define gboolean int #define gchar char #define guchar unsigned char #define glong long #define gint int #define guint unsigned int #define gushort unsigned short #define gint16 my_int16_t #define guint16 my_uint16_t #define gunichar my_uint32_t #define gsize size_t #define gssize ssize_t #define g_malloc malloc #define g_free free #define GError void #define g_set_error(a,b,c,d) 0 #define g_new(struct_type, n_structs) \ ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) # if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) # define G_STMT_START (void)( # define G_STMT_END ) # else # if (defined (sun) || defined (__sun__)) # define G_STMT_START if (1) # define G_STMT_END else (void)0 # else # define G_STMT_START do # define G_STMT_END while (0) # endif # endif #define g_return_val_if_fail(expr,val) G_STMT_START{ (void)0; }G_STMT_END #define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) #define TRUE 1 #define FALSE 0 /* Code from GLIB gunicode.h starts here. */ typedef enum { G_NORMALIZE_DEFAULT, G_NORMALIZE_NFD = G_NORMALIZE_DEFAULT, G_NORMALIZE_DEFAULT_COMPOSE, G_NORMALIZE_NFC = G_NORMALIZE_DEFAULT_COMPOSE, G_NORMALIZE_ALL, G_NORMALIZE_NFKD = G_NORMALIZE_ALL, G_NORMALIZE_ALL_COMPOSE, G_NORMALIZE_NFKC = G_NORMALIZE_ALL_COMPOSE } GNormalizeMode; /* Code from GLIB gutf8.c starts here. */ #define UTF8_COMPUTE(Char, Mask, Len) \ if (Char < 128) \ { \ Len = 1; \ Mask = 0x7f; \ } \ else if ((Char & 0xe0) == 0xc0) \ { \ Len = 2; \ Mask = 0x1f; \ } \ else if ((Char & 0xf0) == 0xe0) \ { \ Len = 3; \ Mask = 0x0f; \ } \ else if ((Char & 0xf8) == 0xf0) \ { \ Len = 4; \ Mask = 0x07; \ } \ else if ((Char & 0xfc) == 0xf8) \ { \ Len = 5; \ Mask = 0x03; \ } \ else if ((Char & 0xfe) == 0xfc) \ { \ Len = 6; \ Mask = 0x01; \ } \ else \ Len = -1; #define UTF8_LENGTH(Char) \ ((Char) < 0x80 ? 1 : \ ((Char) < 0x800 ? 2 : \ ((Char) < 0x10000 ? 3 : \ ((Char) < 0x200000 ? 4 : \ ((Char) < 0x4000000 ? 5 : 6))))) #define UTF8_GET(Result, Chars, Count, Mask, Len) \ (Result) = (Chars)[0] & (Mask); \ for ((Count) = 1; (Count) < (Len); ++(Count)) \ { \ if (((Chars)[(Count)] & 0xc0) != 0x80) \ { \ (Result) = -1; \ break; \ } \ (Result) <<= 6; \ (Result) |= ((Chars)[(Count)] & 0x3f); \ } #define UNICODE_VALID(Char) \ ((Char) < 0x110000 && \ (((Char) & 0xFFFFF800) != 0xD800) && \ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ ((Char) & 0xFFFE) != 0xFFFE) static const gchar utf8_skip_data[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 }; const gchar *const g_utf8_skip = utf8_skip_data; #define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(guchar *)(p)]) /** * g_utf8_strlen: * @p: pointer to the start of a UTF-8 encoded string. * @max: the maximum number of bytes to examine. If @max * is less than 0, then the string is assumed to be * nul-terminated. If @max is 0, @p will not be examined and * may be %NULL. * * Returns the length of the string in characters. * * Return value: the length of the string in characters **/ static glong g_utf8_strlen (const gchar * p, gssize max) { glong len = 0; const gchar *start = p; g_return_val_if_fail (p != NULL || max == 0, 0); if (max < 0) { while (*p) { p = g_utf8_next_char (p); ++len; } } else { if (max == 0 || !*p) return 0; p = g_utf8_next_char (p); while (p - start < max && *p) { ++len; p = g_utf8_next_char (p); } /* only do the last len increment if we got a complete * char (don't count partial chars) */ if (p - start == max) ++len; } return len; } /** * g_utf8_get_char: * @p: a pointer to Unicode character encoded as UTF-8 * * Converts a sequence of bytes encoded as UTF-8 to a Unicode character. * If @p does not point to a valid UTF-8 encoded character, results are * undefined. If you are not sure that the bytes are complete * valid Unicode characters, you should use g_utf8_get_char_validated() * instead. * * Return value: the resulting character **/ static gunichar g_utf8_get_char (const gchar * p) { int i, mask = 0, len; gunichar result; unsigned char c = (unsigned char) *p; UTF8_COMPUTE (c, mask, len); if (len == -1) return (gunichar) - 1; UTF8_GET (result, p, i, mask, len); return result; } /** * g_unichar_to_utf8: * @c: a ISO10646 character code * @outbuf: output buffer, must have at least 6 bytes of space. * If %NULL, the length will be computed and returned * and nothing will be written to @outbuf. * * Converts a single character to UTF-8. * * Return value: number of bytes written **/ static int g_unichar_to_utf8 (gunichar c, gchar * outbuf) { guint len = 0; int first; int i; if (c < 0x80) { first = 0; len = 1; } else if (c < 0x800) { first = 0xc0; len = 2; } else if (c < 0x10000) { first = 0xe0; len = 3; } else if (c < 0x200000) { first = 0xf0; len = 4; } else if (c < 0x4000000) { first = 0xf8; len = 5; } else { first = 0xfc; len = 6; } if (outbuf) { for (i = len - 1; i > 0; --i) { outbuf[i] = (c & 0x3f) | 0x80; c >>= 6; } outbuf[0] = c | first; } return len; } /** * g_utf8_to_ucs4_fast: * @str: a UTF-8 encoded string * @len: the maximum length of @str to use. If @len < 0, then * the string is nul-terminated. * @items_written: location to store the number of characters in the * result, or %NULL. * * Convert a string from UTF-8 to a 32-bit fixed width * representation as UCS-4, assuming valid UTF-8 input. * This function is roughly twice as fast as g_utf8_to_ucs4() * but does no error checking on the input. * * Return value: a pointer to a newly allocated UCS-4 string. * This value must be freed with g_free(). **/ static gunichar * g_utf8_to_ucs4_fast (const gchar * str, glong len, glong * items_written) { gint j, charlen; gunichar *result; gint n_chars, i; const gchar *p; g_return_val_if_fail (str != NULL, NULL); p = str; n_chars = 0; if (len < 0) { while (*p) { p = g_utf8_next_char (p); ++n_chars; } } else { while (p < str + len && *p) { p = g_utf8_next_char (p); ++n_chars; } } result = g_new (gunichar, n_chars + 1); p = str; for (i = 0; i < n_chars; i++) { gunichar wc = ((unsigned char *) p)[0]; if (wc < 0x80) { result[i] = wc; p++; } else { if (wc < 0xe0) { charlen = 2; wc &= 0x1f; } else if (wc < 0xf0) { charlen = 3; wc &= 0x0f; } else if (wc < 0xf8) { charlen = 4; wc &= 0x07; } else if (wc < 0xfc) { charlen = 5; wc &= 0x03; } else { charlen = 6; wc &= 0x01; } for (j = 1; j < charlen; j++) { wc <<= 6; wc |= ((unsigned char *) p)[j] & 0x3f; } result[i] = wc; p += charlen; } } result[i] = 0; if (items_written) *items_written = i; return result; } /** * g_ucs4_to_utf8: * @str: a UCS-4 encoded string * @len: the maximum length of @str to use. If @len < 0, then * the string is terminated with a 0 character. * @items_read: location to store number of characters read read, or %NULL. * @items_written: location to store number of bytes written or %NULL. * The value here stored does not include the trailing 0 * byte. * @error: location to store the error occuring, or %NULL to ignore * errors. Any of the errors in #GConvertError other than * %G_CONVERT_ERROR_NO_CONVERSION may occur. * * Convert a string from a 32-bit fixed width representation as UCS-4. * to UTF-8. The result will be terminated with a 0 byte. * * Return value: a pointer to a newly allocated UTF-8 string. * This value must be freed with g_free(). If an * error occurs, %NULL will be returned and * @error set. **/ static gchar * g_ucs4_to_utf8 (const gunichar * str, glong len, glong * items_read, glong * items_written, GError ** error) { gint result_length; gchar *result = NULL; gchar *p; gint i; result_length = 0; for (i = 0; len < 0 || i < len; i++) { if (!str[i]) break; if (str[i] >= 0x80000000) { if (items_read) *items_read = i; /*g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, _("Character out of range for UTF-8"));*/ goto err_out; } result_length += UTF8_LENGTH (str[i]); } result = g_malloc (result_length + 1); p = result; i = 0; while (p < result + result_length) p += g_unichar_to_utf8 (str[i++], p); *p = '\0'; if (items_written) *items_written = p - result; err_out: if (items_read) *items_read = i; return result; } /* Code from GLIB gunidecomp.c starts here. */ #include "gunidecomp.h" #include "gunicomp.h" #define CC_PART1(Page, Char) \ ((combining_class_table_part1[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ ? (combining_class_table_part1[Page] - G_UNICODE_MAX_TABLE_INDEX) \ : (cclass_data[combining_class_table_part1[Page]][Char])) #define CC_PART2(Page, Char) \ ((combining_class_table_part2[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ ? (combining_class_table_part2[Page] - G_UNICODE_MAX_TABLE_INDEX) \ : (cclass_data[combining_class_table_part2[Page]][Char])) #define COMBINING_CLASS(Char) \ (((Char) <= G_UNICODE_LAST_CHAR_PART1) \ ? CC_PART1 ((Char) >> 8, (Char) & 0xff) \ : (((Char) >= 0xe0000 && (Char) <= G_UNICODE_LAST_CHAR) \ ? CC_PART2 (((Char) - 0xe0000) >> 8, (Char) & 0xff) \ : 0)) /* constants for hangul syllable [de]composition */ #define SBase 0xAC00 #define LBase 0x1100 #define VBase 0x1161 #define TBase 0x11A7 #define LCount 19 #define VCount 21 #define TCount 28 #define NCount (VCount * TCount) #define SCount (LCount * NCount) /** * g_unicode_canonical_ordering: * @string: a UCS-4 encoded string. * @len: the maximum length of @string to use. * * Computes the canonical ordering of a string in-place. * This rearranges decomposed characters in the string * according to their combining classes. See the Unicode * manual for more information. **/ static void g_unicode_canonical_ordering (gunichar * string, gsize len) { gsize i; int swap = 1; while (swap) { int last; swap = 0; last = COMBINING_CLASS (string[0]); for (i = 0; i < len - 1; ++i) { int next = COMBINING_CLASS (string[i + 1]); if (next != 0 && last > next) { gsize j; /* Percolate item leftward through string. */ for (j = i + 1; j > 0; --j) { gunichar t; if (COMBINING_CLASS (string[j - 1]) <= next) break; t = string[j]; string[j] = string[j - 1]; string[j - 1] = t; swap = 1; } /* We're re-entering the loop looking at the old character again. */ next = last; } last = next; } } } /* http://www.unicode.org/unicode/reports/tr15/#Hangul * r should be null or have sufficient space. Calling with r == NULL will * only calculate the result_len; however, a buffer with space for three * characters will always be big enough. */ static void decompose_hangul (gunichar s, gunichar * r, gsize * result_len) { gint SIndex = s - SBase; /* not a hangul syllable */ if (SIndex < 0 || SIndex >= SCount) { if (r) r[0] = s; *result_len = 1; } else { gunichar L = LBase + SIndex / NCount; gunichar V = VBase + (SIndex % NCount) / TCount; gunichar T = TBase + SIndex % TCount; if (r) { r[0] = L; r[1] = V; } if (T != TBase) { if (r) r[2] = T; *result_len = 3; } else *result_len = 2; } } /* returns a pointer to a null-terminated UTF-8 string */ static const gchar * find_decomposition (gunichar ch, gboolean compat) { int start = 0; int end = G_N_ELEMENTS (decomp_table); if (ch >= decomp_table[start].ch && ch <= decomp_table[end - 1].ch) { while (TRUE) { int half = (start + end) / 2; if (ch == decomp_table[half].ch) { int offset; if (compat) { offset = decomp_table[half].compat_offset; if (offset == G_UNICODE_NOT_PRESENT_OFFSET) offset = decomp_table[half].canon_offset; } else { offset = decomp_table[half].canon_offset; if (offset == G_UNICODE_NOT_PRESENT_OFFSET) return NULL; } return &(decomp_expansion_string[offset]); } else if (half == start) break; else if (ch > decomp_table[half].ch) start = half; else end = half; } } return NULL; } /* L,V => LV and LV,T => LVT */ static gboolean combine_hangul (gunichar a, gunichar b, gunichar * result) { gint LIndex = a - LBase; gint SIndex = a - SBase; gint VIndex = b - VBase; gint TIndex = b - TBase; if (0 <= LIndex && LIndex < LCount && 0 <= VIndex && VIndex < VCount) { *result = SBase + (LIndex * VCount + VIndex) * TCount; return TRUE; } else if (0 <= SIndex && SIndex < SCount && (SIndex % TCount) == 0 && 0 <= TIndex && TIndex <= TCount) { *result = a + TIndex; return TRUE; } return FALSE; } #define CI(Page, Char) \ ((compose_table[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ ? (compose_table[Page] - G_UNICODE_MAX_TABLE_INDEX) \ : (compose_data[compose_table[Page]][Char])) #define COMPOSE_INDEX(Char) \ ((((Char) >> 8) > (COMPOSE_TABLE_LAST)) ? 0 : CI((Char) >> 8, (Char) & 0xff)) static gboolean combine (gunichar a, gunichar b, gunichar * result) { gushort index_a, index_b; if (combine_hangul (a, b, result)) return TRUE; index_a = COMPOSE_INDEX (a); if (index_a >= COMPOSE_FIRST_SINGLE_START && index_a < COMPOSE_SECOND_START) { if (b == compose_first_single[index_a - COMPOSE_FIRST_SINGLE_START][0]) { *result = compose_first_single[index_a - COMPOSE_FIRST_SINGLE_START][1]; return TRUE; } else return FALSE; } index_b = COMPOSE_INDEX (b); if (index_b >= COMPOSE_SECOND_SINGLE_START) { if (a == compose_second_single[index_b - COMPOSE_SECOND_SINGLE_START][0]) { *result = compose_second_single[index_b - COMPOSE_SECOND_SINGLE_START][1]; return TRUE; } else return FALSE; } if (index_a >= COMPOSE_FIRST_START && index_a < COMPOSE_FIRST_SINGLE_START && index_b >= COMPOSE_SECOND_START && index_b < COMPOSE_SECOND_SINGLE_START) { gunichar res = compose_array[index_a - COMPOSE_FIRST_START][index_b - COMPOSE_SECOND_START]; if (res) { *result = res; return TRUE; } } return FALSE; } static gunichar * _g_utf8_normalize_wc (const gchar * str, gssize max_len, GNormalizeMode mode) { gsize n_wc; gunichar *wc_buffer; const char *p; gsize last_start; gboolean do_compat = (mode == G_NORMALIZE_NFKC || mode == G_NORMALIZE_NFKD); gboolean do_compose = (mode == G_NORMALIZE_NFC || mode == G_NORMALIZE_NFKC); n_wc = 0; p = str; while ((max_len < 0 || p < str + max_len) && *p) { const gchar *decomp; gunichar wc = g_utf8_get_char (p); if (wc >= 0xac00 && wc <= 0xd7af) { gsize result_len; decompose_hangul (wc, NULL, &result_len); n_wc += result_len; } else { decomp = find_decomposition (wc, do_compat); if (decomp) n_wc += g_utf8_strlen (decomp, -1); else n_wc++; } p = g_utf8_next_char (p); } wc_buffer = g_new (gunichar, n_wc + 1); last_start = 0; n_wc = 0; p = str; while ((max_len < 0 || p < str + max_len) && *p) { gunichar wc = g_utf8_get_char (p); const gchar *decomp; int cc; gsize old_n_wc = n_wc; if (wc >= 0xac00 && wc <= 0xd7af) { gsize result_len; decompose_hangul (wc, wc_buffer + n_wc, &result_len); n_wc += result_len; } else { decomp = find_decomposition (wc, do_compat); if (decomp) { const char *pd; for (pd = decomp; *pd != '\0'; pd = g_utf8_next_char (pd)) wc_buffer[n_wc++] = g_utf8_get_char (pd); } else wc_buffer[n_wc++] = wc; } if (n_wc > 0) { cc = COMBINING_CLASS (wc_buffer[old_n_wc]); if (cc == 0) { g_unicode_canonical_ordering (wc_buffer + last_start, n_wc - last_start); last_start = old_n_wc; } } p = g_utf8_next_char (p); } if (n_wc > 0) { g_unicode_canonical_ordering (wc_buffer + last_start, n_wc - last_start); last_start = n_wc; } wc_buffer[n_wc] = 0; /* All decomposed and reordered */ if (do_compose && n_wc > 0) { gsize i, j; int last_cc = 0; last_start = 0; for (i = 0; i < n_wc; i++) { int cc = COMBINING_CLASS (wc_buffer[i]); if (i > 0 && (last_cc == 0 || last_cc != cc) && combine (wc_buffer[last_start], wc_buffer[i], &wc_buffer[last_start])) { for (j = i + 1; j < n_wc; j++) wc_buffer[j - 1] = wc_buffer[j]; n_wc--; i--; if (i == last_start) last_cc = 0; else last_cc = COMBINING_CLASS (wc_buffer[i - 1]); continue; } if (cc == 0) last_start = i; last_cc = cc; } } wc_buffer[n_wc] = 0; return wc_buffer; } /** * g_utf8_normalize: * @str: a UTF-8 encoded string. * @len: length of @str, in bytes, or -1 if @str is nul-terminated. * @mode: the type of normalization to perform. * * Converts a string into canonical form, standardizing * such issues as whether a character with an accent * is represented as a base character and combining * accent or as a single precomposed character. You * should generally call g_utf8_normalize() before * comparing two Unicode strings. * * The normalization mode %G_NORMALIZE_DEFAULT only * standardizes differences that do not affect the * text content, such as the above-mentioned accent * representation. %G_NORMALIZE_ALL also standardizes * the "compatibility" characters in Unicode, such * as SUPERSCRIPT THREE to the standard forms * (in this case DIGIT THREE). Formatting information * may be lost but for most text operations such * characters should be considered the same. * For example, g_utf8_collate() normalizes * with %G_NORMALIZE_ALL as its first step. * * %G_NORMALIZE_DEFAULT_COMPOSE and %G_NORMALIZE_ALL_COMPOSE * are like %G_NORMALIZE_DEFAULT and %G_NORMALIZE_ALL, * but returned a result with composed forms rather * than a maximally decomposed form. This is often * useful if you intend to convert the string to * a legacy encoding or pass it to a system with * less capable Unicode handling. * * Return value: a newly allocated string, that is the * normalized form of @str. **/ static gchar * g_utf8_normalize (const gchar * str, gssize len, GNormalizeMode mode) { gunichar *result_wc = _g_utf8_normalize_wc (str, len, mode); gchar *result; result = g_ucs4_to_utf8 (result_wc, -1, NULL, NULL, NULL); g_free (result_wc); return result; } /* Public Libidn API starts here. */ /** * stringprep_utf8_to_unichar: * @p: a pointer to Unicode character encoded as UTF-8 * * Converts a sequence of bytes encoded as UTF-8 to a Unicode character. * If @p does not point to a valid UTF-8 encoded character, results are * undefined. If you are not sure that the bytes are complete * valid Unicode characters, you should use g_utf8_get_char_validated() * instead. * * Return value: the resulting character **/ my_uint32_t stringprep_utf8_to_unichar (const char *p) { return g_utf8_get_char (p); } /** * stringprep_unichar_to_utf8: * @c: a ISO10646 character code * @outbuf: output buffer, must have at least 6 bytes of space. * If %NULL, the length will be computed and returned * and nothing will be written to @outbuf. * * Converts a single character to UTF-8. * * Return value: number of bytes written **/ int stringprep_unichar_to_utf8 (my_uint32_t c, char *outbuf) { return g_unichar_to_utf8 (c, outbuf); } /** * stringprep_utf8_to_ucs4: * @str: a UTF-8 encoded string * @len: the maximum length of @str to use. If @len < 0, then * the string is nul-terminated. * @items_written: location to store the number of characters in the * result, or %NULL. * * Convert a string from UTF-8 to a 32-bit fixed width * representation as UCS-4, assuming valid UTF-8 input. * This function does no error checking on the input. * * Return value: a pointer to a newly allocated UCS-4 string. * This value must be freed with free(). **/ my_uint32_t * stringprep_utf8_to_ucs4 (const char *str, ssize_t len, size_t * items_written) { return g_utf8_to_ucs4_fast (str, (glong) len, (glong *) items_written); } /** * stringprep_ucs4_to_utf8: * @str: a UCS-4 encoded string * @len: the maximum length of @str to use. If @len < 0, then * the string is terminated with a 0 character. * @items_read: location to store number of characters read read, or %NULL. * @items_written: location to store number of bytes written or %NULL. * The value here stored does not include the trailing 0 * byte. * * Convert a string from a 32-bit fixed width representation as UCS-4. * to UTF-8. The result will be terminated with a 0 byte. * * Return value: a pointer to a newly allocated UTF-8 string. * This value must be freed with free(). If an * error occurs, %NULL will be returned and * @error set. **/ char * stringprep_ucs4_to_utf8 (const my_uint32_t * str, ssize_t len, size_t * items_read, size_t * items_written) { return g_ucs4_to_utf8 (str, len, (glong *) items_read, (glong *) items_written, NULL); } /** * stringprep_utf8_nfkc_normalize: * @str: a UTF-8 encoded string. * @len: length of @str, in bytes, or -1 if @str is nul-terminated. * * Converts a string into canonical form, standardizing * such issues as whether a character with an accent * is represented as a base character and combining * accent or as a single precomposed character. * * The normalization mode is NFKC (ALL COMPOSE). It standardizes * differences that do not affect the text content, such as the * above-mentioned accent representation. It standardizes the * "compatibility" characters in Unicode, such as SUPERSCRIPT THREE to * the standard forms (in this case DIGIT THREE). Formatting * information may be lost but for most text operations such * characters should be considered the same. It returns a result with * composed forms rather than a maximally decomposed form. * * Return value: a newly allocated string, that is the * NFKC normalized form of @str. **/ char * stringprep_utf8_nfkc_normalize (const char *str, ssize_t len) { return g_utf8_normalize (str, len, G_NORMALIZE_NFKC); } /** * stringprep_ucs4_nfkc_normalize: * @str: a Unicode string. * @len: length of @str array, or -1 if @str is nul-terminated. * * Converts UCS4 string into UTF-8 and runs * stringprep_utf8_nfkc_normalize(). * * Return value: a newly allocated Unicode string, that is the NFKC * normalized form of @str. **/ my_uint32_t * stringprep_ucs4_nfkc_normalize (my_uint32_t * str, ssize_t len) { char *p; my_uint32_t *result_wc; p = stringprep_ucs4_to_utf8 (str, len, 0, 0); result_wc = _g_utf8_normalize_wc (p, -1, G_NORMALIZE_NFKC); free (p); return result_wc; } psi-0.14/iris/src/libidn/stringprep.c0000644000175000017500000003063711305557616015714 0ustar janjan/* stringprep.c Core stringprep implementation. * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "internal.h" static ssize_t stringprep_find_character_in_table (my_uint32_t ucs4, Stringprep_table_element * table) { ssize_t i; for (i = 0; table[i].start; i++) if (ucs4 >= table[i].start && ucs4 <= (table[i].end ? table[i].end : table[i].start)) return i; return -1; } static ssize_t stringprep_find_string_in_table (my_uint32_t * ucs4, size_t ucs4len, size_t * tablepos, Stringprep_table_element * table) { size_t j; ssize_t pos; for (j = 0; j < ucs4len; j++) if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1) { if (tablepos) *tablepos = pos; return j; } return -1; } static int stringprep_apply_table_to_string (my_uint32_t * ucs4, size_t * ucs4len, size_t maxucs4len, Stringprep_table_element * table, const char *tablename) { ssize_t pos; size_t i, maplen; while ((pos = stringprep_find_string_in_table (ucs4, *ucs4len, &i, table)) != -1) { for (maplen = STRINGPREP_MAX_MAP_CHARS; maplen > 0 && table[i].map[maplen - 1] == 0; maplen--) ; if (*ucs4len - 1 + maplen >= maxucs4len) return STRINGPREP_TOO_SMALL_BUFFER; memmove (&ucs4[pos + maplen], &ucs4[pos + 1], *ucs4len * sizeof (my_uint32_t) - (&ucs4[pos + 1] - ucs4)); memcpy (&ucs4[pos], table[i].map, sizeof (my_uint32_t) * maplen); *ucs4len = *ucs4len - 1 + maplen; } return STRINGPREP_OK; } #define INVERTED(x) ((x) & ((~0UL) >> 1)) #define UNAPPLICAPLEFLAGS(flags, profileflags) \ ((!INVERTED(profileflags) && !(profileflags & flags) && profileflags) || \ ( INVERTED(profileflags) && (profileflags & flags))) /** * stringprep: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * @flags: optional stringprep profile flags. * @profile: pointer to stringprep profile to use. * * Prepare the input UTF-8 string according to the stringprep profile. * Normally application programmers use stringprep profile macros such * as stringprep_nameprep(), stringprep_kerberos5() etc instead of * calling this function directly. * * Since the stringprep operation can expand the string, @maxlen * indicate how large the buffer holding the string is. The @flags * are one of Stringprep_profile_flags, or 0. The profile indicates * processing details specific to that profile. Your application can * define new profiles, possibly re-using the generic stringprep * tables that always will be part of the library. * * Note that you must convert strings entered in the systems locale * into UTF-8 before using this function. * * Return value: Returns 0 iff successful, or an error code. **/ int stringprep (char *in, size_t maxlen, Stringprep_profile_flags flags, Stringprep_profile * profile) { size_t i, j; ssize_t k; int rc; char *p = 0; my_uint32_t *q = 0; my_uint32_t *ucs4; size_t ucs4len, maxucs4len; ucs4 = stringprep_utf8_to_ucs4 (in, -1, &ucs4len); maxucs4len = 4 * ucs4len + 10; /* XXX */ ucs4 = realloc (ucs4, 1 + maxucs4len * sizeof (my_uint32_t)); if (!ucs4) { rc = STRINGPREP_MALLOC_ERROR; goto done; } for (i = 0; profile[i].operation; i++) { switch (profile[i].operation) { case STRINGPREP_NFKC: if (UNAPPLICAPLEFLAGS (flags, profile[i].flags)) { break; } if (flags & STRINGPREP_NO_NFKC && !profile[i].flags) { /* Profile requires NFKC, but callee asked for no NFKC. */ rc = STRINGPREP_FLAG_ERROR; goto done; } q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len); if (!q) { rc = STRINGPREP_NFKC_FAILED; goto done; } for (j = 0; q[j]; j++) ; free (ucs4); ucs4 = q; ucs4len = j; q = 0; break; case STRINGPREP_PROHIBIT_TABLE: k = stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[i].table); if (k != -1) { rc = STRINGPREP_CONTAINS_PROHIBITED; goto done; } break; case STRINGPREP_UNASSIGNED_TABLE: if (UNAPPLICAPLEFLAGS (flags, profile[i].flags)) break; if (flags & STRINGPREP_NO_UNASSIGNED) { k = stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[i].table); if (k != -1) { rc = STRINGPREP_CONTAINS_UNASSIGNED; goto done; } } break; case STRINGPREP_MAP_TABLE: if (UNAPPLICAPLEFLAGS (flags, profile[i].flags)) break; rc = stringprep_apply_table_to_string (ucs4, &ucs4len, maxucs4len, profile[i].table, profile[i].name); if (rc != STRINGPREP_OK) goto done; break; case STRINGPREP_BIDI_PROHIBIT_TABLE: case STRINGPREP_BIDI_RAL_TABLE: case STRINGPREP_BIDI_L_TABLE: break; case STRINGPREP_BIDI: { int done_prohibited = 0; int done_ral = 0; int done_l = 0; int contains_ral = -1; int contains_l = -1; for (j = 0; profile[j].operation; j++) if (profile[j].operation == STRINGPREP_BIDI_PROHIBIT_TABLE) { done_prohibited = 1; k = stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[j].table); if (k != -1) { rc = STRINGPREP_BIDI_CONTAINS_PROHIBITED; goto done; } } else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE) { done_ral = 1; if (stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[j].table) != -1) contains_ral = j; } else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE) { done_l = 1; if (stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[j].table) != -1) contains_l = j; } if (!done_prohibited || !done_ral || !done_l) { rc = STRINGPREP_PROFILE_ERROR; goto done; } if (contains_ral != -1 && contains_l != -1) { rc = STRINGPREP_BIDI_BOTH_L_AND_RAL; goto done; } if (contains_ral != -1) { if (!(stringprep_find_character_in_table (ucs4[0], profile[contains_ral].table) != -1 && stringprep_find_character_in_table (ucs4[ucs4len - 1], profile[contains_ral].table) != -1)) { rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL; goto done; } } } break; default: rc = STRINGPREP_PROFILE_ERROR; goto done; break; } } p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0); if (strlen (p) >= maxlen) { rc = STRINGPREP_TOO_SMALL_BUFFER; goto done; } strcpy (in, p); /* flawfinder: ignore */ rc = STRINGPREP_OK; done: if (p) free (p); if (q) free (q); if (ucs4) free (ucs4); return rc; } /** * stringprep_profile: * @in: input/ouput array with string to prepare. * @out: output variable with newly allocate string. * @flags: optional stringprep profile flags. * @profile: name of stringprep profile to use. * * Prepare the input UTF-8 string according to the stringprep profile. * Normally application programmers use stringprep profile macros such * as stringprep_nameprep(), stringprep_kerberos5() etc instead of * calling this function directly. * * Note that you must convert strings entered in the systems locale * into UTF-8 before using this function. * * The output @out variable must be deallocated by the caller. * * Return value: Returns 0 iff successful, or an error code. **/ int stringprep_profile (char *in, char **out, char *profile, Stringprep_profile_flags flags) { Stringprep_profiles *p; char *str; size_t len; int rc; for (p = &stringprep_profiles[0]; p->name; p++) if (strcmp (p->name, profile) == 0) break; if (!p || !p->name || !p->tables) return STRINGPREP_UNKNOWN_PROFILE; len = strlen (in) + BUFSIZ; str = (char *) malloc (len); if (str == NULL) return STRINGPREP_MALLOC_ERROR; strcpy (str, in); rc = stringprep (str, len, flags, p->tables); if (rc == STRINGPREP_OK) *out = str; else free (str); return rc; } /** * STRINGPREP_VERSION * * String defined via CPP denoting the header file version number. * Used together with stringprep_check_version() to verify header file * and run-time library consistency. */ /** * STRINGPREP_MAX_MAP_CHARS * * Maximum number of code points that can replace a single code point, * during stringprep mapping. */ /** * Stringprep_rc * * Enumerated return codes of stringprep(), stringprep_profile() * functions (and macros using those functions). The value 0 is * guaranteed to always correspond to success. */ /** * Stringprep_profile_flags: * @STRINGPREP_NO_NFKC: Disable the NFKC normalization, as well as * selecting the non-NFKC case folding tables. Usually the profile * specifies BIDI and NFKC settings, and applications should not * override it unless in special situations. * @STRINGPREP_NO_BIDI: Disable the BIDI step. Usually the profile * specifies BIDI and NFKC settings, and applications should not * override it unless in special situations. * @STRINGPREP_NO_UNASSIGNED: Make the library return with an error if * string contains unassigned characters according to profile. * * Stringprep profile flags. */ /** * Stringprep_profile_steps: * * Various steps in the stringprep algorithm. You really want to * study the source code to understand this one. Only useful if you * want to add another profile. */ /** * stringprep_nameprep: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the nameprep profile. * The AllowUnassigned flag is true, use * stringprep_nameprep_no_unassigned() for false AllowUnassigned. * Returns 0 iff successful, or an error code. **/ /** * stringprep_nameprep_no_unassigned: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the nameprep profile. * The AllowUnassigned flag is false, use stringprep_nameprep() for * true AllowUnassigned. Returns 0 iff successful, or an error code. **/ /** * stringprep_iscsi: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the draft iSCSI * stringprep profile. Returns 0 iff successful, or an error code. **/ /** * stringprep_kerberos5: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the draft Kerberos5 * stringprep profile. Returns 0 iff successful, or an error code. **/ /** * stringprep_plain: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the draft SASL * ANONYMOUS profile. Returns 0 iff successful, or an error code. **/ /** * stringprep_xmpp_nodeprep: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the draft XMPP node * identifier profile. Returns 0 iff successful, or an error code. **/ /** * stringprep_xmpp_resourceprep: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to the draft XMPP resource * identifier profile. Returns 0 iff successful, or an error code. **/ /** * stringprep_generic: * @in: input/ouput array with string to prepare. * @maxlen: maximum length of input/output array. * * Prepare the input UTF-8 string according to a hypotetical "generic" * stringprep profile. This is mostly used for debugging or when * constructing new stringprep profiles. Returns 0 iff successful, or * an error code. **/ psi-0.14/iris/src/libidn/stringprep.h0000644000175000017500000001522211305557616015712 0ustar janjan/* stringprep.h Header file for stringprep functions. -*- c -*- * Copyright (C) 2002, 2003 Simon Josefsson * * This file is part of GNU Libidn. * * GNU Libidn is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GNU Libidn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GNU Libidn; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _STRINGPREP_H #define _STRINGPREP_H #ifdef __cplusplus extern "C" { #endif #include /* size_t */ #include #if defined(Q_OS_WIN32) && !defined(Q_CC_GNU) typedef int ssize_t; #else #include /* ssize_t */ #endif #include /* my_uint32_t */ #include "qint.h" #define STRINGPREP_VERSION "0.3.1" /* Error codes. */ typedef enum { STRINGPREP_OK = 0, /* Stringprep errors. */ STRINGPREP_CONTAINS_UNASSIGNED = 1, STRINGPREP_CONTAINS_PROHIBITED = 2, STRINGPREP_BIDI_BOTH_L_AND_RAL = 3, STRINGPREP_BIDI_LEADTRAIL_NOT_RAL = 4, STRINGPREP_BIDI_CONTAINS_PROHIBITED = 5, /* Error in calling application. */ STRINGPREP_TOO_SMALL_BUFFER = 100, STRINGPREP_PROFILE_ERROR = 101, STRINGPREP_FLAG_ERROR = 102, STRINGPREP_UNKNOWN_PROFILE = 103, /* Internal errors. */ STRINGPREP_NFKC_FAILED = 200, STRINGPREP_MALLOC_ERROR = 201 } Stringprep_rc; /* Flags used when calling stringprep(). */ typedef enum { STRINGPREP_NO_NFKC = 1, STRINGPREP_NO_BIDI = 2, STRINGPREP_NO_UNASSIGNED = 4 } Stringprep_profile_flags; /* Steps in a stringprep profile. */ typedef enum { STRINGPREP_NFKC = 1, STRINGPREP_BIDI = 2, STRINGPREP_MAP_TABLE = 3, STRINGPREP_UNASSIGNED_TABLE = 4, STRINGPREP_PROHIBIT_TABLE = 5, STRINGPREP_BIDI_PROHIBIT_TABLE = 6, STRINGPREP_BIDI_RAL_TABLE = 7, STRINGPREP_BIDI_L_TABLE = 8 } Stringprep_profile_steps; #define STRINGPREP_MAX_MAP_CHARS 4 struct Stringprep_table_element { my_uint32_t start; my_uint32_t end; /* 0 if only one character */ my_uint32_t map[STRINGPREP_MAX_MAP_CHARS]; /* NULL if end is not 0 */ }; typedef struct Stringprep_table_element Stringprep_table_element; struct Stringprep_table { Stringprep_profile_steps operation; Stringprep_profile_flags flags; Stringprep_table_element *table; char *name; }; typedef struct Stringprep_table Stringprep_profile; struct Stringprep_profiles { char *name; Stringprep_profile *tables; }; typedef struct Stringprep_profiles Stringprep_profiles; extern Stringprep_profiles stringprep_profiles[]; /* Profiles */ extern Stringprep_table_element stringprep_rfc3454_A_1[]; extern Stringprep_table_element stringprep_rfc3454_B_1[]; extern Stringprep_table_element stringprep_rfc3454_B_2[]; extern Stringprep_table_element stringprep_rfc3454_B_3[]; extern Stringprep_table_element stringprep_rfc3454_C_1_1[]; extern Stringprep_table_element stringprep_rfc3454_C_1_2[]; extern Stringprep_table_element stringprep_rfc3454_C_2_1[]; extern Stringprep_table_element stringprep_rfc3454_C_2_2[]; extern Stringprep_table_element stringprep_rfc3454_C_3[]; extern Stringprep_table_element stringprep_rfc3454_C_4[]; extern Stringprep_table_element stringprep_rfc3454_C_5[]; extern Stringprep_table_element stringprep_rfc3454_C_6[]; extern Stringprep_table_element stringprep_rfc3454_C_7[]; extern Stringprep_table_element stringprep_rfc3454_C_8[]; extern Stringprep_table_element stringprep_rfc3454_C_9[]; extern Stringprep_table_element stringprep_rfc3454_D_1[]; extern Stringprep_table_element stringprep_rfc3454_D_2[]; /* Generic (for debugging) */ extern Stringprep_profile stringprep_generic[]; #define stringprep_generic(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_generic) /* Nameprep */ extern Stringprep_profile stringprep_nameprep[]; #define stringprep_nameprep(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_nameprep) #define stringprep_nameprep_no_unassigned(in, maxlen) \ stringprep(in, maxlen, STRINGPREP_NO_UNASSIGNED, stringprep_nameprep) /* SASL */ extern Stringprep_profile stringprep_saslprep[]; extern Stringprep_profile stringprep_plain[]; #define stringprep_plain(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_plain) /* Kerberos */ extern Stringprep_profile stringprep_kerberos5[]; #define stringprep_kerberos5(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_kerberos5) /* XMPP */ extern Stringprep_profile stringprep_xmpp_nodeprep[]; extern Stringprep_profile stringprep_xmpp_resourceprep[]; extern Stringprep_table_element stringprep_xmpp_nodeprep_prohibit[]; #define stringprep_xmpp_nodeprep(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_xmpp_nodeprep) #define stringprep_xmpp_resourceprep(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_xmpp_resourceprep) /* iSCSI */ extern Stringprep_profile stringprep_iscsi[]; #define stringprep_iscsi(in, maxlen) \ stringprep(in, maxlen, 0, stringprep_iscsi) /* API */ extern int stringprep (char *in, size_t maxlen, Stringprep_profile_flags flags, Stringprep_profile * profile); extern int stringprep_profile (char *in, char **out, char *profile, Stringprep_profile_flags flags); extern const char *stringprep_check_version (const char *req_version); /* Utility */ extern int stringprep_unichar_to_utf8 (my_uint32_t c, char *outbuf); extern my_uint32_t stringprep_utf8_to_unichar (const char *p); extern my_uint32_t *stringprep_utf8_to_ucs4 (const char *str, ssize_t len, size_t * items_written); extern char *stringprep_ucs4_to_utf8 (const my_uint32_t * str, ssize_t len, size_t * items_read, size_t * items_written); extern char *stringprep_utf8_nfkc_normalize (const char *str, ssize_t len); extern my_uint32_t *stringprep_ucs4_nfkc_normalize (my_uint32_t * str, ssize_t len); /*extern const char *stringprep_locale_charset (void); extern char *stringprep_convert (const char *str, const char *to_codeset, const char *from_codeset); extern char *stringprep_locale_to_utf8 (const char *str); extern char *stringprep_utf8_to_locale (const char *str);*/ #ifdef __cplusplus } #endif #endif /* _STRINGPREP_H */ psi-0.14/iris/src/src.pro0000644000175000017500000000026611305557616013416 0ustar janjanTEMPLATE = subdirs include(libbase.pri) sub_irisnet.subdir = irisnet sub_xmpp.subdir = xmpp sub_xmpp.depends = sub_irisnet SUBDIRS += sub_irisnet !iris_bundle:SUBDIRS += sub_xmpp psi-0.14/iris/src/xmpp/0000755000175000017500000000000011305557616013065 5ustar janjanpsi-0.14/iris/src/xmpp/base64/0000755000175000017500000000000011305557616014151 5ustar janjanpsi-0.14/iris/src/xmpp/base64/base64.h0000644000175000017500000000035511305557616015411 0ustar janjan#ifndef XMPP_BASE64_H #define XMPP_BASE64_H #include #include namespace XMPP { class Base64 { public: static QString encode(const QByteArray&); static QByteArray decode(const QString &s); }; } #endif psi-0.14/iris/src/xmpp/base64/unittest/0000755000175000017500000000000011305557616016030 5ustar janjanpsi-0.14/iris/src/xmpp/base64/unittest/unittest.pri0000644000175000017500000000004311305557616020420 0ustar janjanSOURCES += \ $$PWD/base64test.cpp psi-0.14/iris/src/xmpp/base64/unittest/unittest.pro0000644000175000017500000000017411305557616020433 0ustar janjaninclude(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$IRIS_XMPP_BASE64_MODULE) include(unittest.pri) psi-0.14/iris/src/xmpp/base64/unittest/base64test.cpp0000644000175000017500000000151411305557616020521 0ustar janjan/* * Copyright (C) 2008 * See COPYING for license details. */ #include #include #include "qttestutil/qttestutil.h" #include "xmpp/base64/base64.h" using namespace XMPP; class Base64Test : public QObject { Q_OBJECT private slots: void testEncode() { QString result = Base64::encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"); QCOMPARE(result, QString("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA=")); } void testDecode() { QString result = Base64::decode("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA="); QCOMPARE(result, QString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")); } }; QTTESTUTIL_REGISTER_TEST(Base64Test); #include "base64test.moc" psi-0.14/iris/src/xmpp/base64/base64.cpp0000644000175000017500000000457311305557616015752 0ustar janjan#include "xmpp/base64/base64.h" namespace XMPP { QString Base64::encode(const QByteArray &s) { int i; int len = s.size(); char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; int a, b, c; QByteArray p; p.resize((len+2)/3*4); int at = 0; for( i = 0; i < len; i += 3 ) { a = ((unsigned char)s[i] & 3) << 4; if(i + 1 < len) { a += (unsigned char)s[i + 1] >> 4; b = ((unsigned char)s[i + 1] & 0xF) << 2; if(i + 2 < len) { b += (unsigned char)s[i + 2] >> 6; c = (unsigned char)s[i + 2] & 0x3F; } else c = 64; } else { b = c = 64; } p[at++] = tbl[(unsigned char)s[i] >> 2]; p[at++] = tbl[a]; p[at++] = tbl[b]; p[at++] = tbl[c]; } return QString::fromAscii(p); } QByteArray Base64::decode(const QString& input) { QByteArray s(QString(input).remove('\n').toUtf8()); QByteArray p; // -1 specifies invalid // 64 specifies eof // everything else specifies data char tbl[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; // this should be a multiple of 4 int len = s.size(); if(len % 4) { return p; } p.resize(len / 4 * 3); int i; int at = 0; int a, b, c, d; c = d = 0; for( i = 0; i < len; i += 4 ) { a = tbl[(int)s[i]]; b = tbl[(int)s[i + 1]]; c = tbl[(int)s[i + 2]]; d = tbl[(int)s[i + 3]]; if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { p.resize(0); return p; } p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); } if(c & 64) p.resize(at - 2); else if(d & 64) p.resize(at - 1); return p; } } psi-0.14/iris/src/xmpp/base64/base64.pri0000644000175000017500000000016311305557616015751 0ustar janjanINCLUDEPATH += $$PWD/../.. DEPENDPATH += $$PWD/../.. HEADERS += \ $$PWD/base64.h SOURCES += \ $$PWD/base64.cpp psi-0.14/iris/src/xmpp/cutestuff/0000755000175000017500000000000011305557616015075 5ustar janjanpsi-0.14/iris/src/xmpp/cutestuff/cutestuff.pri0000644000175000017500000000040111305557616017614 0ustar janjanINCLUDEPATH += $$PWD HEADERS += \ $$PWD/bytestream.h \ $$PWD/bsocket.h \ $$PWD/httpconnect.h \ $$PWD/httppoll.h \ $$PWD/socks.h SOURCES += \ $$PWD/bytestream.cpp \ $$PWD/bsocket.cpp \ $$PWD/httpconnect.cpp \ $$PWD/httppoll.cpp \ $$PWD/socks.cpp psi-0.14/iris/src/xmpp/cutestuff/httpconnect.cpp0000644000175000017500000001746411305557616020146 0ustar janjan/* * httpconnect.cpp - HTTP "CONNECT" proxy * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "httpconnect.h" #include #include #include "bsocket.h" #include //#define PROX_DEBUG #ifdef PROX_DEBUG #include #endif // CS_NAMESPACE_BEGIN #ifdef PROX_DEBUG QString escapeOutput(const QByteArray &in) { QString out; for(int n = 0; n < in.size(); ++n) { if(in[n] == '\\') { out += QString("\\\\"); } else if(in[n] >= 32 && in[n] < 127) { out += QChar::fromLatin1(in[n]); } else { out += QString().sprintf("\\x%02x", (unsigned char)in[n]); } } return out; } #endif static QString extractLine(QByteArray *buf, bool *found) { // Scan for newline int index = buf->indexOf ("\r\n"); if (index == -1) { // Newline not found if (found) *found = false; return ""; } else { // Found newline QString s = QString::fromAscii(buf->left(index)); buf->remove(0, index + 2); if (found) *found = true; return s; } } static bool extractMainHeader(const QString &line, QString *proto, int *code, QString *msg) { int n = line.indexOf(' '); if(n == -1) return false; if(proto) *proto = line.mid(0, n); ++n; int n2 = line.indexOf(' ', n); if(n2 == -1) return false; if(code) *code = line.mid(n, n2-n).toInt(); n = n2+1; if(msg) *msg = line.mid(n); return true; } class HttpConnect::Private { public: Private() {} BSocket sock; QString host; int port; QString user, pass; QString real_host; int real_port; QByteArray recvBuf; bool inHeader; QStringList headerLines; int toWrite; bool active; }; HttpConnect::HttpConnect(QObject *parent) :ByteStream(parent) { d = new Private; connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected())); connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); connect(&d->sock, SIGNAL(delayedCloseFinished()), SLOT(sock_delayedCloseFinished())); connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(&d->sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int))); connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int))); reset(true); } HttpConnect::~HttpConnect() { reset(true); delete d; } void HttpConnect::reset(bool clear) { if(d->sock.state() != BSocket::Idle) d->sock.close(); if(clear) { clearReadBuffer(); d->recvBuf.resize(0); } d->active = false; } void HttpConnect::setAuth(const QString &user, const QString &pass) { d->user = user; d->pass = pass; } void HttpConnect::connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port) { reset(true); d->host = proxyHost; d->port = proxyPort; d->real_host = host; d->real_port = port; #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: Connecting to %s:%d", qPrintable(proxyHost), proxyPort); if(d->user.isEmpty()) fprintf(stderr, "\n"); else fprintf(stderr, ", auth {%s,%s}\n", qPrintable(d->user), qPrintable(d->pass)); #endif d->sock.connectToHost(d->host, d->port); } bool HttpConnect::isOpen() const { return d->active; } void HttpConnect::close() { d->sock.close(); if(d->sock.bytesToWrite() == 0) reset(); } void HttpConnect::write(const QByteArray &buf) { if(d->active) d->sock.write(buf); } QByteArray HttpConnect::read(int bytes) { return ByteStream::read(bytes); } int HttpConnect::bytesAvailable() const { return ByteStream::bytesAvailable(); } int HttpConnect::bytesToWrite() const { if(d->active) return d->sock.bytesToWrite(); else return 0; } void HttpConnect::sock_connected() { #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: Connected\n"); #endif d->inHeader = true; d->headerLines.clear(); // connected, now send the request QString s; s += QString("CONNECT ") + d->real_host + ':' + QString::number(d->real_port) + " HTTP/1.0\r\n"; if(!d->user.isEmpty()) { QString str = d->user + ':' + d->pass; s += QString("Proxy-Authorization: Basic ") + QCA::Base64().encodeString(str) + "\r\n"; } s += "Pragma: no-cache\r\n"; s += "\r\n"; QByteArray block = s.toUtf8(); #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: writing: {%s}\n", qPrintable(escapeOutput(block))); #endif d->toWrite = block.size(); d->sock.write(block); } void HttpConnect::sock_connectionClosed() { if(d->active) { reset(); connectionClosed(); } else { error(ErrProxyNeg); } } void HttpConnect::sock_delayedCloseFinished() { if(d->active) { reset(); delayedCloseFinished(); } } void HttpConnect::sock_readyRead() { QByteArray block = d->sock.read(); if(!d->active) { ByteStream::appendArray(&d->recvBuf, block); if(d->inHeader) { // grab available lines while(1) { bool found; QString line = extractLine(&d->recvBuf, &found); if(!found) break; if(line.isEmpty()) { d->inHeader = false; break; } d->headerLines += line; } // done with grabbing the header? if(!d->inHeader) { QString str = d->headerLines.first(); d->headerLines.takeFirst(); QString proto; int code; QString msg; if(!extractMainHeader(str, &proto, &code, &msg)) { #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: invalid header!\n"); #endif reset(true); error(ErrProxyNeg); return; } else { #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: header proto=[%s] code=[%d] msg=[%s]\n", qPrintable(proto), code, qPrintable(msg)); for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) fprintf(stderr, "HttpConnect: * [%s]\n", qPrintable(*it)); #endif } if(code == 200) { // OK #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: << Success >>\n"); #endif d->active = true; connected(); if(!d->recvBuf.isEmpty()) { appendRead(d->recvBuf); d->recvBuf.resize(0); readyRead(); return; } } else { int err; QString errStr; if(code == 407) { // Authentication failed err = ErrProxyAuth; errStr = tr("Authentication failed"); } else if(code == 404) { // Host not found err = ErrHostNotFound; errStr = tr("Host not found"); } else if(code == 403) { // Access denied err = ErrProxyNeg; errStr = tr("Access denied"); } else if(code == 503) { // Connection refused err = ErrConnectionRefused; errStr = tr("Connection refused"); } else { // invalid reply err = ErrProxyNeg; errStr = tr("Invalid reply"); } #ifdef PROX_DEBUG fprintf(stderr, "HttpConnect: << Error >> [%s]\n", qPrintable(errStr)); #endif reset(true); error(err); return; } } } } else { appendRead(block); readyRead(); return; } } void HttpConnect::sock_bytesWritten(int x) { if(d->toWrite > 0) { int size = x; if(d->toWrite < x) size = d->toWrite; d->toWrite -= size; x -= size; } if(d->active && x > 0) bytesWritten(x); } void HttpConnect::sock_error(int x) { if(d->active) { reset(); error(ErrRead); } else { reset(true); if(x == BSocket::ErrHostNotFound) error(ErrProxyConnect); else if(x == BSocket::ErrConnectionRefused) error(ErrProxyConnect); else if(x == BSocket::ErrRead) error(ErrProxyNeg); } } // CS_NAMESPACE_END psi-0.14/iris/src/xmpp/cutestuff/socks.cpp0000644000175000017500000005405211305557616016731 0ustar janjan/* * socks.cpp - SOCKS5 TCP proxy client/server * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "socks.h" #include #include #include #include #include #include #ifdef Q_OS_UNIX #include #include #endif #ifdef Q_OS_WIN32 #include #endif #ifdef Q_OS_UNIX #include #include #endif #include "servsock.h" #include "bsocket.h" //#define PROX_DEBUG #ifdef PROX_DEBUG #include #endif // CS_NAMESPACE_BEGIN //---------------------------------------------------------------------------- // SocksUDP //---------------------------------------------------------------------------- class SocksUDP::Private { public: QUdpSocket *sd; SocksClient *sc; QHostAddress routeAddr; int routePort; QString host; int port; }; SocksUDP::SocksUDP(SocksClient *sc, const QString &host, int port, const QHostAddress &routeAddr, int routePort) :QObject(sc) { d = new Private; d->sc = sc; d->sd = new QUdpSocket(); connect(d->sd, SIGNAL(readyRead()), SLOT(sd_readyRead())); d->host = host; d->port = port; d->routeAddr = routeAddr; d->routePort = routePort; } SocksUDP::~SocksUDP() { delete d->sd; delete d; } void SocksUDP::change(const QString &host, int port) { d->host = host; d->port = port; } void SocksUDP::write(const QByteArray &data) { d->sd->writeDatagram(data.data(), data.size(), d->routeAddr, d->routePort); } void SocksUDP::sd_activated() { while (d->sd->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(d->sd->pendingDatagramSize()); d->sd->readDatagram(datagram.data(), datagram.size()); packetReady(datagram); } } //---------------------------------------------------------------------------- // SocksClient //---------------------------------------------------------------------------- #define REQ_CONNECT 0x01 #define REQ_BIND 0x02 #define REQ_UDPASSOCIATE 0x03 #define RET_SUCCESS 0x00 #define RET_UNREACHABLE 0x04 #define RET_CONNREFUSED 0x05 // spc = socks packet client // sps = socks packet server // SPCS = socks packet client struct // SPSS = socks packet server struct // Version static QByteArray spc_set_version() { QByteArray ver; ver.resize(4); ver[0] = 0x05; // socks version 5 ver[1] = 0x02; // number of methods ver[2] = 0x00; // no-auth ver[3] = 0x02; // username return ver; } static QByteArray sps_set_version(int method) { QByteArray ver; ver.resize(2); ver[0] = 0x05; ver[1] = method; return ver; } struct SPCS_VERSION { unsigned char version; QByteArray methodList; }; static int spc_get_version(QByteArray *from, SPCS_VERSION *s) { if(from->size() < 1) return 0; if(from->at(0) != 0x05) // only SOCKS5 supported return -1; if(from->size() < 2) return 0; unsigned char mlen = from->at(1); int num = mlen; if(num > 16) // who the heck has over 16 auth methods?? return -1; if(from->size() < 2 + num) return 0; QByteArray a = ByteStream::takeArray(from, 2+num); s->version = a[0]; s->methodList.resize(num); memcpy(s->methodList.data(), a.data() + 2, num); return 1; } struct SPSS_VERSION { unsigned char version; unsigned char method; }; static int sps_get_version(QByteArray *from, SPSS_VERSION *s) { if(from->size() < 2) return 0; QByteArray a = ByteStream::takeArray(from, 2); s->version = a[0]; s->method = a[1]; return 1; } // authUsername static QByteArray spc_set_authUsername(const QByteArray &user, const QByteArray &pass) { int len1 = user.length(); int len2 = pass.length(); if(len1 > 255) len1 = 255; if(len2 > 255) len2 = 255; QByteArray a; a.resize(1+1+len1+1+len2); a[0] = 0x01; // username auth version 1 a[1] = len1; memcpy(a.data() + 2, user.data(), len1); a[2+len1] = len2; memcpy(a.data() + 3 + len1, pass.data(), len2); return a; } static QByteArray sps_set_authUsername(bool success) { QByteArray a; a.resize(2); a[0] = 0x01; a[1] = success ? 0x00 : 0xff; return a; } struct SPCS_AUTHUSERNAME { QString user, pass; }; static int spc_get_authUsername(QByteArray *from, SPCS_AUTHUSERNAME *s) { if(from->size() < 1) return 0; unsigned char ver = from->at(0); if(ver != 0x01) return -1; if(from->size() < 2) return 0; unsigned char ulen = from->at(1); if((int)from->size() < ulen + 3) return 0; unsigned char plen = from->at(ulen+2); if((int)from->size() < ulen + plen + 3) return 0; QByteArray a = ByteStream::takeArray(from, ulen + plen + 3); QByteArray user, pass; user.resize(ulen); pass.resize(plen); memcpy(user.data(), a.data()+2, ulen); memcpy(pass.data(), a.data()+ulen+3, plen); s->user = QString::fromUtf8(user); s->pass = QString::fromUtf8(pass); return 1; } struct SPSS_AUTHUSERNAME { unsigned char version; bool success; }; static int sps_get_authUsername(QByteArray *from, SPSS_AUTHUSERNAME *s) { if(from->size() < 2) return 0; QByteArray a = ByteStream::takeArray(from, 2); s->version = a[0]; s->success = ((char) a[1] == 0 ? true: false); return 1; } // connectRequest static QByteArray sp_set_request(const QHostAddress &addr, unsigned short port, unsigned char cmd1) { int at = 0; QByteArray a; a.resize(4); a[at++] = 0x05; // socks version 5 a[at++] = cmd1; a[at++] = 0x00; // reserved if(addr.protocol() == QAbstractSocket::IPv4Protocol || addr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { a[at++] = 0x01; // address type = ipv4 quint32 ip4 = htonl(addr.toIPv4Address()); a.resize(at+4); memcpy(a.data() + at, &ip4, 4); at += 4; } else { a[at++] = 0x04; quint8 a6[16]; QStringList s6 = addr.toString().split(':'); int at = 0; quint16 c; bool ok; for(QStringList::ConstIterator it = s6.begin(); it != s6.end(); ++it) { c = (*it).toInt(&ok, 16); a6[at++] = (c >> 8); a6[at++] = c & 0xff; } a.resize(at+16); memcpy(a.data() + at, a6, 16); at += 16; } // port a.resize(at+2); unsigned short p = htons(port); memcpy(a.data() + at, &p, 2); return a; } static QByteArray sp_set_request(const QString &host, quint16 port, unsigned char cmd1) { // detect for IP addresses QHostAddress addr; if(addr.setAddress(host)) return sp_set_request(addr, port, cmd1); QByteArray h = host.toUtf8(); h.truncate(255); h = QString::fromUtf8(h).toUtf8(); // delete any partial characters? int hlen = h.length(); int at = 0; QByteArray a; a.resize(4); a[at++] = 0x05; // socks version 5 a[at++] = cmd1; a[at++] = 0x00; // reserved a[at++] = 0x03; // address type = domain // host a.resize(at+hlen+1); a[at++] = hlen; memcpy(a.data() + at, h.data(), hlen); at += hlen; // port a.resize(at+2); unsigned short p = htons(port); memcpy(a.data() + at, &p, 2); return a; } struct SPS_CONNREQ { unsigned char version; unsigned char cmd; int address_type; QString host; QHostAddress addr; quint16 port; }; static int sp_get_request(QByteArray *from, SPS_CONNREQ *s) { int full_len = 4; if((int)from->size() < full_len) return 0; QString host; QHostAddress addr; unsigned char atype = from->at(3); if(atype == 0x01) { full_len += 4; if((int)from->size() < full_len) return 0; quint32 ip4; memcpy(&ip4, from->data() + 4, 4); addr.setAddress(ntohl(ip4)); } else if(atype == 0x03) { ++full_len; if((int)from->size() < full_len) return 0; unsigned char host_len = from->at(4); full_len += host_len; if((int)from->size() < full_len) return 0; QByteArray cs; cs.resize(host_len); memcpy(cs.data(), from->data() + 5, host_len); host = QString::fromLatin1(cs); } else if(atype == 0x04) { full_len += 16; if((int)from->size() < full_len) return 0; quint8 a6[16]; memcpy(a6, from->data() + 4, 16); addr.setAddress(a6); } full_len += 2; if((int)from->size() < full_len) return 0; QByteArray a = ByteStream::takeArray(from, full_len); quint16 p; memcpy(&p, a.data() + full_len - 2, 2); s->version = a[0]; s->cmd = a[1]; s->address_type = atype; s->host = host; s->addr = addr; s->port = ntohs(p); return 1; } enum { StepVersion, StepAuth, StepRequest }; class SocksClient::Private { public: Private() {} BSocket sock; QString host; int port; QString user, pass; QString real_host; int real_port; QByteArray recvBuf; bool active; int step; int authMethod; bool incoming, waiting; QString rhost; int rport; int pending; bool udp; QString udpAddr; int udpPort; }; SocksClient::SocksClient(QObject *parent) :ByteStream(parent) { init(); d->incoming = false; } SocksClient::SocksClient(int s, QObject *parent) :ByteStream(parent) { init(); d->incoming = true; d->waiting = true; d->sock.setSocket(s); } void SocksClient::init() { d = new Private; connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected())); connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); connect(&d->sock, SIGNAL(delayedCloseFinished()), SLOT(sock_delayedCloseFinished())); connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(&d->sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int))); connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int))); reset(true); } SocksClient::~SocksClient() { reset(true); delete d; } void SocksClient::reset(bool clear) { if(d->sock.state() != BSocket::Idle) d->sock.close(); if(clear) clearReadBuffer(); d->recvBuf.resize(0); d->active = false; d->waiting = false; d->udp = false; d->pending = 0; } bool SocksClient::isIncoming() const { return d->incoming; } void SocksClient::setAuth(const QString &user, const QString &pass) { d->user = user; d->pass = pass; } void SocksClient::connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port, bool udpMode) { reset(true); d->host = proxyHost; d->port = proxyPort; d->real_host = host; d->real_port = port; d->udp = udpMode; #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: Connecting to %s:%d", qPrintable(proxyHost), proxyPort); if(d->user.isEmpty()) fprintf(stderr, "\n"); else fprintf(stderr, ", auth {%s,%s}\n", qPrintable(d->user), qPrintable(d->pass)); #endif d->sock.connectToHost(d->host, d->port); } bool SocksClient::isOpen() const { return d->active; } void SocksClient::close() { d->sock.close(); if(d->sock.bytesToWrite() == 0) reset(); } void SocksClient::writeData(const QByteArray &buf) { #ifdef PROX_DEBUG // show hex fprintf(stderr, "SocksClient: client write { "); for(int n = 0; n < (int)buf.size(); ++n) fprintf(stderr, "%02X ", (unsigned char)buf[n]); fprintf(stderr, " } \n"); #endif d->pending += buf.size(); d->sock.write(buf); } void SocksClient::write(const QByteArray &buf) { if(d->active && !d->udp) d->sock.write(buf); } QByteArray SocksClient::read(int bytes) { return ByteStream::read(bytes); } int SocksClient::bytesAvailable() const { return ByteStream::bytesAvailable(); } int SocksClient::bytesToWrite() const { if(d->active) return d->sock.bytesToWrite(); else return 0; } void SocksClient::sock_connected() { #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: Connected\n"); #endif d->step = StepVersion; writeData(spc_set_version()); } void SocksClient::sock_connectionClosed() { if(d->active) { reset(); connectionClosed(); } else { error(ErrProxyNeg); } } void SocksClient::sock_delayedCloseFinished() { if(d->active) { reset(); delayedCloseFinished(); } } void SocksClient::sock_readyRead() { QByteArray block = d->sock.read(); if(!d->active) { if(d->incoming) processIncoming(block); else processOutgoing(block); } else { if(!d->udp) { appendRead(block); readyRead(); } } } void SocksClient::processOutgoing(const QByteArray &block) { #ifdef PROX_DEBUG // show hex fprintf(stderr, "SocksClient: client recv { "); for(int n = 0; n < (int)block.size(); ++n) fprintf(stderr, "%02X ", (unsigned char)block[n]); fprintf(stderr, " } \n"); #endif ByteStream::appendArray(&d->recvBuf, block); if(d->step == StepVersion) { SPSS_VERSION s; int r = sps_get_version(&d->recvBuf, &s); if(r == -1) { reset(true); error(ErrProxyNeg); return; } else if(r == 1) { if(s.version != 0x05 || s.method == 0xff) { #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: Method selection failed\n"); #endif reset(true); error(ErrProxyNeg); return; } QString str; if(s.method == 0x00) { str = "None"; d->authMethod = AuthNone; } else if(s.method == 0x02) { str = "Username/Password"; d->authMethod = AuthUsername; } else { #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: Server wants to use unknown method '%02x'\n", s.method); #endif reset(true); error(ErrProxyNeg); return; } if(d->authMethod == AuthNone) { // no auth, go straight to the request do_request(); } else if(d->authMethod == AuthUsername) { d->step = StepAuth; #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: Authenticating [Username] ...\n"); #endif writeData(spc_set_authUsername(d->user.toLatin1(), d->pass.toLatin1())); } } } if(d->step == StepAuth) { if(d->authMethod == AuthUsername) { SPSS_AUTHUSERNAME s; int r = sps_get_authUsername(&d->recvBuf, &s); if(r == -1) { reset(true); error(ErrProxyNeg); return; } else if(r == 1) { if(s.version != 0x01) { reset(true); error(ErrProxyNeg); return; } if(!s.success) { reset(true); error(ErrProxyAuth); return; } do_request(); } } } else if(d->step == StepRequest) { SPS_CONNREQ s; int r = sp_get_request(&d->recvBuf, &s); if(r == -1) { reset(true); error(ErrProxyNeg); return; } else if(r == 1) { if(s.cmd != RET_SUCCESS) { #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: client << Error >> [%02x]\n", s.cmd); #endif reset(true); if(s.cmd == RET_UNREACHABLE) error(ErrHostNotFound); else if(s.cmd == RET_CONNREFUSED) error(ErrConnectionRefused); else error(ErrProxyNeg); return; } #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: client << Success >>\n"); #endif if(d->udp) { if(s.address_type == 0x03) d->udpAddr = s.host; else d->udpAddr = s.addr.toString(); d->udpPort = s.port; } d->active = true; QPointer self = this; connected(); if(!self) return; if(!d->recvBuf.isEmpty()) { appendRead(d->recvBuf); d->recvBuf.resize(0); readyRead(); } } } } void SocksClient::do_request() { #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: Requesting ...\n"); #endif d->step = StepRequest; int cmd = d->udp ? REQ_UDPASSOCIATE : REQ_CONNECT; QByteArray buf; if(!d->real_host.isEmpty()) buf = sp_set_request(d->real_host, d->real_port, cmd); else buf = sp_set_request(QHostAddress(), 0, cmd); writeData(buf); } void SocksClient::sock_bytesWritten(int x) { int bytes = x; if(d->pending >= bytes) { d->pending -= bytes; bytes = 0; } else { bytes -= d->pending; d->pending = 0; } if(bytes > 0) bytesWritten(bytes); } void SocksClient::sock_error(int x) { if(d->active) { reset(); error(ErrRead); } else { reset(true); if(x == BSocket::ErrHostNotFound) error(ErrProxyConnect); else if(x == BSocket::ErrConnectionRefused) error(ErrProxyConnect); else if(x == BSocket::ErrRead) error(ErrProxyNeg); } } void SocksClient::serve() { d->waiting = false; d->step = StepVersion; continueIncoming(); } void SocksClient::processIncoming(const QByteArray &block) { #ifdef PROX_DEBUG // show hex fprintf(stderr, "SocksClient: server recv { "); for(int n = 0; n < (int)block.size(); ++n) fprintf(stderr, "%02X ", (unsigned char)block[n]); fprintf(stderr, " } \n"); #endif ByteStream::appendArray(&d->recvBuf, block); if(!d->waiting) continueIncoming(); } void SocksClient::continueIncoming() { if(d->recvBuf.isEmpty()) return; if(d->step == StepVersion) { SPCS_VERSION s; int r = spc_get_version(&d->recvBuf, &s); if(r == -1) { reset(true); error(ErrProxyNeg); return; } else if(r == 1) { if(s.version != 0x05) { reset(true); error(ErrProxyNeg); return; } int methods = 0; for(int n = 0; n < (int)s.methodList.size(); ++n) { unsigned char c = s.methodList[n]; if(c == 0x00) methods |= AuthNone; else if(c == 0x02) methods |= AuthUsername; } d->waiting = true; incomingMethods(methods); } } else if(d->step == StepAuth) { SPCS_AUTHUSERNAME s; int r = spc_get_authUsername(&d->recvBuf, &s); if(r == -1) { reset(true); error(ErrProxyNeg); return; } else if(r == 1) { d->waiting = true; incomingAuth(s.user, s.pass); } } else if(d->step == StepRequest) { SPS_CONNREQ s; int r = sp_get_request(&d->recvBuf, &s); if(r == -1) { reset(true); error(ErrProxyNeg); return; } else if(r == 1) { d->waiting = true; if(s.cmd == REQ_CONNECT) { if(!s.host.isEmpty()) d->rhost = s.host; else d->rhost = s.addr.toString(); d->rport = s.port; incomingConnectRequest(d->rhost, d->rport); } else if(s.cmd == REQ_UDPASSOCIATE) { incomingUDPAssociateRequest(); } else { requestDeny(); return; } } } } void SocksClient::chooseMethod(int method) { if(d->step != StepVersion || !d->waiting) return; unsigned char c; if(method == AuthNone) { d->step = StepRequest; c = 0x00; } else { d->step = StepAuth; c = 0x02; } // version response d->waiting = false; writeData(sps_set_version(c)); continueIncoming(); } void SocksClient::authGrant(bool b) { if(d->step != StepAuth || !d->waiting) return; if(b) d->step = StepRequest; // auth response d->waiting = false; writeData(sps_set_authUsername(b)); if(!b) { reset(true); return; } continueIncoming(); } void SocksClient::requestDeny() { if(d->step != StepRequest || !d->waiting) return; // response d->waiting = false; writeData(sp_set_request(d->rhost, d->rport, RET_UNREACHABLE)); reset(true); } void SocksClient::grantConnect() { if(d->step != StepRequest || !d->waiting) return; // response d->waiting = false; writeData(sp_set_request(d->rhost, d->rport, RET_SUCCESS)); d->active = true; #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: server << Success >>\n"); #endif if(!d->recvBuf.isEmpty()) { appendRead(d->recvBuf); d->recvBuf.resize(0); readyRead(); } } void SocksClient::grantUDPAssociate(const QString &relayHost, int relayPort) { if(d->step != StepRequest || !d->waiting) return; // response d->waiting = false; writeData(sp_set_request(relayHost, relayPort, RET_SUCCESS)); d->udp = true; d->active = true; #ifdef PROX_DEBUG fprintf(stderr, "SocksClient: server << Success >>\n"); #endif if(!d->recvBuf.isEmpty()) d->recvBuf.resize(0); } QHostAddress SocksClient::peerAddress() const { return d->sock.peerAddress(); } quint16 SocksClient::peerPort() const { return d->sock.peerPort(); } QString SocksClient::udpAddress() const { return d->udpAddr; } quint16 SocksClient::udpPort() const { return d->udpPort; } SocksUDP *SocksClient::createUDP(const QString &host, int port, const QHostAddress &routeAddr, int routePort) { return new SocksUDP(this, host, port, routeAddr, routePort); } //---------------------------------------------------------------------------- // SocksServer //---------------------------------------------------------------------------- class SocksServer::Private { public: Private() {} ServSock serv; QList incomingConns; QUdpSocket *sd; }; SocksServer::SocksServer(QObject *parent) :QObject(parent) { d = new Private; d->sd = 0; connect(&d->serv, SIGNAL(connectionReady(int)), SLOT(connectionReady(int))); } SocksServer::~SocksServer() { stop(); while (d->incomingConns.count()) { delete d->incomingConns.takeFirst(); } delete d; } bool SocksServer::isActive() const { return d->serv.isActive(); } bool SocksServer::listen(quint16 port, bool udp) { stop(); if(!d->serv.listen(port)) return false; if(udp) { d->sd = new QUdpSocket(); if(!d->sd->bind(QHostAddress::LocalHost, port)) { delete d->sd; d->sd = 0; d->serv.stop(); return false; } connect(d->sd, SIGNAL(readyRead()), SLOT(sd_activated())); } return true; } void SocksServer::stop() { delete d->sd; d->sd = 0; d->serv.stop(); } int SocksServer::port() const { return d->serv.port(); } QHostAddress SocksServer::address() const { return d->serv.address(); } SocksClient *SocksServer::takeIncoming() { if(d->incomingConns.isEmpty()) return 0; SocksClient *c = d->incomingConns.takeFirst(); // we don't care about errors anymore disconnect(c, SIGNAL(error(int)), this, SLOT(connectionError())); // don't serve the connection until the event loop, to give the caller a chance to map signals QTimer::singleShot(0, c, SLOT(serve())); return c; } void SocksServer::writeUDP(const QHostAddress &addr, int port, const QByteArray &data) { if(d->sd) { d->sd->writeDatagram(data.data(), data.size(), addr, port); } } void SocksServer::connectionReady(int s) { SocksClient *c = new SocksClient(s, this); connect(c, SIGNAL(error(int)), this, SLOT(connectionError())); d->incomingConns.append(c); incomingReady(); } void SocksServer::connectionError() { SocksClient *c = (SocksClient *)sender(); d->incomingConns.removeAll(c); c->deleteLater(); } void SocksServer::sd_activated() { while (d->sd->hasPendingDatagrams()) { QByteArray datagram; QHostAddress sender; quint16 senderPort; datagram.resize(d->sd->pendingDatagramSize()); d->sd->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); incomingUDP(sender.toString(), senderPort, d->sd->peerAddress(), d->sd->peerPort(), datagram); } } // CS_NAMESPACE_END psi-0.14/iris/src/xmpp/cutestuff/httpconnect.h0000644000175000017500000000340211305557616017576 0ustar janjan/* * httpconnect.h - HTTP "CONNECT" proxy * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_HTTPCONNECT_H #define CS_HTTPCONNECT_H #include "bytestream.h" // CS_NAMESPACE_BEGIN class HttpConnect : public ByteStream { Q_OBJECT public: enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; HttpConnect(QObject *parent=0); ~HttpConnect(); void setAuth(const QString &user, const QString &pass=""); void connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port); // from ByteStream bool isOpen() const; void close(); void write(const QByteArray &); QByteArray read(int bytes=0); int bytesAvailable() const; int bytesToWrite() const; signals: void connected(); private slots: void sock_connected(); void sock_connectionClosed(); void sock_delayedCloseFinished(); void sock_readyRead(); void sock_bytesWritten(int); void sock_error(int); private: class Private; Private *d; void reset(bool clear=false); }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/xmpp/cutestuff/bytestream.h0000644000175000017500000000376311305557616017436 0ustar janjan/* * bytestream.h - base class for bytestreams * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_BYTESTREAM_H #define CS_BYTESTREAM_H #include #include // CS_NAMESPACE_BEGIN // CS_EXPORT_BEGIN class ByteStream : public QObject { Q_OBJECT public: enum Error { ErrRead, ErrWrite, ErrCustom = 10 }; ByteStream(QObject *parent=0); virtual ~ByteStream()=0; virtual bool isOpen() const; virtual void close(); virtual void write(const QByteArray &); virtual QByteArray read(int bytes=0); virtual int bytesAvailable() const; virtual int bytesToWrite() const; static void appendArray(QByteArray *a, const QByteArray &b); static QByteArray takeArray(QByteArray *from, int size=0, bool del=true); signals: void connectionClosed(); void delayedCloseFinished(); void readyRead(); void bytesWritten(int); void error(int); protected: void clearReadBuffer(); void clearWriteBuffer(); void appendRead(const QByteArray &); void appendWrite(const QByteArray &); QByteArray takeRead(int size=0, bool del=true); QByteArray takeWrite(int size=0, bool del=true); QByteArray & readBuf(); QByteArray & writeBuf(); virtual int tryWrite(); private: //! \if _hide_doc_ class Private; Private *d; //! \endif }; // CS_EXPORT_END // CS_NAMESPACE_END #endif psi-0.14/iris/src/xmpp/cutestuff/bsocket.cpp0000644000175000017500000002120511305557616017233 0ustar janjan/* * bsocket.cpp - QSocket wrapper based on Bytestream with SRV DNS support * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "bsocket.h" //#include "safedelete.h" #include "ndns.h" #include "srvresolver.h" //#define BS_DEBUG #ifdef BS_DEBUG #include #endif #define READBUFSIZE 65536 // CS_NAMESPACE_BEGIN class QTcpSocketSignalRelay : public QObject { Q_OBJECT public: QTcpSocketSignalRelay(QTcpSocket *sock, QObject *parent = 0) :QObject(parent) { qRegisterMetaType("QAbstractSocket::SocketError"); connect(sock, SIGNAL(hostFound()), SLOT(sock_hostFound()), Qt::QueuedConnection); connect(sock, SIGNAL(connected()), SLOT(sock_connected()), Qt::QueuedConnection); connect(sock, SIGNAL(disconnected()), SLOT(sock_disconnected()), Qt::QueuedConnection); connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()), Qt::QueuedConnection); connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64)), Qt::QueuedConnection); connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sock_error(QAbstractSocket::SocketError)), Qt::QueuedConnection); } signals: void hostFound(); void connected(); void disconnected(); void readyRead(); void bytesWritten(qint64); void error(QAbstractSocket::SocketError); public slots: void sock_hostFound() { emit hostFound(); } void sock_connected() { emit connected(); } void sock_disconnected() { emit disconnected(); } void sock_readyRead() { emit readyRead(); } void sock_bytesWritten(qint64 x) { emit bytesWritten(x); } void sock_error(QAbstractSocket::SocketError x) { emit error(x); } }; class BSocket::Private { public: Private() { qsock = 0; qsock_relay = 0; } QTcpSocket *qsock; QTcpSocketSignalRelay *qsock_relay; int state; NDns ndns; SrvResolver srv; QString host; int port; //SafeDelete sd; }; BSocket::BSocket(QObject *parent) :ByteStream(parent) { d = new Private; connect(&d->ndns, SIGNAL(resultsReady()), SLOT(ndns_done())); connect(&d->srv, SIGNAL(resultsReady()), SLOT(srv_done())); reset(); } BSocket::~BSocket() { reset(true); delete d; } void BSocket::reset(bool clear) { if(d->qsock) { delete d->qsock_relay; d->qsock_relay = 0; /*d->qsock->disconnect(this); if(!clear && d->qsock->isOpen() && d->qsock->isValid()) {*/ // move remaining into the local queue QByteArray block(d->qsock->bytesAvailable(), 0); d->qsock->read(block.data(), block.size()); appendRead(block); //} //d->sd.deleteLater(d->qsock); d->qsock->deleteLater(); d->qsock = 0; } else { if(clear) clearReadBuffer(); } if(d->srv.isBusy()) d->srv.stop(); if(d->ndns.isBusy()) d->ndns.stop(); d->state = Idle; } void BSocket::ensureSocket() { if(!d->qsock) { d->qsock = new QTcpSocket; #if QT_VERSION >= 0x030200 d->qsock->setReadBufferSize(READBUFSIZE); #endif d->qsock_relay = new QTcpSocketSignalRelay(d->qsock); connect(d->qsock_relay, SIGNAL(hostFound()), SLOT(qs_hostFound())); connect(d->qsock_relay, SIGNAL(connected()), SLOT(qs_connected())); connect(d->qsock_relay, SIGNAL(disconnected()), SLOT(qs_closed())); connect(d->qsock_relay, SIGNAL(readyRead()), SLOT(qs_readyRead())); connect(d->qsock_relay, SIGNAL(bytesWritten(qint64)), SLOT(qs_bytesWritten(qint64))); connect(d->qsock_relay, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(qs_error(QAbstractSocket::SocketError))); } } void BSocket::connectToHost(const QString &host, quint16 port) { reset(true); d->host = host; d->port = port; d->state = HostLookup; d->ndns.resolve(d->host); } void BSocket::connectToServer(const QString &srv, const QString &type) { reset(true); d->state = HostLookup; d->srv.resolve(srv, type, "tcp"); } int BSocket::socket() const { if(d->qsock) return d->qsock->socketDescriptor(); else return -1; } void BSocket::setSocket(int s) { reset(true); ensureSocket(); d->state = Connected; d->qsock->setSocketDescriptor(s); } int BSocket::state() const { return d->state; } bool BSocket::isOpen() const { if(d->state == Connected) return true; else return false; } void BSocket::close() { if(d->state == Idle) return; if(d->qsock) { d->qsock->close(); d->state = Closing; if(d->qsock->bytesToWrite() == 0) reset(); } else { reset(); } } void BSocket::write(const QByteArray &a) { if(d->state != Connected) return; #ifdef BS_DEBUG QString s = QString::fromUtf8(a); fprintf(stderr, "BSocket: writing [%d]: {%s}\n", a.size(), s.latin1()); #endif d->qsock->write(a.data(), a.size()); } QByteArray BSocket::read(int bytes) { QByteArray block; if(d->qsock) { int max = bytesAvailable(); if(bytes <= 0 || bytes > max) bytes = max; block.resize(bytes); d->qsock->read(block.data(), block.size()); } else block = ByteStream::read(bytes); #ifdef BS_DEBUG QString s = QString::fromUtf8(block); fprintf(stderr, "BSocket: read [%d]: {%s}\n", block.size(), s.latin1()); #endif return block; } int BSocket::bytesAvailable() const { if(d->qsock) return d->qsock->bytesAvailable(); else return ByteStream::bytesAvailable(); } int BSocket::bytesToWrite() const { if(!d->qsock) return 0; return d->qsock->bytesToWrite(); } QHostAddress BSocket::address() const { if(d->qsock) return d->qsock->localAddress(); else return QHostAddress(); } quint16 BSocket::port() const { if(d->qsock) return d->qsock->localPort(); else return 0; } QHostAddress BSocket::peerAddress() const { if(d->qsock) return d->qsock->peerAddress(); else return QHostAddress(); } quint16 BSocket::peerPort() const { if(d->qsock) return d->qsock->peerPort(); else return 0; } void BSocket::srv_done() { if(d->srv.failed()) { #ifdef BS_DEBUG fprintf(stderr, "BSocket: Error resolving hostname.\n"); #endif error(ErrHostNotFound); return; } d->host = d->srv.resultAddress().toString(); d->port = d->srv.resultPort(); do_connect(); //QTimer::singleShot(0, this, SLOT(do_connect())); //hostFound(); } void BSocket::ndns_done() { if(!d->ndns.result().isNull()) { d->host = d->ndns.resultString(); d->state = Connecting; do_connect(); //QTimer::singleShot(0, this, SLOT(do_connect())); //hostFound(); } else { #ifdef BS_DEBUG fprintf(stderr, "BSocket: Error resolving hostname.\n"); #endif error(ErrHostNotFound); } } void BSocket::do_connect() { #ifdef BS_DEBUG fprintf(stderr, "BSocket: Connecting to %s:%d\n", d->host.latin1(), d->port); #endif ensureSocket(); d->qsock->connectToHost(d->host, d->port); } void BSocket::qs_hostFound() { //SafeDeleteLock s(&d->sd); } void BSocket::qs_connected() { d->state = Connected; #ifdef BS_DEBUG fprintf(stderr, "BSocket: Connected.\n"); #endif //SafeDeleteLock s(&d->sd); connected(); } void BSocket::qs_closed() { if(d->state == Closing) { #ifdef BS_DEBUG fprintf(stderr, "BSocket: Delayed Close Finished.\n"); #endif //SafeDeleteLock s(&d->sd); reset(); delayedCloseFinished(); } } void BSocket::qs_readyRead() { //SafeDeleteLock s(&d->sd); readyRead(); } void BSocket::qs_bytesWritten(qint64 x64) { int x = x64; #ifdef BS_DEBUG fprintf(stderr, "BSocket: BytesWritten [%d].\n", x); #endif //SafeDeleteLock s(&d->sd); bytesWritten(x); } void BSocket::qs_error(QAbstractSocket::SocketError x) { if(x == QTcpSocket::RemoteHostClosedError) { #ifdef BS_DEBUG fprintf(stderr, "BSocket: Connection Closed.\n"); #endif //SafeDeleteLock s(&d->sd); reset(); connectionClosed(); return; } #ifdef BS_DEBUG fprintf(stderr, "BSocket: Error.\n"); #endif //SafeDeleteLock s(&d->sd); // connection error during SRV host connect? try next if(d->state == HostLookup && (x == QTcpSocket::ConnectionRefusedError || x == QTcpSocket::HostNotFoundError)) { d->srv.next(); return; } reset(); if(x == QTcpSocket::ConnectionRefusedError) error(ErrConnectionRefused); else if(x == QTcpSocket::HostNotFoundError) error(ErrHostNotFound); else error(ErrRead); } #include "bsocket.moc" // CS_NAMESPACE_END psi-0.14/iris/src/xmpp/cutestuff/httppoll.cpp0000644000175000017500000004730411305557616017457 0ustar janjan/* * httppoll.cpp - HTTP polling proxy * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "httppoll.h" #include #include #include #include #include #include #include #include "bsocket.h" #ifdef PROX_DEBUG #include #endif #define POLL_KEYS 64 // CS_NAMESPACE_BEGIN static QByteArray randomArray(int size) { QByteArray a; a.resize(size); for(int n = 0; n < size; ++n) a[n] = (char)(256.0*rand()/(RAND_MAX+1.0)); return a; } //---------------------------------------------------------------------------- // HttpPoll //---------------------------------------------------------------------------- static QString hpk(int n, const QString &s) { if(n == 0) return s; else return QCA::Base64().arrayToString( QCA::Hash("sha1").hash( hpk(n - 1, s).toLatin1() ).toByteArray() ); } class HttpPoll::Private { public: Private() {} HttpProxyPost http; QString host; int port; QString user, pass; QString url; bool use_proxy; QByteArray out; int state; bool closing; QString ident; QTimer *t; QString key[POLL_KEYS]; int key_n; int polltime; }; HttpPoll::HttpPoll(QObject *parent) :ByteStream(parent) { d = new Private; d->polltime = 30; d->t = new QTimer; d->t->setSingleShot(true); connect(d->t, SIGNAL(timeout()), SLOT(do_sync())); connect(&d->http, SIGNAL(result()), SLOT(http_result())); connect(&d->http, SIGNAL(error(int)), SLOT(http_error(int))); reset(true); } HttpPoll::~HttpPoll() { reset(true); delete d->t; delete d; } void HttpPoll::reset(bool clear) { if(d->http.isActive()) d->http.stop(); if(clear) clearReadBuffer(); clearWriteBuffer(); d->out.resize(0); d->state = 0; d->closing = false; d->t->stop(); } void HttpPoll::setAuth(const QString &user, const QString &pass) { d->user = user; d->pass = pass; } void HttpPoll::connectToUrl(const QString &url) { connectToHost("", 0, url); } void HttpPoll::connectToHost(const QString &proxyHost, int proxyPort, const QString &url) { reset(true); // using proxy? if(!proxyHost.isEmpty()) { d->host = proxyHost; d->port = proxyPort; d->url = url; d->use_proxy = true; } else { QUrl u = url; d->host = u.host(); if(u.port() != -1) d->port = u.port(); else d->port = 80; d->url = u.path() + "?" + u.encodedQuery(); d->use_proxy = false; } resetKey(); bool last; QString key = getKey(&last); #ifdef PROX_DEBUG fprintf(stderr, "HttpPoll: Connecting to %s:%d [%s]", d->host.latin1(), d->port, d->url.latin1()); if(d->user.isEmpty()) fprintf(stderr, "\n"); else fprintf(stderr, ", auth {%s,%s}\n", d->user.latin1(), d->pass.latin1()); #endif QPointer self = this; syncStarted(); if(!self) return; d->state = 1; d->http.setAuth(d->user, d->pass); d->http.post(d->host, d->port, d->url, makePacket("0", key, "", QByteArray()), d->use_proxy); } QByteArray HttpPoll::makePacket(const QString &ident, const QString &key, const QString &newkey, const QByteArray &block) { QString str = ident; if(!key.isEmpty()) { str += ';'; str += key; } if(!newkey.isEmpty()) { str += ';'; str += newkey; } str += ','; QByteArray cs = str.toLatin1(); int len = cs.length(); QByteArray a; a.resize(len + block.size()); memcpy(a.data(), cs.data(), len); memcpy(a.data() + len, block.data(), block.size()); return a; } int HttpPoll::pollInterval() const { return d->polltime; } void HttpPoll::setPollInterval(int seconds) { d->polltime = seconds; } bool HttpPoll::isOpen() const { return (d->state == 2 ? true: false); } void HttpPoll::close() { if(d->state == 0 || d->closing) return; if(bytesToWrite() == 0) reset(); else d->closing = true; } void HttpPoll::http_result() { // check for death :) QPointer self = this; syncFinished(); if(!self) return; // get id and packet QString id; QString cookie = d->http.getHeader("Set-Cookie"); int n = cookie.indexOf("ID="); if(n == -1) { reset(); error(ErrRead); return; } n += 3; int n2 = cookie.indexOf(';', n); if(n2 != -1) id = cookie.mid(n, n2-n); else id = cookie.mid(n); QByteArray block = d->http.body(); // session error? if(id.right(2) == ":0") { if(id == "0:0" && d->state == 2) { reset(); connectionClosed(); return; } else { reset(); error(ErrRead); return; } } d->ident = id; bool justNowConnected = false; if(d->state == 1) { d->state = 2; justNowConnected = true; } // sync up again soon if(bytesToWrite() > 0 || !d->closing) { d->t->start(d->polltime * 1000); } // connecting if(justNowConnected) { connected(); } else { if(!d->out.isEmpty()) { int x = d->out.size(); d->out.resize(0); takeWrite(x); bytesWritten(x); } } if(!self) return; if(!block.isEmpty()) { appendRead(block); readyRead(); } if(!self) return; if(bytesToWrite() > 0) { do_sync(); } else { if(d->closing) { reset(); delayedCloseFinished(); return; } } } void HttpPoll::http_error(int x) { reset(); if(x == HttpProxyPost::ErrConnectionRefused) error(ErrConnectionRefused); else if(x == HttpProxyPost::ErrHostNotFound) error(ErrHostNotFound); else if(x == HttpProxyPost::ErrSocket) error(ErrRead); else if(x == HttpProxyPost::ErrProxyConnect) error(ErrProxyConnect); else if(x == HttpProxyPost::ErrProxyNeg) error(ErrProxyNeg); else if(x == HttpProxyPost::ErrProxyAuth) error(ErrProxyAuth); } int HttpPoll::tryWrite() { if(!d->http.isActive()) do_sync(); return 0; } void HttpPoll::do_sync() { if(d->http.isActive()) return; d->t->stop(); d->out = takeWrite(0, false); bool last; QString key = getKey(&last); QString newkey; if(last) { resetKey(); newkey = getKey(&last); } QPointer self = this; syncStarted(); if(!self) return; d->http.post(d->host, d->port, d->url, makePacket(d->ident, key, newkey, d->out), d->use_proxy); } void HttpPoll::resetKey() { #ifdef PROX_DEBUG fprintf(stderr, "HttpPoll: reset key!\n"); #endif QByteArray a = randomArray(64); QString str = QString::fromLatin1(a.data(), a.size()); d->key_n = POLL_KEYS; for(int n = 0; n < POLL_KEYS; ++n) d->key[n] = hpk(n+1, str); } const QString & HttpPoll::getKey(bool *last) { *last = false; --(d->key_n); if(d->key_n == 0) *last = true; return d->key[d->key_n]; } //---------------------------------------------------------------------------- // HttpProxyPost //---------------------------------------------------------------------------- static QString extractLine(QByteArray *buf, bool *found) { // scan for newline int n; for(n = 0; n < (int)buf->size()-1; ++n) { if(buf->at(n) == '\r' && buf->at(n+1) == '\n') { QByteArray cstr; cstr.resize(n); memcpy(cstr.data(), buf->data(), n); n += 2; // hack off CR/LF memmove(buf->data(), buf->data() + n, buf->size() - n); buf->resize(buf->size() - n); QString s = QString::fromUtf8(cstr); if(found) *found = true; return s; } } if(found) *found = false; return ""; } static bool extractMainHeader(const QString &line, QString *proto, int *code, QString *msg) { int n = line.indexOf(' '); if(n == -1) return false; if(proto) *proto = line.mid(0, n); ++n; int n2 = line.indexOf(' ', n); if(n2 == -1) return false; if(code) *code = line.mid(n, n2-n).toInt(); n = n2+1; if(msg) *msg = line.mid(n); return true; } class HttpProxyPost::Private { public: Private() {} BSocket sock; QByteArray postdata, recvBuf, body; QString url; QString user, pass; bool inHeader; QStringList headerLines; bool asProxy; QString host; }; HttpProxyPost::HttpProxyPost(QObject *parent) :QObject(parent) { d = new Private; connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected())); connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int))); reset(true); } HttpProxyPost::~HttpProxyPost() { reset(true); delete d; } void HttpProxyPost::reset(bool clear) { if(d->sock.state() != BSocket::Idle) d->sock.close(); d->recvBuf.resize(0); if(clear) d->body.resize(0); } void HttpProxyPost::setAuth(const QString &user, const QString &pass) { d->user = user; d->pass = pass; } bool HttpProxyPost::isActive() const { return (d->sock.state() == BSocket::Idle ? false: true); } void HttpProxyPost::post(const QString &proxyHost, int proxyPort, const QString &url, const QByteArray &data, bool asProxy) { reset(true); d->host = proxyHost; d->url = url; d->postdata = data; d->asProxy = asProxy; #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: Connecting to %s:%d", proxyHost.latin1(), proxyPort); if(d->user.isEmpty()) fprintf(stderr, "\n"); else fprintf(stderr, ", auth {%s,%s}\n", d->user.latin1(), d->pass.latin1()); #endif d->sock.connectToHost(proxyHost, proxyPort); } void HttpProxyPost::stop() { reset(); } QByteArray HttpProxyPost::body() const { return d->body; } QString HttpProxyPost::getHeader(const QString &var) const { for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) { const QString &s = *it; int n = s.indexOf(": "); if(n == -1) continue; QString v = s.mid(0, n); if(v.toLower() == var.toLower()) return s.mid(n+2); } return ""; } void HttpProxyPost::sock_connected() { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: Connected\n"); #endif d->inHeader = true; d->headerLines.clear(); QUrl u = d->url; // connected, now send the request QString s; s += QString("POST ") + d->url + " HTTP/1.0\r\n"; if(d->asProxy) { if(!d->user.isEmpty()) { QString str = d->user + ':' + d->pass; s += QString("Proxy-Authorization: Basic ") + QCA::Base64().encodeString(str) + "\r\n"; } s += "Pragma: no-cache\r\n"; s += QString("Host: ") + u.host() + "\r\n"; } else { s += QString("Host: ") + d->host + "\r\n"; } s += "Content-Type: application/x-www-form-urlencoded\r\n"; s += QString("Content-Length: ") + QString::number(d->postdata.size()) + "\r\n"; s += "\r\n"; // write request d->sock.write(s.toUtf8()); // write postdata d->sock.write(d->postdata); } void HttpProxyPost::sock_connectionClosed() { d->body = d->recvBuf; reset(); result(); } void HttpProxyPost::sock_readyRead() { QByteArray block = d->sock.read(); ByteStream::appendArray(&d->recvBuf, block); if(d->inHeader) { // grab available lines while(1) { bool found; QString line = extractLine(&d->recvBuf, &found); if(!found) break; if(line.isEmpty()) { d->inHeader = false; break; } d->headerLines += line; } // done with grabbing the header? if(!d->inHeader) { QString str = d->headerLines.first(); d->headerLines.takeFirst(); QString proto; int code; QString msg; if(!extractMainHeader(str, &proto, &code, &msg)) { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: invalid header!\n"); #endif reset(true); error(ErrProxyNeg); return; } else { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: header proto=[%s] code=[%d] msg=[%s]\n", proto.latin1(), code, msg.latin1()); for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) fprintf(stderr, "HttpProxyPost: * [%s]\n", (*it).latin1()); #endif } if(code == 200) { // OK #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: << Success >>\n"); #endif } else { int err; QString errStr; if(code == 407) { // Authentication failed err = ErrProxyAuth; errStr = tr("Authentication failed"); } else if(code == 404) { // Host not found err = ErrHostNotFound; errStr = tr("Host not found"); } else if(code == 403) { // Access denied err = ErrProxyNeg; errStr = tr("Access denied"); } else if(code == 503) { // Connection refused err = ErrConnectionRefused; errStr = tr("Connection refused"); } else { // invalid reply err = ErrProxyNeg; errStr = tr("Invalid reply"); } #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: << Error >> [%s]\n", errStr.latin1()); #endif reset(true); error(err); return; } } } } void HttpProxyPost::sock_error(int x) { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyPost: socket error: %d\n", x); #endif reset(true); if(x == BSocket::ErrHostNotFound) error(ErrProxyConnect); else if(x == BSocket::ErrConnectionRefused) error(ErrProxyConnect); else if(x == BSocket::ErrRead) error(ErrProxyNeg); } //---------------------------------------------------------------------------- // HttpProxyGetStream //---------------------------------------------------------------------------- class HttpProxyGetStream::Private { public: Private() {} BSocket sock; QByteArray recvBuf; QString url; QString user, pass; bool inHeader; QStringList headerLines; bool use_ssl; bool asProxy; QString host; int length; QCA::TLS *tls; }; HttpProxyGetStream::HttpProxyGetStream(QObject *parent) :QObject(parent) { d = new Private; d->tls = 0; connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected())); connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int))); reset(true); } HttpProxyGetStream::~HttpProxyGetStream() { reset(true); delete d; } void HttpProxyGetStream::reset(bool /*clear*/) { if(d->tls) { delete d->tls; d->tls = 0; } if(d->sock.state() != BSocket::Idle) d->sock.close(); d->recvBuf.resize(0); //if(clear) // d->body.resize(0); d->length = -1; } void HttpProxyGetStream::setAuth(const QString &user, const QString &pass) { d->user = user; d->pass = pass; } bool HttpProxyGetStream::isActive() const { return (d->sock.state() == BSocket::Idle ? false: true); } void HttpProxyGetStream::get(const QString &proxyHost, int proxyPort, const QString &url, bool ssl, bool asProxy) { reset(true); d->host = proxyHost; d->url = url; d->use_ssl = ssl; d->asProxy = asProxy; #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: Connecting to %s:%d", proxyHost.latin1(), proxyPort); if(d->user.isEmpty()) fprintf(stderr, "\n"); else fprintf(stderr, ", auth {%s,%s}\n", d->user.latin1(), d->pass.latin1()); #endif d->sock.connectToHost(proxyHost, proxyPort); } void HttpProxyGetStream::stop() { reset(); } QString HttpProxyGetStream::getHeader(const QString &var) const { for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) { const QString &s = *it; int n = s.indexOf(": "); if(n == -1) continue; QString v = s.mid(0, n); if(v.toLower() == var.toLower()) return s.mid(n+2); } return ""; } int HttpProxyGetStream::length() const { return d->length; } void HttpProxyGetStream::sock_connected() { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: Connected\n"); #endif if(d->use_ssl) { d->tls = new QCA::TLS; connect(d->tls, SIGNAL(readyRead()), SLOT(tls_readyRead())); connect(d->tls, SIGNAL(readyReadOutgoing()), SLOT(tls_readyReadOutgoing())); connect(d->tls, SIGNAL(error()), SLOT(tls_error())); d->tls->startClient(); } d->inHeader = true; d->headerLines.clear(); QUrl u = d->url; // connected, now send the request QString s; s += QString("GET ") + d->url + " HTTP/1.0\r\n"; if(d->asProxy) { if(!d->user.isEmpty()) { QString str = d->user + ':' + d->pass; s += QString("Proxy-Authorization: Basic ") + QCA::Base64().encodeString(str) + "\r\n"; } s += "Pragma: no-cache\r\n"; s += QString("Host: ") + u.host() + "\r\n"; } else { s += QString("Host: ") + d->host + "\r\n"; } s += "\r\n"; // write request if(d->use_ssl) d->tls->write(s.toUtf8()); else d->sock.write(s.toUtf8()); } void HttpProxyGetStream::sock_connectionClosed() { //d->body = d->recvBuf; reset(); emit finished(); } void HttpProxyGetStream::sock_readyRead() { QByteArray block = d->sock.read(); if(d->use_ssl) d->tls->writeIncoming(block); else processData(block); } void HttpProxyGetStream::processData(const QByteArray &block) { printf("processData: %d bytes\n", block.size()); if(!d->inHeader) { emit dataReady(block); return; } ByteStream::appendArray(&d->recvBuf, block); if(d->inHeader) { // grab available lines while(1) { bool found; QString line = extractLine(&d->recvBuf, &found); if(!found) break; if(line.isEmpty()) { printf("empty line\n"); d->inHeader = false; break; } d->headerLines += line; printf("headerLine: [%s]\n", qPrintable(line)); } // done with grabbing the header? if(!d->inHeader) { QString str = d->headerLines.first(); d->headerLines.takeFirst(); QString proto; int code; QString msg; if(!extractMainHeader(str, &proto, &code, &msg)) { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: invalid header!\n"); #endif reset(true); error(ErrProxyNeg); return; } else { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: header proto=[%s] code=[%d] msg=[%s]\n", proto.latin1(), code, msg.latin1()); for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) fprintf(stderr, "HttpProxyGetStream: * [%s]\n", (*it).latin1()); #endif } if(code == 200) { // OK #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: << Success >>\n"); #endif bool ok; int x = getHeader("Content-Length").toInt(&ok); if(ok) d->length = x; QPointer self = this; emit handshaken(); if(!self) return; } else { int err; QString errStr; if(code == 407) { // Authentication failed err = ErrProxyAuth; errStr = tr("Authentication failed"); } else if(code == 404) { // Host not found err = ErrHostNotFound; errStr = tr("Host not found"); } else if(code == 403) { // Access denied err = ErrProxyNeg; errStr = tr("Access denied"); } else if(code == 503) { // Connection refused err = ErrConnectionRefused; errStr = tr("Connection refused"); } else { // invalid reply err = ErrProxyNeg; errStr = tr("Invalid reply"); } #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: << Error >> [%s]\n", errStr.latin1()); #endif reset(true); error(err); return; } if(!d->recvBuf.isEmpty()) { QByteArray a = d->recvBuf; d->recvBuf.clear(); emit dataReady(a); } } } } void HttpProxyGetStream::sock_error(int x) { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: socket error: %d\n", x); #endif reset(true); if(x == BSocket::ErrHostNotFound) error(ErrProxyConnect); else if(x == BSocket::ErrConnectionRefused) error(ErrProxyConnect); else if(x == BSocket::ErrRead) error(ErrProxyNeg); } void HttpProxyGetStream::tls_readyRead() { //printf("tls_readyRead\n"); processData(d->tls->read()); } void HttpProxyGetStream::tls_readyReadOutgoing() { //printf("tls_readyReadOutgoing\n"); d->sock.write(d->tls->readOutgoing()); } void HttpProxyGetStream::tls_error() { #ifdef PROX_DEBUG fprintf(stderr, "HttpProxyGetStream: ssl error: %d\n", d->tls->errorCode()); #endif reset(true); error(ErrConnectionRefused); // FIXME: bogus error } // CS_NAMESPACE_END psi-0.14/iris/src/xmpp/cutestuff/httppoll.h0000644000175000017500000000675211305557616017126 0ustar janjan/* * httppoll.h - HTTP polling proxy * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_HTTPPOLL_H #define CS_HTTPPOLL_H #include "bytestream.h" // CS_NAMESPACE_BEGIN class HttpPoll : public ByteStream { Q_OBJECT public: enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; HttpPoll(QObject *parent=0); ~HttpPoll(); void setAuth(const QString &user, const QString &pass=""); void connectToUrl(const QString &url); void connectToHost(const QString &proxyHost, int proxyPort, const QString &url); int pollInterval() const; void setPollInterval(int seconds); // from ByteStream bool isOpen() const; void close(); signals: void connected(); void syncStarted(); void syncFinished(); protected: int tryWrite(); private slots: void http_result(); void http_error(int); void do_sync(); private: class Private; Private *d; void reset(bool clear=false); QByteArray makePacket(const QString &ident, const QString &key, const QString &newkey, const QByteArray &block); void resetKey(); const QString & getKey(bool *); }; class HttpProxyPost : public QObject { Q_OBJECT public: enum Error { ErrConnectionRefused, ErrHostNotFound, ErrSocket, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; HttpProxyPost(QObject *parent=0); ~HttpProxyPost(); void setAuth(const QString &user, const QString &pass=""); bool isActive() const; void post(const QString &proxyHost, int proxyPort, const QString &url, const QByteArray &data, bool asProxy=true); void stop(); QByteArray body() const; QString getHeader(const QString &) const; signals: void result(); void error(int); private slots: void sock_connected(); void sock_connectionClosed(); void sock_readyRead(); void sock_error(int); private: class Private; Private *d; void reset(bool clear=false); }; class HttpProxyGetStream : public QObject { Q_OBJECT public: enum Error { ErrConnectionRefused, ErrHostNotFound, ErrSocket, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; HttpProxyGetStream(QObject *parent=0); ~HttpProxyGetStream(); void setAuth(const QString &user, const QString &pass=""); bool isActive() const; void get(const QString &proxyHost, int proxyPort, const QString &url, bool ssl=false, bool asProxy=false); void stop(); QString getHeader(const QString &) const; int length() const; // -1 for unknown signals: void handshaken(); void dataReady(const QByteArray &buf); void finished(); void error(int); private slots: void sock_connected(); void sock_connectionClosed(); void sock_readyRead(); void sock_error(int); void tls_readyRead(); void tls_readyReadOutgoing(); void tls_error(); private: class Private; Private *d; void reset(bool clear=false); void processData(const QByteArray &block); }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/xmpp/cutestuff/socks.h0000644000175000017500000000751711305557616016402 0ustar janjan/* * socks.h - SOCKS5 TCP proxy client/server * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_SOCKS_H #define CS_SOCKS_H #include "bytestream.h" // CS_NAMESPACE_BEGIN class QHostAddress; class SocksClient; class SocksServer; class SocksUDP : public QObject { Q_OBJECT public: ~SocksUDP(); void change(const QString &host, int port); void write(const QByteArray &data); signals: void packetReady(const QByteArray &data); private slots: void sd_activated(); private: class Private; Private *d; friend class SocksClient; SocksUDP(SocksClient *sc, const QString &host, int port, const QHostAddress &routeAddr, int routePort); }; class SocksClient : public ByteStream { Q_OBJECT public: enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; enum Method { AuthNone=0x0001, AuthUsername=0x0002 }; enum Request { ReqConnect, ReqUDPAssociate }; SocksClient(QObject *parent=0); SocksClient(int, QObject *parent=0); ~SocksClient(); bool isIncoming() const; // outgoing void setAuth(const QString &user, const QString &pass=""); void connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port, bool udpMode=false); // incoming void chooseMethod(int); void authGrant(bool); void requestDeny(); void grantConnect(); void grantUDPAssociate(const QString &relayHost, int relayPort); // from ByteStream bool isOpen() const; void close(); void write(const QByteArray &); QByteArray read(int bytes=0); int bytesAvailable() const; int bytesToWrite() const; // remote address QHostAddress peerAddress() const; quint16 peerPort() const; // udp QString udpAddress() const; quint16 udpPort() const; SocksUDP *createUDP(const QString &host, int port, const QHostAddress &routeAddr, int routePort); signals: // outgoing void connected(); // incoming void incomingMethods(int); void incomingAuth(const QString &user, const QString &pass); void incomingConnectRequest(const QString &host, int port); void incomingUDPAssociateRequest(); private slots: void sock_connected(); void sock_connectionClosed(); void sock_delayedCloseFinished(); void sock_readyRead(); void sock_bytesWritten(int); void sock_error(int); void serve(); private: class Private; Private *d; void init(); void reset(bool clear=false); void do_request(); void processOutgoing(const QByteArray &); void processIncoming(const QByteArray &); void continueIncoming(); void writeData(const QByteArray &a); }; class SocksServer : public QObject { Q_OBJECT public: SocksServer(QObject *parent=0); ~SocksServer(); bool isActive() const; bool listen(quint16 port, bool udp=false); void stop(); int port() const; QHostAddress address() const; SocksClient *takeIncoming(); void writeUDP(const QHostAddress &addr, int port, const QByteArray &data); signals: void incomingReady(); void incomingUDP(const QString &host, int port, const QHostAddress &addr, int sourcePort, const QByteArray &data); private slots: void connectionReady(int); void connectionError(); void sd_activated(); private: class Private; Private *d; }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/xmpp/cutestuff/bytestream.cpp0000644000175000017500000001622211305557616017763 0ustar janjan/* * bytestream.cpp - base class for bytestreams * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bytestream.h" #include // CS_NAMESPACE_BEGIN //! \class ByteStream bytestream.h //! \brief Base class for "bytestreams" //! //! This class provides a basic framework for a "bytestream", here defined //! as a bi-directional, asynchronous pipe of data. It can be used to create //! several different kinds of bytestream-applications, such as a console or //! TCP connection, or something more abstract like a security layer or tunnel, //! all with the same interface. The provided functions make creating such //! classes simpler. ByteStream is a pure-virtual class, so you do not use it //! on its own, but instead through a subclass such as \a BSocket. //! //! The signals connectionClosed(), delayedCloseFinished(), readyRead(), //! bytesWritten(), and error() serve the exact same function as those from //! QSocket. //! //! The simplest way to create a ByteStream is to reimplement isOpen(), close(), //! and tryWrite(). Call appendRead() whenever you want to make data available for //! reading. ByteStream will take care of the buffers with regards to the caller, //! and will call tryWrite() when the write buffer gains data. It will be your //! job to call tryWrite() whenever it is acceptable to write more data to //! the underlying system. //! //! If you need more advanced control, reimplement read(), write(), bytesAvailable(), //! and/or bytesToWrite() as necessary. //! //! Use appendRead(), appendWrite(), takeRead(), and takeWrite() to modify the //! buffers. If you have more advanced requirements, the buffers can be accessed //! directly with readBuf() and writeBuf(). //! //! Also available are the static convenience functions ByteStream::appendArray() //! and ByteStream::takeArray(), which make dealing with byte queues very easy. class ByteStream::Private { public: Private() {} QByteArray readBuf, writeBuf; }; //! //! Constructs a ByteStream object with parent \a parent. ByteStream::ByteStream(QObject *parent) :QObject(parent) { d = new Private; } //! //! Destroys the object and frees allocated resources. ByteStream::~ByteStream() { delete d; } //! //! Returns TRUE if the stream is open, meaning that you can write to it. bool ByteStream::isOpen() const { return false; } //! //! Closes the stream. If there is data in the write buffer then it will be //! written before actually closing the stream. Once all data has been written, //! the delayedCloseFinished() signal will be emitted. //! \sa delayedCloseFinished() void ByteStream::close() { } //! //! Writes array \a a to the stream. void ByteStream::write(const QByteArray &a) { if(!isOpen()) return; bool doWrite = bytesToWrite() == 0 ? true: false; appendWrite(a); if(doWrite) tryWrite(); } //! //! Reads bytes \a bytes of data from the stream and returns them as an array. If \a bytes is 0, then //! \a read will return all available data. QByteArray ByteStream::read(int bytes) { return takeRead(bytes); } //! //! Returns the number of bytes available for reading. int ByteStream::bytesAvailable() const { return d->readBuf.size(); } //! //! Returns the number of bytes that are waiting to be written. int ByteStream::bytesToWrite() const { return d->writeBuf.size(); } //! //! Clears the read buffer. void ByteStream::clearReadBuffer() { d->readBuf.resize(0); } //! //! Clears the write buffer. void ByteStream::clearWriteBuffer() { d->writeBuf.resize(0); } //! //! Appends \a block to the end of the read buffer. void ByteStream::appendRead(const QByteArray &block) { appendArray(&d->readBuf, block); } //! //! Appends \a block to the end of the write buffer. void ByteStream::appendWrite(const QByteArray &block) { appendArray(&d->writeBuf, block); } //! //! Returns \a size bytes from the start of the read buffer. //! If \a size is 0, then all available data will be returned. //! If \a del is TRUE, then the bytes are also removed. QByteArray ByteStream::takeRead(int size, bool del) { return takeArray(&d->readBuf, size, del); } //! //! Returns \a size bytes from the start of the write buffer. //! If \a size is 0, then all available data will be returned. //! If \a del is TRUE, then the bytes are also removed. QByteArray ByteStream::takeWrite(int size, bool del) { return takeArray(&d->writeBuf, size, del); } //! //! Returns a reference to the read buffer. QByteArray & ByteStream::readBuf() { return d->readBuf; } //! //! Returns a reference to the write buffer. QByteArray & ByteStream::writeBuf() { return d->writeBuf; } //! //! Attempts to try and write some bytes from the write buffer, and returns the number //! successfully written or -1 on error. The default implementation returns -1. int ByteStream::tryWrite() { return -1; } //! //! Append array \a b to the end of the array pointed to by \a a. void ByteStream::appendArray(QByteArray *a, const QByteArray &b) { int oldsize = a->size(); a->resize(oldsize + b.size()); memcpy(a->data() + oldsize, b.data(), b.size()); } //! //! Returns \a size bytes from the start of the array pointed to by \a from. //! If \a size is 0, then all available data will be returned. //! If \a del is TRUE, then the bytes are also removed. QByteArray ByteStream::takeArray(QByteArray *from, int size, bool del) { QByteArray a; if(size == 0) { a = *from; if(del) from->resize(0); } else { if(size > (int)from->size()) size = from->size(); a.resize(size); char *r = from->data(); memcpy(a.data(), r, size); if(del) { int newsize = from->size()-size; memmove(r, r+size, newsize); from->resize(newsize); } } return a; } void connectionClosed(); void delayedCloseFinished(); void readyRead(); void bytesWritten(int); void error(int); //! \fn void ByteStream::connectionClosed() //! This signal is emitted when the remote end of the stream closes. //! \fn void ByteStream::delayedCloseFinished() //! This signal is emitted when all pending data has been written to the stream //! after an attempt to close. //! \fn void ByteStream::readyRead() //! This signal is emitted when data is available to be read. //! \fn void ByteStream::bytesWritten(int x); //! This signal is emitted when data has been successfully written to the stream. //! \a x is the number of bytes written. //! \fn void ByteStream::error(int code) //! This signal is emitted when an error occurs in the stream. The reason for //! error is indicated by \a code. // CS_NAMESPACE_END psi-0.14/iris/src/xmpp/cutestuff/bsocket.h0000644000175000017500000000416711305557616016710 0ustar janjan/* * bsocket.h - QSocket wrapper based on Bytestream with SRV DNS support * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CS_BSOCKET_H #define CS_BSOCKET_H #include #include "bytestream.h" class QString; class QObject; class QByteArray; // CS_NAMESPACE_BEGIN class BSocket : public ByteStream { Q_OBJECT public: enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound }; enum State { Idle, HostLookup, Connecting, Connected, Closing }; BSocket(QObject *parent=0); ~BSocket(); void connectToHost(const QString &host, quint16 port); void connectToServer(const QString &srv, const QString &type); int socket() const; void setSocket(int); int state() const; // from ByteStream bool isOpen() const; void close(); void write(const QByteArray &); QByteArray read(int bytes=0); int bytesAvailable() const; int bytesToWrite() const; // local QHostAddress address() const; quint16 port() const; // remote QHostAddress peerAddress() const; quint16 peerPort() const; signals: void hostFound(); void connected(); private slots: void qs_hostFound(); void qs_connected(); void qs_closed(); void qs_readyRead(); void qs_bytesWritten(qint64); void qs_error(QAbstractSocket::SocketError); void srv_done(); void ndns_done(); void do_connect(); private: class Private; Private *d; void reset(bool clear=false); void ensureSocket(); }; // CS_NAMESPACE_END #endif psi-0.14/iris/src/xmpp/xmpp-core/0000755000175000017500000000000011305557616014777 5ustar janjanpsi-0.14/iris/src/xmpp/xmpp-core/xmpp_stream.h0000644000175000017500000000407611305557616017516 0ustar janjan/* * xmpp.h - XMPP "core" library API * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_STREAM_H #define XMPP_STREAM_H #include #include #include "xmpp_stanza.h" #include "xmpp/jid/jid.h" class QDomDocument; namespace XMPP { class Stream : public QObject { Q_OBJECT public: enum Error { ErrParse, ErrProtocol, ErrStream, ErrCustom = 10 }; enum StreamCond { GenericStreamError, Conflict, ConnectionTimeout, InternalServerError, InvalidFrom, InvalidXml, PolicyViolation, ResourceConstraint, SystemShutdown }; Stream(QObject *parent=0); virtual ~Stream(); virtual QDomDocument & doc() const=0; virtual QString baseNS() const=0; virtual bool old() const=0; virtual void close()=0; virtual bool stanzaAvailable() const=0; virtual Stanza read()=0; virtual void write(const Stanza &s)=0; virtual int errorCondition() const=0; virtual QString errorText() const=0; virtual QDomElement errorAppSpec() const=0; Stanza createStanza(Stanza::Kind k, const Jid &to="", const QString &type="", const QString &id=""); Stanza createStanza(const QDomElement &e); static QString xmlToString(const QDomElement &e, bool clip=false); signals: void connectionClosed(); void delayedCloseFinished(); void readyRead(); void stanzaWritten(); void error(int); }; } #endif psi-0.14/iris/src/xmpp/xmpp-core/xmpp_stanza.h0000644000175000017500000000613211305557616017516 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_STANZA_H #define XMPP_STANZA_H #include #include #include class QDomDocument; namespace XMPP { class Jid; class Stream; class Stanza { public: enum Kind { Message, Presence, IQ }; Stanza(); Stanza(const Stanza &from); Stanza & operator=(const Stanza &from); virtual ~Stanza(); class Error { public: enum ErrorType { Cancel = 1, Continue, Modify, Auth, Wait }; enum ErrorCond { BadRequest = 1, Conflict, FeatureNotImplemented, Forbidden, Gone, InternalServerError, ItemNotFound, JidMalformed, NotAcceptable, NotAllowed, NotAuthorized, PaymentRequired, RecipientUnavailable, Redirect, RegistrationRequired, RemoteServerNotFound, RemoteServerTimeout, ResourceConstraint, ServiceUnavailable, SubscriptionRequired, UndefinedCondition, UnexpectedRequest }; Error(int type=Cancel, int condition=UndefinedCondition, const QString &text="", const QDomElement &appSpec=QDomElement()); int type; int condition; QString text; QDomElement appSpec; int code() const; bool fromCode(int code); QPair description() const; QDomElement toXml(QDomDocument &doc, const QString &baseNS) const; bool fromXml(const QDomElement &e, const QString &baseNS); private: class Private; int originalCode; }; bool isNull() const; QDomElement element() const; QString toString() const; QDomDocument & doc() const; QString baseNS() const; QDomElement createElement(const QString &ns, const QString &tagName); QDomElement createTextElement(const QString &ns, const QString &tagName, const QString &text); void appendChild(const QDomElement &e); Kind kind() const; void setKind(Kind k); Jid to() const; Jid from() const; QString id() const; QString type() const; QString lang() const; void setTo(const Jid &j); void setFrom(const Jid &j); void setId(const QString &id); void setType(const QString &type); void setLang(const QString &lang); Error error() const; void setError(const Error &err); void clearError(); private: friend class Stream; Stanza(Stream *s, Kind k, const Jid &to, const QString &type, const QString &id); Stanza(Stream *s, const QDomElement &e); class Private; Private *d; }; } #endif psi-0.14/iris/src/xmpp/xmpp-core/xmpp_stanza.cpp0000644000175000017500000004476111305557616020063 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_stanza.h" #include #include "xmpp/jid/jid.h" #include "xmpp_stream.h" using namespace XMPP; #define NS_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" #define NS_XML "http://www.w3.org/XML/1998/namespace" //---------------------------------------------------------------------------- // Stanza::Error //---------------------------------------------------------------------------- /** \class Stanza::Error \brief Represents stanza error Stanza error consists of error type and condition. In addition, it may contain a human readable description, and application specific element. One of the usages of this class is to easily generate error XML: \code QDomElement e = createIQ(client()->doc(), "error", jid, id); Error error(Stanza::Error::Auth, Stanza::Error::NotAuthorized); e.appendChild(error.toXml(*client()->doc(), client()->stream().baseNS())); \endcode This class implements JEP-0086, which means that it can read both old and new style error elements. Also, generated XML will contain both type/condition and code. Error text in output XML is always presented in XMPP-style only. All functions will always try to guess missing information based on mappings defined in the JEP. */ /** \enum Stanza::Error::ErrorType \brief Represents error type */ /** \enum Stanza::Error::ErrorCond \brief Represents error condition */ /** \brief Constructs new error */ Stanza::Error::Error(int _type, int _condition, const QString &_text, const QDomElement &_appSpec) { type = _type; condition = _condition; text = _text; appSpec = _appSpec; originalCode = 0; } class Stanza::Error::Private { public: struct ErrorTypeEntry { const char *str; int type; }; static ErrorTypeEntry errorTypeTable[]; struct ErrorCondEntry { const char *str; int cond; }; static ErrorCondEntry errorCondTable[]; struct ErrorCodeEntry { int cond; int type; int code; }; static ErrorCodeEntry errorCodeTable[]; struct ErrorDescEntry { int cond; char *name; char *str; }; static ErrorDescEntry errorDescriptions[]; static int stringToErrorType(const QString &s) { for(int n = 0; errorTypeTable[n].str; ++n) { if(s == errorTypeTable[n].str) return errorTypeTable[n].type; } return -1; } static QString errorTypeToString(int x) { for(int n = 0; errorTypeTable[n].str; ++n) { if(x == errorTypeTable[n].type) return errorTypeTable[n].str; } return QString(); } static int stringToErrorCond(const QString &s) { for(int n = 0; errorCondTable[n].str; ++n) { if(s == errorCondTable[n].str) return errorCondTable[n].cond; } return -1; } static QString errorCondToString(int x) { for(int n = 0; errorCondTable[n].str; ++n) { if(x == errorCondTable[n].cond) return errorCondTable[n].str; } return QString(); } static int errorTypeCondToCode(int t, int c) { Q_UNUSED(t); for(int n = 0; errorCodeTable[n].cond; ++n) { if(c == errorCodeTable[n].cond) return errorCodeTable[n].code; } return 0; } static QPair errorCodeToTypeCond(int x) { for(int n = 0; errorCodeTable[n].cond; ++n) { if(x == errorCodeTable[n].code) return QPair(errorCodeTable[n].type, errorCodeTable[n].cond); } return QPair(-1, -1); } static QPair errorCondToDesc(int x) { for(int n = 0; errorDescriptions[n].str; ++n) { if(x == errorDescriptions[n].cond) return QPair(QCoreApplication::translate("Stanza::Error::Private", errorDescriptions[n].name), QCoreApplication::translate("Stanza::Error::Private", errorDescriptions[n].str)); } return QPair(); } }; Stanza::Error::Private::ErrorTypeEntry Stanza::Error::Private::errorTypeTable[] = { { "cancel", Cancel }, { "continue", Continue }, { "modify", Modify }, { "auth", Auth }, { "wait", Wait }, { 0, 0 }, }; Stanza::Error::Private::ErrorCondEntry Stanza::Error::Private::errorCondTable[] = { { "bad-request", BadRequest }, { "conflict", Conflict }, { "feature-not-implemented", FeatureNotImplemented }, { "forbidden", Forbidden }, { "gone", Gone }, { "internal-server-error", InternalServerError }, { "item-not-found", ItemNotFound }, { "jid-malformed", JidMalformed }, { "not-acceptable", NotAcceptable }, { "not-allowed", NotAllowed }, { "not-authorized", NotAuthorized }, { "payment-required", PaymentRequired }, { "recipient-unavailable", RecipientUnavailable }, { "redirect", Redirect }, { "registration-required", RegistrationRequired }, { "remote-server-not-found", RemoteServerNotFound }, { "remote-server-timeout", RemoteServerTimeout }, { "resource-constraint", ResourceConstraint }, { "service-unavailable", ServiceUnavailable }, { "subscription-required", SubscriptionRequired }, { "undefined-condition", UndefinedCondition }, { "unexpected-request", UnexpectedRequest }, { 0, 0 }, }; Stanza::Error::Private::ErrorCodeEntry Stanza::Error::Private::errorCodeTable[] = { { BadRequest, Modify, 400 }, { Conflict, Cancel, 409 }, { FeatureNotImplemented, Cancel, 501 }, { Forbidden, Auth, 403 }, { Gone, Modify, 302 }, // permanent { InternalServerError, Wait, 500 }, { ItemNotFound, Cancel, 404 }, { JidMalformed, Modify, 400 }, { NotAcceptable, Modify, 406 }, { NotAllowed, Cancel, 405 }, { NotAuthorized, Auth, 401 }, { PaymentRequired, Auth, 402 }, { RecipientUnavailable, Wait, 404 }, { Redirect, Modify, 302 }, // temporary { RegistrationRequired, Auth, 407 }, { RemoteServerNotFound, Cancel, 404 }, { RemoteServerTimeout, Wait, 504 }, { ResourceConstraint, Wait, 500 }, { ServiceUnavailable, Cancel, 503 }, { SubscriptionRequired, Auth, 407 }, { UndefinedCondition, Wait, 500 }, // Note: any type matches really { UnexpectedRequest, Wait, 400 }, { 0, 0, 0 }, }; Stanza::Error::Private::ErrorDescEntry Stanza::Error::Private::errorDescriptions[] = { { BadRequest, QT_TR_NOOP("Bad request"), QT_TR_NOOP("The sender has sent XML that is malformed or that cannot be processed.") }, { Conflict, QT_TR_NOOP("Conflict"), QT_TR_NOOP("Access cannot be granted because an existing resource or session exists with the same name or address.") }, { FeatureNotImplemented, QT_TR_NOOP("Feature not implemented"), QT_TR_NOOP("The feature requested is not implemented by the recipient or server and therefore cannot be processed.") }, { Forbidden, QT_TR_NOOP("Forbidden"), QT_TR_NOOP("The requesting entity does not possess the required permissions to perform the action.") }, { Gone, QT_TR_NOOP("Gone"), QT_TR_NOOP("The recipient or server can no longer be contacted at this address.") }, { InternalServerError, QT_TR_NOOP("Internal server error"), QT_TR_NOOP("The server could not process the stanza because of a misconfiguration or an otherwise-undefined internal server error.") }, { ItemNotFound, QT_TR_NOOP("Item not found"), QT_TR_NOOP("The addressed JID or item requested cannot be found.") }, { JidMalformed, QT_TR_NOOP("JID malformed"), QT_TR_NOOP("The sending entity has provided or communicated an XMPP address (e.g., a value of the 'to' attribute) or aspect thereof (e.g., a resource identifier) that does not adhere to the syntax defined in Addressing Scheme.") }, { NotAcceptable, QT_TR_NOOP("Not acceptable"), QT_TR_NOOP("The recipient or server understands the request but is refusing to process it because it does not meet criteria defined by the recipient or server (e.g., a local policy regarding acceptable words in messages).") }, { NotAllowed, QT_TR_NOOP("Not allowed"), QT_TR_NOOP("The recipient or server does not allow any entity to perform the action.") }, { NotAuthorized, QT_TR_NOOP("Not authorized"), QT_TR_NOOP("The sender must provide proper credentials before being allowed to perform the action, or has provided improper credentials.") }, { PaymentRequired, QT_TR_NOOP("Payment required"), QT_TR_NOOP("The requesting entity is not authorized to access the requested service because payment is required.") }, { RecipientUnavailable, QT_TR_NOOP("Recipient unavailable"), QT_TR_NOOP("The intended recipient is temporarily unavailable.") }, { Redirect, QT_TR_NOOP("Redirect"), QT_TR_NOOP("The recipient or server is redirecting requests for this information to another entity, usually temporarily.") }, { RegistrationRequired, QT_TR_NOOP("Registration required"), QT_TR_NOOP("The requesting entity is not authorized to access the requested service because registration is required.") }, { RemoteServerNotFound, QT_TR_NOOP("Remote server not found"), QT_TR_NOOP("A remote server or service specified as part or all of the JID of the intended recipient does not exist.") }, { RemoteServerTimeout, QT_TR_NOOP("Remote server timeout"), QT_TR_NOOP("A remote server or service specified as part or all of the JID of the intended recipient (or required to fulfill a request) could not be contacted within a reasonable amount of time.") }, { ResourceConstraint, QT_TR_NOOP("Resource constraint"), QT_TR_NOOP("The server or recipient lacks the system resources necessary to service the request.") }, { ServiceUnavailable, QT_TR_NOOP("Service unavailable"), QT_TR_NOOP("The server or recipient does not currently provide the requested service.") }, { SubscriptionRequired, QT_TR_NOOP("Subscription required"), QT_TR_NOOP("The requesting entity is not authorized to access the requested service because a subscription is required.") }, { UndefinedCondition, QT_TR_NOOP("Undefined condition"), QT_TR_NOOP("The error condition is not one of those defined by the other conditions in this list.") }, { UnexpectedRequest, QT_TR_NOOP("Unexpected request"), QT_TR_NOOP("The recipient or server understood the request but was not expecting it at this time (e.g., the request was out of order).") }, }; /** \brief Returns the error code If the error object was constructed with a code, this code will be returned. Otherwise, the code will be guessed. 0 means unknown code. */ int Stanza::Error::code() const { return originalCode ? originalCode : Private::errorTypeCondToCode(type, condition); } /** \brief Creates a StanzaError from \a code. The error's type and condition are guessed from the give \a code. The application-specific error element is preserved. */ bool Stanza::Error::fromCode(int code) { QPair guess = Private::errorCodeToTypeCond(code); if(guess.first == -1 || guess.second == -1) return false; type = guess.first; condition = guess.second; originalCode = code; return true; } /** \brief Reads the error from XML This function finds and reads the error element \a e. You need to provide the base namespace of the stream which this stanza belongs to (probably by using stream.baseNS() function). */ bool Stanza::Error::fromXml(const QDomElement &e, const QString &baseNS) { if(e.tagName() != "error" && e.namespaceURI() != baseNS) return false; // type type = Private::stringToErrorType(e.attribute("type")); // condition QDomNodeList nl = e.childNodes(); QDomElement t; condition = -1; int n; for(n = 0; n < nl.count(); ++n) { QDomNode i = nl.item(n); t = i.toElement(); if(!t.isNull()) { // FIX-ME: this shouldn't be needed if(t.namespaceURI() == NS_STANZAS || t.attribute("xmlns") == NS_STANZAS) { condition = Private::stringToErrorCond(t.tagName()); if (condition != -1) break; } } } // code originalCode = e.attribute("code").toInt(); // try to guess type/condition if(type == -1 || condition == -1) { QPair guess(-1, -1); if (originalCode) guess = Private::errorCodeToTypeCond(originalCode); if (type == -1) type = guess.first != -1 ? guess.first : Cancel; if (condition == -1) condition = guess.second != -1 ? guess.second : UndefinedCondition; } // text t = e.elementsByTagNameNS(NS_STANZAS, "text").item(0).toElement(); if(!t.isNull()) text = t.text().trimmed(); else text = e.text().trimmed(); // appspec: find first non-standard namespaced element appSpec = QDomElement(); nl = e.childNodes(); for(n = 0; n < nl.count(); ++n) { QDomNode i = nl.item(n); if(i.isElement() && i.namespaceURI() != NS_STANZAS) { appSpec = i.toElement(); break; } } return true; } /** \brief Writes the error to XML This function creates an error element representing the error object. You need to provide the base namespace of the stream to which this stanza belongs to (probably by using stream.baseNS() function). */ QDomElement Stanza::Error::toXml(QDomDocument &doc, const QString &baseNS) const { QDomElement errElem = doc.createElementNS(baseNS, "error"); QDomElement t; // XMPP error QString stype = Private::errorTypeToString(type); if(stype.isEmpty()) return errElem; QString scond = Private::errorCondToString(condition); if(scond.isEmpty()) return errElem; errElem.setAttribute("type", stype); errElem.appendChild(t = doc.createElementNS(NS_STANZAS, scond)); t.setAttribute("xmlns", NS_STANZAS); // FIX-ME: this shouldn't be needed // old code int scode = code(); if(scode) errElem.setAttribute("code", scode); // text if(!text.isEmpty()) { t = doc.createElementNS(NS_STANZAS, "text"); t.setAttribute("xmlns", NS_STANZAS); // FIX-ME: this shouldn't be needed t.appendChild(doc.createTextNode(text)); errElem.appendChild(t); } // application specific errElem.appendChild(appSpec); return errElem; } /** \brief Returns the error name and description Returns the error name (e.g. "Not Allowed") and generic description. */ QPair Stanza::Error::description() const { return Private::errorCondToDesc(condition); } //---------------------------------------------------------------------------- // Stanza //---------------------------------------------------------------------------- class Stanza::Private { public: static int stringToKind(const QString &s) { if(s == "message") return Message; else if(s == "presence") return Presence; else if(s == "iq") return IQ; else return -1; } static QString kindToString(Kind k) { if(k == Message) return "message"; else if(k == Presence) return "presence"; else return "iq"; } Stream *s; QDomElement e; }; Stanza::Stanza() { d = 0; } Stanza::Stanza(Stream *s, Kind k, const Jid &to, const QString &type, const QString &id) { Q_ASSERT(s); d = new Private; Kind kind; if(k == Message || k == Presence || k == IQ) kind = k; else kind = Message; d->s = s; if(d->s) d->e = d->s->doc().createElementNS(s->baseNS(), Private::kindToString(kind)); if(to.isValid()) setTo(to); if(!type.isEmpty()) setType(type); if(!id.isEmpty()) setId(id); } Stanza::Stanza(Stream *s, const QDomElement &e) { Q_ASSERT(s); d = 0; if(e.namespaceURI() != s->baseNS()) return; int x = Private::stringToKind(e.tagName()); if(x == -1) return; d = new Private; d->s = s; d->e = e; } Stanza::Stanza(const Stanza &from) { d = 0; *this = from; } Stanza & Stanza::operator=(const Stanza &from) { delete d; d = 0; if(from.d) d = new Private(*from.d); return *this; } Stanza::~Stanza() { delete d; } bool Stanza::isNull() const { return (d ? false: true); } QDomElement Stanza::element() const { return d->e; } QString Stanza::toString() const { return Stream::xmlToString(d->e); } QDomDocument & Stanza::doc() const { return d->s->doc(); } QString Stanza::baseNS() const { return d->s->baseNS(); } QDomElement Stanza::createElement(const QString &ns, const QString &tagName) { return d->s->doc().createElementNS(ns, tagName); } QDomElement Stanza::createTextElement(const QString &ns, const QString &tagName, const QString &text) { QDomElement e = d->s->doc().createElementNS(ns, tagName); e.appendChild(d->s->doc().createTextNode(text)); return e; } void Stanza::appendChild(const QDomElement &e) { d->e.appendChild(e); } Stanza::Kind Stanza::kind() const { return (Kind)Private::stringToKind(d->e.tagName()); } void Stanza::setKind(Kind k) { d->e.setTagName(Private::kindToString(k)); } Jid Stanza::to() const { return Jid(d->e.attribute("to")); } Jid Stanza::from() const { return Jid(d->e.attribute("from")); } QString Stanza::id() const { return d->e.attribute("id"); } QString Stanza::type() const { return d->e.attribute("type"); } QString Stanza::lang() const { return d->e.attributeNS(NS_XML, "lang", QString()); } void Stanza::setTo(const Jid &j) { d->e.setAttribute("to", j.full()); } void Stanza::setFrom(const Jid &j) { d->e.setAttribute("from", j.full()); } void Stanza::setId(const QString &id) { d->e.setAttribute("id", id); } void Stanza::setType(const QString &type) { d->e.setAttribute("type", type); } void Stanza::setLang(const QString &lang) { d->e.setAttribute("xml:lang", lang); } Stanza::Error Stanza::error() const { Error err; QDomElement e = d->e.elementsByTagNameNS(d->s->baseNS(), "error").item(0).toElement(); if(!e.isNull()) err.fromXml(e, d->s->baseNS()); return err; } void Stanza::setError(const Error &err) { QDomDocument doc = d->e.ownerDocument(); QDomElement errElem = err.toXml(doc, d->s->baseNS()); QDomElement oldElem = d->e.elementsByTagNameNS(d->s->baseNS(), "error").item(0).toElement(); if(oldElem.isNull()) { d->e.appendChild(errElem); } else { d->e.replaceChild(errElem, oldElem); } } void Stanza::clearError() { QDomElement errElem = d->e.elementsByTagNameNS(d->s->baseNS(), "error").item(0).toElement(); if(!errElem.isNull()) d->e.removeChild(errElem); } psi-0.14/iris/src/xmpp/xmpp-core/protocol.h0000644000175000017500000002356211305557616017021 0ustar janjan/* * protocol.h - XMPP-Core protocol state machine * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PROTOCOL_H #define PROTOCOL_H #include //Added by qt3to4: #include #include "xmlprotocol.h" #include "xmpp.h" #define NS_ETHERX "http://etherx.jabber.org/streams" #define NS_CLIENT "jabber:client" #define NS_SERVER "jabber:server" #define NS_DIALBACK "jabber:server:dialback" #define NS_STREAMS "urn:ietf:params:xml:ns:xmpp-streams" #define NS_TLS "urn:ietf:params:xml:ns:xmpp-tls" #define NS_SASL "urn:ietf:params:xml:ns:xmpp-sasl" #define NS_SESSION "urn:ietf:params:xml:ns:xmpp-session" #define NS_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" #define NS_BIND "urn:ietf:params:xml:ns:xmpp-bind" #define NS_COMPRESS_FEATURE "http://jabber.org/features/compress" #define NS_COMPRESS_PROTOCOL "http://jabber.org/protocol/compress" #define NS_HOSTS "http://barracuda.com/xmppextensions/hosts" namespace XMPP { class Version { public: Version(int maj=0, int min=0); int major, minor; }; class StreamFeatures { public: StreamFeatures(); bool tls_supported, sasl_supported, bind_supported, compress_supported; bool tls_required; QStringList sasl_mechs; QStringList compression_mechs; QStringList hosts; }; class BasicProtocol : public XmlProtocol { public: // xmpp 1.0 error conditions enum SASLCond { Aborted, IncorrectEncoding, InvalidAuthzid, InvalidMech, MechTooWeak, NotAuthorized, TemporaryAuthFailure }; enum StreamCond { BadFormat, BadNamespacePrefix, Conflict, ConnectionTimeout, HostGone, HostUnknown, ImproperAddressing, InternalServerError, InvalidFrom, InvalidId, InvalidNamespace, InvalidXml, StreamNotAuthorized, PolicyViolation, RemoteConnectionFailed, ResourceConstraint, RestrictedXml, SeeOtherHost, SystemShutdown, UndefinedCondition, UnsupportedEncoding, UnsupportedStanzaType, UnsupportedVersion, XmlNotWellFormed }; enum BindCond { BindBadRequest, BindNotAllowed, BindConflict }; // extend the XmlProtocol enums enum Need { NSASLMechs = XmlProtocol::NCustom, // need SASL mechlist NStartTLS, // need to switch on TLS layer NCompress, // need to switch on compression layer NSASLFirst, // need SASL first step NSASLNext, // need SASL next step NSASLLayer, // need to switch on SASL layer NCustom = XmlProtocol::NCustom+10 }; enum Event { EFeatures = XmlProtocol::ECustom, // breakpoint after features packet is received ESASLSuccess, // breakpoint after successful sasl auth EStanzaReady, // a stanza was received EStanzaSent, // a stanza was sent EReady, // stream is ready for stanza use ECustom = XmlProtocol::ECustom+10 }; enum Error { ErrProtocol = XmlProtocol::ErrCustom, // there was an error in the xmpp-core protocol exchange ErrStream, // , see errCond, errText, and errAppSpec for details ErrStartTLS, // server refused starttls ErrCompress, // server refused compression ErrAuth, // authorization error. errCond holds sasl condition (or numeric code for old-protocol) ErrBind, // server refused resource bind ErrCustom = XmlProtocol::ErrCustom+10 }; BasicProtocol(); ~BasicProtocol(); void reset(); // for outgoing xml QDomDocument doc; // sasl-related QString saslMech() const; QByteArray saslStep() const; void setSASLMechList(const QStringList &list); void setSASLFirst(const QString &mech, const QByteArray &step); void setSASLNext(const QByteArray &step); void setSASLAuthed(); // send / recv void sendStanza(const QDomElement &e); void sendDirect(const QString &s); void sendWhitespace(); QDomElement recvStanza(); // shutdown void shutdown(); void shutdownWithError(int cond, const QString &otherHost=""); // information QString to, from, id, lang; Version version; // error output int errCond; QString errText; QDomElement errAppSpec; QString otherHost; QByteArray spare; // filled with unprocessed data on NStartTLS and NSASLLayer bool isReady() const; enum { TypeElement, TypeStanza, TypeDirect, TypePing }; protected: static int stringToSASLCond(const QString &s); static int stringToStreamCond(const QString &s); static QString saslCondToString(int); static QString streamCondToString(int); void send(const QDomElement &e, bool clip=false); void sendStreamError(int cond, const QString &text="", const QDomElement &appSpec=QDomElement()); void sendStreamError(const QString &text); // old-style bool errorAndClose(int cond, const QString &text="", const QDomElement &appSpec=QDomElement()); bool error(int code); void delayErrorAndClose(int cond, const QString &text="", const QDomElement &appSpec=QDomElement()); void delayError(int code); // reimplemented QDomElement docElement(); void handleDocOpen(const Parser::Event &pe); bool handleError(); bool handleCloseFinished(); bool doStep(const QDomElement &e); void itemWritten(int id, int size); virtual QString defaultNamespace(); virtual QStringList extraNamespaces(); // stringlist: prefix,uri,prefix,uri, [...] virtual void handleStreamOpen(const Parser::Event &pe); virtual bool doStep2(const QDomElement &e)=0; void setReady(bool b); QString sasl_mech; QStringList sasl_mechlist; QByteArray sasl_step; bool sasl_authed; QDomElement stanzaToRecv; private: struct SASLCondEntry { const char *str; int cond; }; static SASLCondEntry saslCondTable[]; struct StreamCondEntry { const char *str; int cond; }; static StreamCondEntry streamCondTable[]; struct SendItem { QDomElement stanzaToSend; QString stringToSend; bool doWhitespace; }; QList sendList; bool doShutdown, delayedError, closeError, ready; int stanzasPending, stanzasWritten; void init(); void extractStreamError(const QDomElement &e); }; class CoreProtocol : public BasicProtocol { public: enum { NPassword = NCustom, // need password for old-mode EDBVerify = ECustom, // breakpoint after db:verify request ErrPlain = ErrCustom // server only supports plain, but allowPlain is false locally }; CoreProtocol(); ~CoreProtocol(); void reset(); void startClientOut(const Jid &jid, bool oldOnly, bool tlsActive, bool doAuth, bool doCompression); void startServerOut(const QString &to); void startDialbackOut(const QString &to, const QString &from); void startDialbackVerifyOut(const QString &to, const QString &from, const QString &id, const QString &key); void startClientIn(const QString &id); void startServerIn(const QString &id); void setLang(const QString &s); void setAllowTLS(bool b); void setAllowBind(bool b); void setAllowPlain(bool b); // old-mode const Jid& jid() const; void setPassword(const QString &s); void setFrom(const QString &s); void setDialbackKey(const QString &s); // input QString user, host; // status bool old; StreamFeatures features; QStringList hosts; //static QString xmlToString(const QDomElement &e, bool clip=false); class DBItem { public: enum { ResultRequest, ResultGrant, VerifyRequest, VerifyGrant, Validated }; int type; Jid to, from; QString key, id; bool ok; }; private: enum Step { Start, Done, SendFeatures, GetRequest, HandleTLS, GetSASLResponse, IncHandleSASLSuccess, GetFeatures, // read features packet HandleFeatures, // act on features, by initiating tls, sasl, or bind GetTLSProceed, // read tls response GetCompressProceed, // read compression response GetSASLFirst, // perform sasl first step using provided data GetSASLChallenge, // read server sasl challenge GetSASLNext, // perform sasl next step using provided data HandleSASLSuccess, // handle what must be done after reporting sasl success GetBindResponse, // read bind response HandleAuthGet, // send old-protocol auth-get GetAuthGetResponse, // read auth-get response HandleAuthSet, // send old-protocol auth-set GetAuthSetResponse // read auth-set response }; QList dbrequests, dbpending, dbvalidated; bool server, dialback, dialback_verify; int step; bool digest; bool tls_started, sasl_started, compress_started; Jid jid_; bool oldOnly; bool allowPlain; bool doTLS, doAuth, doBinding, doCompress; QString password; QString dialback_id, dialback_key; QString self_from; void init(); static int getOldErrorCode(const QDomElement &e); bool loginComplete(); bool isValidStanza(const QDomElement &e) const; bool grabPendingItem(const Jid &to, const Jid &from, int type, DBItem *item); bool normalStep(const QDomElement &e); bool dialbackStep(const QDomElement &e); // reimplemented bool stepAdvancesParser() const; bool stepRequiresElement() const; void stringSend(const QString &s); void stringRecv(const QString &s); QString defaultNamespace(); QStringList extraNamespaces(); void handleStreamOpen(const Parser::Event &pe); bool doStep2(const QDomElement &e); void elementSend(const QDomElement &e); void elementRecv(const QDomElement &e); }; } #endif psi-0.14/iris/src/xmpp/xmpp-core/xmpp.h0000644000175000017500000001213711305557616016140 0ustar janjan/* * xmpp.h - XMPP "core" library API * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_H #define XMPP_H #include #include #include #include #include #include #include #include "xmpp/jid/jid.h" #include "xmpp_stanza.h" #include "xmpp_stream.h" #include "xmpp_clientstream.h" namespace QCA { class TLS; }; #ifndef CS_XMPP class ByteStream; #endif #include // For QCA::SASL::Params namespace XMPP { // CS_IMPORT_BEGIN cutestuff/bytestream.h #ifdef CS_XMPP class ByteStream; #endif // CS_IMPORT_END class Debug { public: virtual ~Debug(); virtual void msg(const QString &)=0; virtual void outgoingTag(const QString &)=0; virtual void incomingTag(const QString &)=0; virtual void outgoingXml(const QDomElement &)=0; virtual void incomingXml(const QDomElement &)=0; }; void setDebug(Debug *); class Connector : public QObject { Q_OBJECT public: Connector(QObject *parent=0); virtual ~Connector(); virtual void connectToServer(const QString &server)=0; virtual ByteStream *stream() const=0; virtual void done()=0; bool useSSL() const; bool havePeerAddress() const; QHostAddress peerAddress() const; quint16 peerPort() const; virtual QString host() const; signals: void connected(); void error(); protected: void setUseSSL(bool b); void setPeerAddressNone(); void setPeerAddress(const QHostAddress &addr, quint16 port); private: bool ssl; bool haveaddr; QHostAddress addr; quint16 port; }; class AdvancedConnector : public Connector { Q_OBJECT public: enum Error { ErrConnectionRefused, ErrHostNotFound, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth, ErrStream }; AdvancedConnector(QObject *parent=0); virtual ~AdvancedConnector(); class Proxy { public: enum { None, HttpConnect, HttpPoll, Socks }; Proxy(); ~Proxy(); int type() const; QString host() const; quint16 port() const; QString url() const; QString user() const; QString pass() const; int pollInterval() const; void setHttpConnect(const QString &host, quint16 port); void setHttpPoll(const QString &host, quint16 port, const QString &url); void setSocks(const QString &host, quint16 port); void setUserPass(const QString &user, const QString &pass); void setPollInterval(int secs); private: int t; QString v_host, v_url; quint16 v_port; QString v_user, v_pass; int v_poll; }; void setProxy(const Proxy &proxy); void setOptHostPort(const QString &host, quint16 port); void setOptHostsPort(const QStringList &hosts, quint16 port); void setOptProbe(bool); void setOptSSL(bool); void changePollInterval(int secs); void connectToServer(const QString &server); ByteStream *stream() const; void done(); int errorCode() const; virtual QString host() const; signals: void srvLookup(const QString &server); void srvResult(bool success); void httpSyncStarted(); void httpSyncFinished(); private slots: void dns_done(); void srv_done(); void bs_connected(); void bs_error(int); void http_syncStarted(); void http_syncFinished(); void t_timeout(); private: class Private; Private *d; void cleanup(); void do_resolve(); void do_connect(); void tryNextSrv(); }; class TLSHandler : public QObject { Q_OBJECT public: TLSHandler(QObject *parent=0); virtual ~TLSHandler(); virtual void reset()=0; virtual void startClient(const QString &host)=0; virtual void write(const QByteArray &a)=0; virtual void writeIncoming(const QByteArray &a)=0; signals: void success(); void fail(); void closed(); void readyRead(const QByteArray &a); void readyReadOutgoing(const QByteArray &a, int plainBytes); }; class QCATLSHandler : public TLSHandler { Q_OBJECT public: QCATLSHandler(QCA::TLS *parent); ~QCATLSHandler(); QCA::TLS *tls() const; int tlsError() const; void setXMPPCertCheck(bool enable); bool XMPPCertCheck(); bool certMatchesHostname(); void reset(); void startClient(const QString &host); void write(const QByteArray &a); void writeIncoming(const QByteArray &a); signals: void tlsHandshaken(); public slots: void continueAfterHandshake(); private slots: void tls_handshaken(); void tls_readyRead(); void tls_readyReadOutgoing(); void tls_closed(); void tls_error(); private: class Private; Private *d; }; }; #endif psi-0.14/iris/src/xmpp/xmpp-core/td.h0000644000175000017500000000050211305557616015554 0ustar janjan#ifndef TESTDEBUG_H #define TESTDEBUG_H #include class TD { public: TD(); ~TD(); static void msg(const QString &); static void outgoingTag(const QString &); static void incomingTag(const QString &); static void outgoingXml(const QDomElement &); static void incomingXml(const QDomElement &); }; #endif psi-0.14/iris/src/xmpp/xmpp-core/tlshandler.cpp0000644000175000017500000002436311305557616017653 0ustar janjan/* * tlshandler.cpp - abstract wrapper for TLS * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp.h" #include #include "qca.h" using namespace XMPP; // FIXME: remove this code once qca cert host checking works ... using namespace QCA; #include // ip address string to binary (msb), adapted from jdns (adapted from qt) // return: size 4 = ipv4, size 16 = ipv6, size 0 = error static QByteArray ipaddr_str2bin(const QString &str) { // ipv6 if(str.contains(':')) { QStringList parts = str.split(':', QString::KeepEmptyParts); if(parts.count() < 3 || parts.count() > 8) return QByteArray(); QByteArray ipv6(16, 0); int at = 16; int fill = 9 - parts.count(); for(int n = parts.count() - 1; n >= 0; --n) { if(at <= 0) return QByteArray(); if(parts[n].isEmpty()) { if(n == parts.count() - 1) { if(!parts[n - 1].isEmpty()) return QByteArray(); ipv6[--at] = 0; ipv6[--at] = 0; } else if(n == 0) { if(!parts[n + 1].isEmpty()) return QByteArray(); ipv6[--at] = 0; ipv6[--at] = 0; } else { for(int i = 0; i < fill; ++i) { if(at <= 0) return QByteArray(); ipv6[--at] = 0; ipv6[--at] = 0; } } } else { if(parts[n].indexOf('.') == -1) { bool ok; int x = parts[n].toInt(&ok, 16); if(!ok || x < 0 || x > 0xffff) return QByteArray(); ipv6[--at] = x & 0xff; ipv6[--at] = (x >> 8) & 0xff; } else { if(n != parts.count() - 1) return QByteArray(); QByteArray buf = ipaddr_str2bin(parts[n]); if(buf.isEmpty()) return QByteArray(); ipv6[--at] = buf[3]; ipv6[--at] = buf[2]; ipv6[--at] = buf[1]; ipv6[--at] = buf[0]; --fill; } } } return ipv6; } else if(str.contains('.')) { QStringList parts = str.split('.', QString::KeepEmptyParts); if(parts.count() != 4) return QByteArray(); QByteArray out(4, 0); for(int n = 0; n < 4; ++n) { bool ok; int x = parts[n].toInt(&ok); if(!ok || x < 0 || x > 0xff) return QByteArray(); out[n] = (unsigned char)x; } return out; } else return QByteArray(); } // acedomain must be all lowercase, with no trailing dot or wildcards static bool cert_match_domain(const QString &certname, const QString &acedomain) { // KSSL strips start/end whitespace, even though such whitespace is // probably not legal anyway. (compat) QString name = certname.trimmed(); // KSSL strips trailing dot, even though the dot is probably not // legal anyway. (compat) if(name.length() > 0 && name[name.length()-1] == '.') name.truncate(name.length()-1); // after our compatibility modifications, make sure the name isn't // empty. if(name.isEmpty()) return false; // lowercase, for later performing case insensitive matching name = name.toLower(); // ensure the cert field contains valid characters only if(QRegExp("[^a-z0-9\\.\\*\\-]").indexIn(name) >= 0) return false; // hack into parts, and require at least 1 part QStringList parts_name = name.split('.', QString::KeepEmptyParts); if(parts_name.isEmpty()) return false; // KSSL checks to make sure the last two parts don't contain // wildcards. I don't know where it is written that this // should be done, but for compat sake we'll do it. if(parts_name[parts_name.count()-1].contains('*')) return false; if(parts_name.count() >= 2 && parts_name[parts_name.count()-2].contains('*')) return false; QStringList parts_compare = acedomain.split('.', QString::KeepEmptyParts); if(parts_compare.isEmpty()) return false; // don't allow empty parts foreach(const QString &s, parts_name) { if(s.isEmpty()) return false; } foreach(const QString &s, parts_compare) { if(s.isEmpty()) return false; } // RFC2818: "Names may contain the wildcard character * which is // considered to match any single domain name component or // component fragment. E.g., *.a.com matches foo.a.com but not // bar.foo.a.com. f*.com matches foo.com but not bar.com." // // This means that for the domain to match it must have the // same number of components, wildcards or not. If there are // wildcards, their scope must only be within the component // they reside in. // // First, make sure the number of parts is equal. if(parts_name.count() != parts_compare.count()) return false; // Now compare each part for(int n = 0; n < parts_name.count(); ++n) { const QString &p1 = parts_name[n]; const QString &p2 = parts_compare[n]; if(!QRegExp(p1, Qt::CaseSensitive, QRegExp::Wildcard).exactMatch(p2)) return false; } return true; } // ipaddress must be an ipv4 or ipv6 address in binary format static bool cert_match_ipaddress(const QString &certname, const QByteArray &ipaddress) { // KSSL strips start/end whitespace, even though such whitespace is // probably not legal anyway. (compat) QString name = certname.trimmed(); // KSSL accepts IPv6 in brackets, which is usually done for URIs, but // IMO sounds very strange for a certificate. We'll follow this // behavior anyway. (compat) if(name.length() >= 2 && name[0] == '[' && name[name.length()-1] == ']') name = name.mid(1, name.length() - 2); // chop off brackets // after our compatibility modifications, make sure the name isn't // empty. if(name.isEmpty()) return false; // convert to binary form QByteArray addr = ipaddr_str2bin(name); if(addr.isEmpty()) return false; // not the same? if(addr != ipaddress) return false; return true; } static bool matchesHostName(const QCA::Certificate &cert, const QString &host) { QByteArray ipaddr = ipaddr_str2bin(host); if(!ipaddr.isEmpty()) // ip address { // check iPAddress foreach(const QString &s, cert.subjectInfo().values(IPAddress)) { if(cert_match_ipaddress(s, ipaddr)) return true; } // check dNSName foreach(const QString &s, cert.subjectInfo().values(DNS)) { if(cert_match_ipaddress(s, ipaddr)) return true; } // check commonName foreach(const QString &s, cert.subjectInfo().values(CommonName)) { if(cert_match_ipaddress(s, ipaddr)) return true; } } else // domain { // lowercase QString name = host.toLower(); // ACE name = QString::fromLatin1(QUrl::toAce(name)); // don't allow wildcards in the comparison host if(name.contains('*')) return false; // strip out trailing dot if(name.length() > 0 && name[name.length()-1] == '.') name.truncate(name.length()-1); // make sure the name is not empty after our modifications if(name.isEmpty()) return false; // check dNSName foreach(const QString &s, cert.subjectInfo().values(DNS)) { if(cert_match_domain(s, name)) return true; } // check commonName foreach(const QString &s, cert.subjectInfo().values(CommonName)) { if(cert_match_domain(s, name)) return true; } } return false; } //---------------------------------------------------------------------------- // TLSHandler //---------------------------------------------------------------------------- TLSHandler::TLSHandler(QObject *parent) :QObject(parent) { } TLSHandler::~TLSHandler() { } //---------------------------------------------------------------------------- // QCATLSHandler //---------------------------------------------------------------------------- class QCATLSHandler::Private { public: QCA::TLS *tls; int state, err; QString host; bool internalHostMatch; }; QCATLSHandler::QCATLSHandler(QCA::TLS *parent) :TLSHandler(parent) { d = new Private; d->tls = parent; connect(d->tls, SIGNAL(handshaken()), SLOT(tls_handshaken())); connect(d->tls, SIGNAL(readyRead()), SLOT(tls_readyRead())); connect(d->tls, SIGNAL(readyReadOutgoing()), SLOT(tls_readyReadOutgoing())); connect(d->tls, SIGNAL(closed()), SLOT(tls_closed())); connect(d->tls, SIGNAL(error()), SLOT(tls_error())); d->state = 0; d->err = -1; d->internalHostMatch = false; } QCATLSHandler::~QCATLSHandler() { delete d; } void QCATLSHandler::setXMPPCertCheck(bool enable) { d->internalHostMatch = enable; } bool QCATLSHandler::XMPPCertCheck() { return d->internalHostMatch; } bool QCATLSHandler::certMatchesHostname() { if (!d->internalHostMatch) return false; QCA::CertificateChain peerCert = d->tls->peerCertificateChain(); if (matchesHostName(peerCert.primary(), d->host)) return true; Jid host(d->host); foreach( const QString &idOnXmppAddr, peerCert.primary().subjectInfo().values(QCA::XMPP) ) { if (host.compare(Jid(idOnXmppAddr))) return true; } return false; } QCA::TLS *QCATLSHandler::tls() const { return d->tls; } int QCATLSHandler::tlsError() const { return d->err; } void QCATLSHandler::reset() { d->tls->reset(); d->state = 0; } void QCATLSHandler::startClient(const QString &host) { d->state = 0; d->err = -1; if (d->internalHostMatch) d->host = host; d->tls->startClient(d->internalHostMatch ? QString() : host); } void QCATLSHandler::write(const QByteArray &a) { d->tls->write(a); } void QCATLSHandler::writeIncoming(const QByteArray &a) { d->tls->writeIncoming(a); } void QCATLSHandler::continueAfterHandshake() { if(d->state == 2) { d->tls->continueAfterStep(); success(); d->state = 3; } } void QCATLSHandler::tls_handshaken() { d->state = 2; tlsHandshaken(); } void QCATLSHandler::tls_readyRead() { readyRead(d->tls->read()); } void QCATLSHandler::tls_readyReadOutgoing() { int plainBytes; QByteArray buf = d->tls->readOutgoing(&plainBytes); readyReadOutgoing(buf, plainBytes); } void QCATLSHandler::tls_closed() { closed(); } void QCATLSHandler::tls_error() { d->err = d->tls->errorCode(); d->state = 0; fail(); } psi-0.14/iris/src/xmpp/xmpp-core/protocol.cpp0000644000175000017500000011341211305557616017346 0ustar janjan/* * protocol.cpp - XMPP-Core protocol state machine * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // TODO: let the app know if tls is required // require mutual auth for server out/in // report ErrProtocol if server uses wrong NS // use send() instead of writeElement() in CoreProtocol #include "protocol.h" #include #include #include #include #ifdef XMPP_TEST #include "td.h" #endif using namespace XMPP; // printArray // // This function prints out an array of bytes as latin characters, converting // non-printable bytes into hex values as necessary. Useful for displaying // QByteArrays for debugging purposes. static QString printArray(const QByteArray &a) { QString s; for(int n = 0; n < a.size(); ++n) { unsigned char c = (unsigned char)a[(int)n]; if(c < 32 || c >= 127) { QString str; str.sprintf("[%02x]", c); s += str; } else s += c; } return s; } // firstChildElement // // Get an element's first child element static QDomElement firstChildElement(const QDomElement &e) { for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { if(n.isElement()) return n.toElement(); } return QDomElement(); } //---------------------------------------------------------------------------- // Version //---------------------------------------------------------------------------- Version::Version(int maj, int min) { major = maj; minor = min; } //---------------------------------------------------------------------------- // StreamFeatures //---------------------------------------------------------------------------- StreamFeatures::StreamFeatures() { tls_supported = false; sasl_supported = false; bind_supported = false; tls_required = false; compress_supported = false; } //---------------------------------------------------------------------------- // BasicProtocol //---------------------------------------------------------------------------- BasicProtocol::SASLCondEntry BasicProtocol::saslCondTable[] = { { "aborted", Aborted }, { "incorrect-encoding", IncorrectEncoding }, { "invalid-authzid", InvalidAuthzid }, { "invalid-mechanism", InvalidMech }, { "mechanism-too-weak", MechTooWeak }, { "not-authorized", NotAuthorized }, { "temporary-auth-failure", TemporaryAuthFailure }, { 0, 0 }, }; BasicProtocol::StreamCondEntry BasicProtocol::streamCondTable[] = { { "bad-format", BadFormat }, { "bad-namespace-prefix", BadNamespacePrefix }, { "conflict", Conflict }, { "connection-timeout", ConnectionTimeout }, { "host-gone", HostGone }, { "host-unknown", HostUnknown }, { "improper-addressing", ImproperAddressing }, { "internal-server-error", InternalServerError }, { "invalid-from", InvalidFrom }, { "invalid-id", InvalidId }, { "invalid-namespace", InvalidNamespace }, { "invalid-xml", InvalidXml }, { "not-authorized", StreamNotAuthorized }, { "policy-violation", PolicyViolation }, { "remote-connection-failed", RemoteConnectionFailed }, { "resource-constraint", ResourceConstraint }, { "restricted-xml", RestrictedXml }, { "see-other-host", SeeOtherHost }, { "system-shutdown", SystemShutdown }, { "undefined-condition", UndefinedCondition }, { "unsupported-encoding", UnsupportedEncoding }, { "unsupported-stanza-type", UnsupportedStanzaType }, { "unsupported-version", UnsupportedVersion }, { "xml-not-well-formed", XmlNotWellFormed }, { 0, 0 }, }; BasicProtocol::BasicProtocol() :XmlProtocol() { init(); } BasicProtocol::~BasicProtocol() { } void BasicProtocol::init() { errCond = -1; sasl_authed = false; doShutdown = false; delayedError = false; closeError = false; ready = false; stanzasPending = 0; stanzasWritten = 0; } void BasicProtocol::reset() { XmlProtocol::reset(); init(); to = QString(); from = QString(); id = QString(); lang = QString(); version = Version(1,0); errText = QString(); errAppSpec = QDomElement(); otherHost = QString(); spare.resize(0); sasl_mech = QString(); sasl_mechlist.clear(); sasl_step.resize(0); stanzaToRecv = QDomElement(); sendList.clear(); } void BasicProtocol::sendStanza(const QDomElement &e) { SendItem i; i.stanzaToSend = e; sendList += i; } void BasicProtocol::sendDirect(const QString &s) { SendItem i; i.stringToSend = s; sendList += i; } void BasicProtocol::sendWhitespace() { SendItem i; i.doWhitespace = true; sendList += i; } QDomElement BasicProtocol::recvStanza() { QDomElement e = stanzaToRecv; stanzaToRecv = QDomElement(); return e; } void BasicProtocol::shutdown() { doShutdown = true; } void BasicProtocol::shutdownWithError(int cond, const QString &str) { otherHost = str; delayErrorAndClose(cond); } bool BasicProtocol::isReady() const { return ready; } void BasicProtocol::setReady(bool b) { ready = b; } QString BasicProtocol::saslMech() const { return sasl_mech; } QByteArray BasicProtocol::saslStep() const { return sasl_step; } void BasicProtocol::setSASLMechList(const QStringList &list) { sasl_mechlist = list; } void BasicProtocol::setSASLFirst(const QString &mech, const QByteArray &step) { sasl_mech = mech; sasl_step = step; } void BasicProtocol::setSASLNext(const QByteArray &step) { sasl_step = step; } void BasicProtocol::setSASLAuthed() { sasl_authed = true; } int BasicProtocol::stringToSASLCond(const QString &s) { for(int n = 0; saslCondTable[n].str; ++n) { if(s == saslCondTable[n].str) return saslCondTable[n].cond; } return -1; } int BasicProtocol::stringToStreamCond(const QString &s) { for(int n = 0; streamCondTable[n].str; ++n) { if(s == streamCondTable[n].str) return streamCondTable[n].cond; } return -1; } QString BasicProtocol::saslCondToString(int x) { for(int n = 0; saslCondTable[n].str; ++n) { if(x == saslCondTable[n].cond) return saslCondTable[n].str; } return QString(); } QString BasicProtocol::streamCondToString(int x) { for(int n = 0; streamCondTable[n].str; ++n) { if(x == streamCondTable[n].cond) return streamCondTable[n].str; } return QString(); } void BasicProtocol::extractStreamError(const QDomElement &e) { QString text; QDomElement appSpec; QDomElement t = firstChildElement(e); if(t.isNull() || t.namespaceURI() != NS_STREAMS) { // probably old-style error errCond = -1; errText = e.text(); } else errCond = stringToStreamCond(t.tagName()); if(errCond != -1) { if(errCond == SeeOtherHost) otherHost = t.text(); t = e.elementsByTagNameNS(NS_STREAMS, "text").item(0).toElement(); if(!t.isNull()) text = t.text(); // find first non-standard namespaced element QDomNodeList nl = e.childNodes(); for(int n = 0; n < nl.count(); ++n) { QDomNode i = nl.item(n); if(i.isElement() && i.namespaceURI() != NS_STREAMS) { appSpec = i.toElement(); break; } } errText = text; errAppSpec = appSpec; } } void BasicProtocol::send(const QDomElement &e, bool clip) { writeElement(e, TypeElement, false, clip); } void BasicProtocol::sendStreamError(int cond, const QString &text, const QDomElement &appSpec) { QDomElement se = doc.createElementNS(NS_ETHERX, "stream:error"); QDomElement err = doc.createElementNS(NS_STREAMS, streamCondToString(cond)); if(!otherHost.isEmpty()) err.appendChild(doc.createTextNode(otherHost)); se.appendChild(err); if(!text.isEmpty()) { QDomElement te = doc.createElementNS(NS_STREAMS, "text"); te.setAttributeNS(NS_XML, "xml:lang", "en"); te.appendChild(doc.createTextNode(text)); se.appendChild(te); } se.appendChild(appSpec); writeElement(se, 100, false); } void BasicProtocol::sendStreamError(const QString &text) { QDomElement se = doc.createElementNS(NS_ETHERX, "stream:error"); se.appendChild(doc.createTextNode(text)); writeElement(se, 100, false); } bool BasicProtocol::errorAndClose(int cond, const QString &text, const QDomElement &appSpec) { closeError = true; errCond = cond; errText = text; errAppSpec = appSpec; sendStreamError(cond, text, appSpec); return close(); } bool BasicProtocol::error(int code) { event = EError; errorCode = code; return true; } void BasicProtocol::delayErrorAndClose(int cond, const QString &text, const QDomElement &appSpec) { errorCode = ErrStream; errCond = cond; errText = text; errAppSpec = appSpec; delayedError = true; } void BasicProtocol::delayError(int code) { errorCode = code; delayedError = true; } QDomElement BasicProtocol::docElement() { // create the root element QDomElement e = doc.createElementNS(NS_ETHERX, "stream:stream"); QString defns = defaultNamespace(); QStringList list = extraNamespaces(); // HACK: using attributes seems to be the only way to get additional namespaces in here if(!defns.isEmpty()) e.setAttribute("xmlns", defns); for(QStringList::ConstIterator it = list.begin(); it != list.end();) { QString prefix = *(it++); QString uri = *(it++); e.setAttribute(QString("xmlns:") + prefix, uri); } // additional attributes if(!isIncoming() && !to.isEmpty()) e.setAttribute("to", to); if(isIncoming() && !from.isEmpty()) e.setAttribute("from", from); if(!id.isEmpty()) e.setAttribute("id", id); if(!lang.isEmpty()) e.setAttributeNS(NS_XML, "xml:lang", lang); if(version.major > 0 || version.minor > 0) e.setAttribute("version", QString::number(version.major) + '.' + QString::number(version.minor)); return e; } void BasicProtocol::handleDocOpen(const Parser::Event &pe) { if(isIncoming()) { if(xmlEncoding() != "UTF-8") { delayErrorAndClose(UnsupportedEncoding); return; } } if(pe.namespaceURI() == NS_ETHERX && pe.localName() == "stream") { QXmlAttributes atts = pe.atts(); // grab the version int major = 0; int minor = 0; QString verstr = atts.value("version"); if(!verstr.isEmpty()) { int n = verstr.indexOf('.'); if(n != -1) { major = verstr.mid(0, n).toInt(); minor = verstr.mid(n+1).toInt(); } else { major = verstr.toInt(); minor = 0; } } version = Version(major, minor); if(isIncoming()) { to = atts.value("to"); QString peerLang = atts.value(NS_XML, "lang"); if(!peerLang.isEmpty()) lang = peerLang; } // outgoing else { from = atts.value("from"); lang = atts.value(NS_XML, "lang"); id = atts.value("id"); } handleStreamOpen(pe); } else { if(isIncoming()) delayErrorAndClose(BadFormat); else delayError(ErrProtocol); } } bool BasicProtocol::handleError() { if(isIncoming()) return errorAndClose(XmlNotWellFormed); else return error(ErrParse); } bool BasicProtocol::handleCloseFinished() { if(closeError) { event = EError; errorCode = ErrStream; // note: errCond and friends are already set at this point } else event = EClosed; return true; } bool BasicProtocol::doStep(const QDomElement &e) { // handle pending error if(delayedError) { if(isIncoming()) return errorAndClose(errCond, errText, errAppSpec); else return error(errorCode); } // shutdown? if(doShutdown) { doShutdown = false; return close(); } if(!e.isNull()) { // check for error if(e.namespaceURI() == NS_ETHERX && e.tagName() == "error") { extractStreamError(e); return error(ErrStream); } } if(ready) { // stanzas written? if(stanzasWritten > 0) { --stanzasWritten; event = EStanzaSent; return true; } // send items? if(!sendList.isEmpty()) { SendItem i; { QList::Iterator it = sendList.begin(); i = (*it); sendList.erase(it); } // outgoing stanza? if(!i.stanzaToSend.isNull()) { ++stanzasPending; writeElement(i.stanzaToSend, TypeStanza, true); event = ESend; } // direct send? else if(!i.stringToSend.isEmpty()) { writeString(i.stringToSend, TypeDirect, true); event = ESend; } // whitespace keepalive? else if(i.doWhitespace) { writeString("\n", TypePing, false); event = ESend; } return true; } else { // if we have pending outgoing stanzas, ask for write notification if(stanzasPending) notify |= NSend; } } return doStep2(e); } void BasicProtocol::itemWritten(int id, int) { if(id == TypeStanza) { --stanzasPending; ++stanzasWritten; } } QString BasicProtocol::defaultNamespace() { // default none return QString(); } QStringList BasicProtocol::extraNamespaces() { // default none return QStringList(); } void BasicProtocol::handleStreamOpen(const Parser::Event &) { // default does nothing } //---------------------------------------------------------------------------- // CoreProtocol //---------------------------------------------------------------------------- CoreProtocol::CoreProtocol() :BasicProtocol() { init(); } CoreProtocol::~CoreProtocol() { } void CoreProtocol::init() { step = Start; // ?? server = false; dialback = false; dialback_verify = false; // settings jid_ = Jid(); password = QString(); oldOnly = false; allowPlain = false; doTLS = true; doAuth = true; doCompress = true; doBinding = true; // input user = QString(); host = QString(); // status old = false; digest = false; tls_started = false; sasl_started = false; compress_started = false; } void CoreProtocol::reset() { BasicProtocol::reset(); init(); } void CoreProtocol::startClientOut(const Jid &_jid, bool _oldOnly, bool tlsActive, bool _doAuth, bool _doCompress) { jid_ = _jid; to = _jid.domain(); oldOnly = _oldOnly; doAuth = _doAuth; doCompress = _doCompress; tls_started = tlsActive; if(oldOnly) version = Version(0,0); startConnect(); } void CoreProtocol::startServerOut(const QString &_to) { server = true; to = _to; startConnect(); } void CoreProtocol::startDialbackOut(const QString &_to, const QString &_from) { server = true; dialback = true; to = _to; self_from = _from; startConnect(); } void CoreProtocol::startDialbackVerifyOut(const QString &_to, const QString &_from, const QString &id, const QString &key) { server = true; dialback = true; dialback_verify = true; to = _to; self_from = _from; dialback_id = id; dialback_key = key; startConnect(); } void CoreProtocol::startClientIn(const QString &_id) { id = _id; startAccept(); } void CoreProtocol::startServerIn(const QString &_id) { server = true; id = _id; startAccept(); } void CoreProtocol::setLang(const QString &s) { lang = s; } void CoreProtocol::setAllowTLS(bool b) { doTLS = b; } void CoreProtocol::setAllowBind(bool b) { doBinding = b; } void CoreProtocol::setAllowPlain(bool b) { allowPlain = b; } const Jid& CoreProtocol::jid() const { return jid_; } void CoreProtocol::setPassword(const QString &s) { password = s; } void CoreProtocol::setFrom(const QString &s) { from = s; } void CoreProtocol::setDialbackKey(const QString &s) { dialback_key = s; } bool CoreProtocol::loginComplete() { setReady(true); event = EReady; step = Done; return true; } int CoreProtocol::getOldErrorCode(const QDomElement &e) { QDomElement err = e.elementsByTagNameNS(NS_CLIENT, "error").item(0).toElement(); if(err.isNull() || !err.hasAttribute("code")) return -1; return err.attribute("code").toInt(); } /*QString CoreProtocol::xmlToString(const QDomElement &e, bool clip) { // determine an appropriate 'fakeNS' to use QString ns; if(e.prefix() == "stream") ns = NS_ETHERX; else if(e.prefix() == "db") ns = NS_DIALBACK; else ns = NS_CLIENT; return ::xmlToString(e, ns, "stream:stream", clip); }*/ bool CoreProtocol::stepAdvancesParser() const { if(stepRequiresElement()) return true; else if(isReady()) return true; return false; } // all element-needing steps need to be registered here bool CoreProtocol::stepRequiresElement() const { switch(step) { case GetFeatures: case GetTLSProceed: case GetCompressProceed: case GetSASLChallenge: case GetBindResponse: case GetAuthGetResponse: case GetAuthSetResponse: case GetRequest: case GetSASLResponse: return true; } return false; } void CoreProtocol::stringSend(const QString &s) { #ifdef XMPP_TEST TD::outgoingTag(s); #endif } void CoreProtocol::stringRecv(const QString &s) { #ifdef XMPP_TEST TD::incomingTag(s); #endif } QString CoreProtocol::defaultNamespace() { if(server) return NS_SERVER; else return NS_CLIENT; } QStringList CoreProtocol::extraNamespaces() { QStringList list; if(dialback) { list += "db"; list += NS_DIALBACK; } return list; } void CoreProtocol::handleStreamOpen(const Parser::Event &pe) { if(isIncoming()) { QString ns = pe.nsprefix(); QString db; if(server) { db = pe.nsprefix("db"); if(!db.isEmpty()) dialback = true; } // verify namespace if((!server && ns != NS_CLIENT) || (server && ns != NS_SERVER) || (dialback && db != NS_DIALBACK)) { delayErrorAndClose(InvalidNamespace); return; } // verify version if(version.major < 1 && !dialback) { delayErrorAndClose(UnsupportedVersion); return; } } else { if(!dialback) { if(version.major >= 1 && !oldOnly) old = false; else old = true; } } } void CoreProtocol::elementSend(const QDomElement &e) { #ifdef XMPP_TEST TD::outgoingXml(e); #endif } void CoreProtocol::elementRecv(const QDomElement &e) { #ifdef XMPP_TEST TD::incomingXml(e); #endif } bool CoreProtocol::doStep2(const QDomElement &e) { if(dialback) return dialbackStep(e); else return normalStep(e); } bool CoreProtocol::isValidStanza(const QDomElement &e) const { QString s = e.tagName(); if(e.namespaceURI() == (server ? NS_SERVER : NS_CLIENT) && (s == "message" || s == "presence" || s == "iq")) return true; else return false; } bool CoreProtocol::grabPendingItem(const Jid &to, const Jid &from, int type, DBItem *item) { for(QList::Iterator it = dbpending.begin(); it != dbpending.end(); ++it) { const DBItem &i = *it; if(i.type == type && i.to.compare(to) && i.from.compare(from)) { const DBItem &i = (*it); *item = i; dbpending.erase(it); return true; } } return false; } bool CoreProtocol::dialbackStep(const QDomElement &e) { if(step == Start) { setReady(true); step = Done; event = EReady; return true; } if(!dbrequests.isEmpty()) { // process a request DBItem i; { QList::Iterator it = dbrequests.begin(); i = (*it); dbrequests.erase(it); } QDomElement r; if(i.type == DBItem::ResultRequest) { r = doc.createElementNS(NS_DIALBACK, "db:result"); r.setAttribute("to", i.to.full()); r.setAttribute("from", i.from.full()); r.appendChild(doc.createTextNode(i.key)); dbpending += i; } else if(i.type == DBItem::ResultGrant) { r = doc.createElementNS(NS_DIALBACK, "db:result"); r.setAttribute("to", i.to.full()); r.setAttribute("from", i.from.full()); r.setAttribute("type", i.ok ? "valid" : "invalid"); if(i.ok) { i.type = DBItem::Validated; dbvalidated += i; } else { // TODO: disconnect after writing element } } else if(i.type == DBItem::VerifyRequest) { r = doc.createElementNS(NS_DIALBACK, "db:verify"); r.setAttribute("to", i.to.full()); r.setAttribute("from", i.from.full()); r.setAttribute("id", i.id); r.appendChild(doc.createTextNode(i.key)); dbpending += i; } // VerifyGrant else { r = doc.createElementNS(NS_DIALBACK, "db:verify"); r.setAttribute("to", i.to.full()); r.setAttribute("from", i.from.full()); r.setAttribute("id", i.id); r.setAttribute("type", i.ok ? "valid" : "invalid"); } writeElement(r, TypeElement, false); event = ESend; return true; } if(!e.isNull()) { if(e.namespaceURI() == NS_DIALBACK) { if(e.tagName() == "result") { Jid to(Jid(e.attribute("to")).domain()); Jid from(Jid(e.attribute("from")).domain()); if(isIncoming()) { QString key = e.text(); // TODO: report event } else { bool ok = (e.attribute("type") == "valid") ? true: false; DBItem i; if(grabPendingItem(from, to, DBItem::ResultRequest, &i)) { if(ok) { i.type = DBItem::Validated; i.ok = true; dbvalidated += i; // TODO: report event } else { // TODO: report event } } } } else if(e.tagName() == "verify") { Jid to(Jid(e.attribute("to")).domain()); Jid from(Jid(e.attribute("from")).domain()); QString id = e.attribute("id"); if(isIncoming()) { QString key = e.text(); // TODO: report event } else { bool ok = (e.attribute("type") == "valid") ? true: false; DBItem i; if(grabPendingItem(from, to, DBItem::VerifyRequest, &i)) { if(ok) { // TODO: report event } else { // TODO: report event } } } } } else { if(isReady()) { if(isValidStanza(e)) { // TODO: disconnect if stanza is from unverified sender // TODO: ignore packets from receiving servers stanzaToRecv = e; event = EStanzaReady; return true; } } } } need = NNotify; notify |= NRecv; return false; } bool CoreProtocol::normalStep(const QDomElement &e) { if(step == Start) { if(isIncoming()) { need = NSASLMechs; step = SendFeatures; return false; } else { if(old) { if(doAuth) step = HandleAuthGet; else return loginComplete(); } else step = GetFeatures; return processStep(); } } else if(step == HandleFeatures) { // deal with TLS? if(doTLS && !tls_started && !sasl_authed && features.tls_supported) { QDomElement e = doc.createElementNS(NS_TLS, "starttls"); send(e, true); event = ESend; step = GetTLSProceed; return true; } // Should we go further ? if (!doAuth) return loginComplete(); // Deal with compression if (doCompress && !compress_started && features.compress_supported && features.compression_mechs.contains("zlib")) { QDomElement e = doc.createElementNS(NS_COMPRESS_PROTOCOL, "compress"); QDomElement m = doc.createElementNS(NS_COMPRESS_PROTOCOL, "method"); m.appendChild(doc.createTextNode("zlib")); e.appendChild(m); send(e,true); event = ESend; step = GetCompressProceed; return true; } // deal with SASL? if(!sasl_authed) { if(!features.sasl_supported) { // SASL MUST be supported //event = EError; //errorCode = ErrProtocol; //return true; // Fall back on auth for non-compliant servers step = HandleAuthGet; old = true; return true; } #ifdef XMPP_TEST TD::msg("starting SASL authentication..."); #endif need = NSASLFirst; step = GetSASLFirst; return false; } if(server) { return loginComplete(); } else { if(!doBinding) return loginComplete(); } // deal with bind if(!features.bind_supported) { // bind MUST be supported event = EError; errorCode = ErrProtocol; return true; } QDomElement e = doc.createElement("iq"); e.setAttribute("type", "set"); e.setAttribute("id", "bind_1"); QDomElement b = doc.createElementNS(NS_BIND, "bind"); // request specific resource? QString resource = jid_.resource(); if(!resource.isEmpty()) { QDomElement r = doc.createElement("resource"); r.appendChild(doc.createTextNode(jid_.resource())); b.appendChild(r); } e.appendChild(b); send(e); event = ESend; step = GetBindResponse; return true; } else if(step == GetSASLFirst) { QDomElement e = doc.createElementNS(NS_SASL, "auth"); e.setAttribute("mechanism", sasl_mech); if(!sasl_step.isEmpty()) { #ifdef XMPP_TEST TD::msg(QString("SASL OUT: [%1]").arg(printArray(sasl_step))); #endif e.appendChild(doc.createTextNode(QCA::Base64().arrayToString(sasl_step))); } send(e, true); event = ESend; step = GetSASLChallenge; return true; } else if(step == GetSASLNext) { if(isIncoming()) { if(sasl_authed) { QDomElement e = doc.createElementNS(NS_SASL, "success"); writeElement(e, TypeElement, false, true); event = ESend; step = IncHandleSASLSuccess; return true; } else { QByteArray stepData = sasl_step; QDomElement e = doc.createElementNS(NS_SASL, "challenge"); if(!stepData.isEmpty()) e.appendChild(doc.createTextNode(QCA::Base64().arrayToString(stepData))); writeElement(e, TypeElement, false, true); event = ESend; step = GetSASLResponse; return true; } } else { // already authed? then ignore last client step // (this happens if "additional data with success" // is used) if(sasl_authed) { event = ESASLSuccess; step = HandleSASLSuccess; return true; } QByteArray stepData = sasl_step; #ifdef XMPP_TEST TD::msg(QString("SASL OUT: [%1]").arg(printArray(sasl_step))); #endif QDomElement e = doc.createElementNS(NS_SASL, "response"); if(!stepData.isEmpty()) e.appendChild(doc.createTextNode(QCA::Base64().arrayToString(stepData))); send(e, true); event = ESend; step = GetSASLChallenge; return true; } } else if(step == HandleSASLSuccess) { need = NSASLLayer; spare = resetStream(); step = Start; return false; } else if(step == HandleAuthGet) { QDomElement e = doc.createElement("iq"); e.setAttribute("to", to); e.setAttribute("type", "get"); e.setAttribute("id", "auth_1"); QDomElement q = doc.createElementNS("jabber:iq:auth", "query"); QDomElement u = doc.createElement("username"); u.appendChild(doc.createTextNode(jid_.node())); q.appendChild(u); e.appendChild(q); send(e); event = ESend; step = GetAuthGetResponse; return true; } else if(step == HandleAuthSet) { QDomElement e = doc.createElement("iq"); e.setAttribute("to", to); e.setAttribute("type", "set"); e.setAttribute("id", "auth_2"); QDomElement q = doc.createElementNS("jabber:iq:auth", "query"); QDomElement u = doc.createElement("username"); u.appendChild(doc.createTextNode(jid_.node())); q.appendChild(u); QDomElement p; if(digest) { // need SHA1 here //if(!QCA::isSupported(QCA::CAP_SHA1)) // QCA::insertProvider(createProviderHash()); p = doc.createElement("digest"); QByteArray cs = id.toUtf8() + password.toUtf8(); p.appendChild(doc.createTextNode(QCA::Hash("sha1").hashToString(cs))); } else { p = doc.createElement("password"); p.appendChild(doc.createTextNode(password)); } q.appendChild(p); QDomElement r = doc.createElement("resource"); r.appendChild(doc.createTextNode(jid_.resource())); q.appendChild(r); e.appendChild(q); send(e, true); event = ESend; step = GetAuthSetResponse; return true; } // server else if(step == SendFeatures) { QDomElement f = doc.createElementNS(NS_ETHERX, "stream:features"); if(!tls_started && !sasl_authed) { // don't offer tls if we are already sasl'd QDomElement tls = doc.createElementNS(NS_TLS, "starttls"); f.appendChild(tls); } if(sasl_authed) { if(!server) { QDomElement bind = doc.createElementNS(NS_BIND, "bind"); f.appendChild(bind); } } else { QDomElement mechs = doc.createElementNS(NS_SASL, "mechanisms"); for(QStringList::ConstIterator it = sasl_mechlist.begin(); it != sasl_mechlist.end(); ++it) { QDomElement m = doc.createElement("mechanism"); m.appendChild(doc.createTextNode(*it)); mechs.appendChild(m); } f.appendChild(mechs); } writeElement(f, TypeElement, false); event = ESend; step = GetRequest; return true; } // server else if(step == HandleTLS) { tls_started = true; need = NStartTLS; spare = resetStream(); step = Start; return false; } // server else if(step == IncHandleSASLSuccess) { event = ESASLSuccess; spare = resetStream(); step = Start; printf("sasl success\n"); return true; } else if(step == GetFeatures) { // we are waiting for stream features if(e.namespaceURI() == NS_ETHERX && e.tagName() == "features") { // extract features StreamFeatures f; QDomElement s = e.elementsByTagNameNS(NS_TLS, "starttls").item(0).toElement(); if(!s.isNull()) { f.tls_supported = true; f.tls_required = s.elementsByTagNameNS(NS_TLS, "required").count() > 0; } QDomElement m = e.elementsByTagNameNS(NS_SASL, "mechanisms").item(0).toElement(); if(!m.isNull()) { f.sasl_supported = true; QDomNodeList l = m.elementsByTagNameNS(NS_SASL, "mechanism"); for(int n = 0; n < l.count(); ++n) f.sasl_mechs += l.item(n).toElement().text(); } QDomElement c = e.elementsByTagNameNS(NS_COMPRESS_FEATURE, "compression").item(0).toElement(); if(!c.isNull()) { f.compress_supported = true; QDomNodeList l = c.elementsByTagNameNS(NS_COMPRESS_FEATURE, "method"); for(int n = 0; n < l.count(); ++n) f.compression_mechs += l.item(n).toElement().text(); } QDomElement b = e.elementsByTagNameNS(NS_BIND, "bind").item(0).toElement(); if(!b.isNull()) f.bind_supported = true; QDomElement h = e.elementsByTagNameNS(NS_HOSTS, "hosts").item(0).toElement(); if(!h.isNull()) { QDomNodeList l = h.elementsByTagNameNS(NS_HOSTS, "host"); for(int n = 0; n < l.count(); ++n) f.hosts += l.item(n).toElement().text(); hosts += f.hosts; } if(f.tls_supported) { #ifdef XMPP_TEST QString s = "STARTTLS is available"; if(f.tls_required) s += " (required)"; TD::msg(s); #endif } if(f.sasl_supported) { #ifdef XMPP_TEST QString s = "SASL mechs:"; for(QStringList::ConstIterator it = f.sasl_mechs.begin(); it != f.sasl_mechs.end(); ++it) s += QString(" [%1]").arg((*it)); TD::msg(s); #endif } if(f.compress_supported) { #ifdef XMPP_TEST QString s = "Compression mechs:"; for(QStringList::ConstIterator it = f.compression_mechs.begin(); it != f.compression_mechs.end(); ++it) s += QString(" [%1]").arg((*it)); TD::msg(s); #endif } event = EFeatures; features = f; step = HandleFeatures; return true; } else { // ignore } } else if(step == GetTLSProceed) { // waiting for proceed to starttls if(e.namespaceURI() == NS_TLS) { if(e.tagName() == "proceed") { #ifdef XMPP_TEST TD::msg("Server wants us to proceed with ssl handshake"); #endif tls_started = true; need = NStartTLS; spare = resetStream(); step = Start; return false; } else if(e.tagName() == "failure") { event = EError; errorCode = ErrStartTLS; return true; } else { event = EError; errorCode = ErrProtocol; return true; } } else { // ignore } } else if(step == GetCompressProceed) { // waiting for proceed to compression if(e.namespaceURI() == NS_COMPRESS_PROTOCOL) { if(e.tagName() == "compressed") { #ifdef XMPP_TEST TD::msg("Server wants us to proceed with compression"); #endif compress_started = true; need = NCompress; spare = resetStream(); step = Start; return false; } else if(e.tagName() == "failure") { event = EError; errorCode = ErrCompress; return true; } else { event = EError; errorCode = ErrProtocol; return true; } } else { // ignore } } else if(step == GetSASLChallenge) { // waiting for sasl challenge/success/fail if(e.namespaceURI() == NS_SASL) { if(e.tagName() == "challenge") { QByteArray a = QCA::Base64().stringToArray(e.text()).toByteArray(); #ifdef XMPP_TEST TD::msg(QString("SASL IN: [%1]").arg(printArray(a))); #endif sasl_step = a; need = NSASLNext; step = GetSASLNext; return false; } else if(e.tagName() == "success") { QString str = e.text(); // "additional data with success" ? if(!str.isEmpty()) { QByteArray a = QCA::Base64().stringToArray(str).toByteArray(); sasl_step = a; sasl_authed = true; need = NSASLNext; step = GetSASLNext; return false; } sasl_authed = true; event = ESASLSuccess; step = HandleSASLSuccess; return true; } else if(e.tagName() == "failure") { QDomElement t = firstChildElement(e); if(t.isNull() || t.namespaceURI() != NS_SASL) errCond = -1; else errCond = stringToSASLCond(t.tagName()); event = EError; errorCode = ErrAuth; return true; } else { event = EError; errorCode = ErrProtocol; return true; } } } else if(step == GetBindResponse) { if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { QString type(e.attribute("type")); QString id(e.attribute("id")); if(id == "bind_1" && (type == "result" || type == "error")) { if(type == "result") { QDomElement b = e.elementsByTagNameNS(NS_BIND, "bind").item(0).toElement(); Jid j; if(!b.isNull()) { QDomElement je = e.elementsByTagName("jid").item(0).toElement(); j = je.text(); } if(!j.isValid()) { event = EError; errorCode = ErrProtocol; return true; } jid_ = j; return loginComplete(); } else { errCond = -1; QDomElement err = e.elementsByTagNameNS(NS_CLIENT, "error").item(0).toElement(); if(!err.isNull()) { // get error condition QDomNodeList nl = err.childNodes(); QDomElement t; for(int n = 0; n < nl.count(); ++n) { QDomNode i = nl.item(n); if(i.isElement()) { t = i.toElement(); break; } } if(!t.isNull() && t.namespaceURI() == NS_STANZAS) { QString cond = t.tagName(); if(cond == "not-allowed") errCond = BindNotAllowed; else if(cond == "conflict") errCond = BindConflict; } } event = EError; errorCode = ErrBind; return true; } } else { // ignore } } else { // ignore } } else if(step == GetAuthGetResponse) { // waiting for an iq if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { Jid from(e.attribute("from")); QString type(e.attribute("type")); QString id(e.attribute("id")); bool okfrom = (from.isEmpty() || from.compare(Jid(to))); if(okfrom && id == "auth_1" && (type == "result" || type == "error")) { if(type == "result") { QDomElement q = e.elementsByTagNameNS("jabber:iq:auth", "query").item(0).toElement(); if(q.isNull() || q.elementsByTagName("username").item(0).isNull() || q.elementsByTagName("resource").item(0).isNull()) { event = EError; errorCode = ErrProtocol; return true; } bool plain_supported = !q.elementsByTagName("password").item(0).isNull(); bool digest_supported = !q.elementsByTagName("digest").item(0).isNull(); if(!digest_supported && !plain_supported) { event = EError; errorCode = ErrProtocol; return true; } // plain text not allowed? if(!digest_supported && !allowPlain) { event = EError; errorCode = ErrPlain; return true; } digest = digest_supported; need = NPassword; step = HandleAuthSet; return false; } else { errCond = getOldErrorCode(e); event = EError; errorCode = ErrAuth; return true; } } else { // ignore } } else { // ignore } } else if(step == GetAuthSetResponse) { // waiting for an iq if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { Jid from(e.attribute("from")); QString type(e.attribute("type")); QString id(e.attribute("id")); bool okfrom = (from.isEmpty() || from.compare(Jid(to))); if(okfrom && id == "auth_2" && (type == "result" || type == "error")) { if(type == "result") { return loginComplete(); } else { errCond = getOldErrorCode(e); event = EError; errorCode = ErrAuth; return true; } } else { // ignore } } else { // ignore } } // server else if(step == GetRequest) { printf("get request: [%s], %s\n", e.namespaceURI().toLatin1().data(), e.tagName().toLatin1().data()); if(e.namespaceURI() == NS_TLS && e.localName() == "starttls") { // TODO: don't let this be done twice QDomElement e = doc.createElementNS(NS_TLS, "proceed"); writeElement(e, TypeElement, false, true); event = ESend; step = HandleTLS; return true; } if(e.namespaceURI() == NS_SASL) { if(e.localName() == "auth") { if(sasl_started) { // TODO printf("error\n"); return false; } sasl_started = true; sasl_mech = e.attribute("mechanism"); // TODO: if child text missing, don't pass it sasl_step = QCA::Base64().stringToArray(e.text()).toByteArray(); need = NSASLFirst; step = GetSASLNext; return false; } else { // TODO printf("unknown sasl tag\n"); return false; } } if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { QDomElement b = e.elementsByTagNameNS(NS_BIND, "bind").item(0).toElement(); if(!b.isNull()) { QDomElement res = b.elementsByTagName("resource").item(0).toElement(); QString resource = res.text(); QDomElement r = doc.createElement("iq"); r.setAttribute("type", "result"); r.setAttribute("id", e.attribute("id")); QDomElement bind = doc.createElementNS(NS_BIND, "bind"); QDomElement jid = doc.createElement("jid"); Jid j = user + '@' + host + '/' + resource; jid.appendChild(doc.createTextNode(j.full())); bind.appendChild(jid); r.appendChild(bind); writeElement(r, TypeElement, false); event = ESend; // TODO return true; } else { // TODO } } } else if(step == GetSASLResponse) { if(e.namespaceURI() == NS_SASL && e.localName() == "response") { sasl_step = QCA::Base64().stringToArray(e.text()).toByteArray(); need = NSASLNext; step = GetSASLNext; return false; } } if(isReady()) { if(!e.isNull() && isValidStanza(e)) { stanzaToRecv = e; event = EStanzaReady; setIncomingAsExternal(); return true; } } need = NNotify; notify |= NRecv; return false; } psi-0.14/iris/src/xmpp/xmpp-core/xmpp_clientstream.h0000644000175000017500000001324311305557616020711 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_CLIENTSTREAM_H #define XMPP_CLIENTSTREAM_H #include #include "xmpp_stream.h" class QByteArray; class QString; class QDomDocument; class QDomElement; class QObject; class ByteStream; class QHostAddress; namespace XMPP { class TLSHandler; class Connector; class ClientStream : public Stream { Q_OBJECT public: enum Error { ErrConnection = ErrCustom, // Connection error, ask Connector-subclass what's up ErrNeg, // Negotiation error, see condition ErrTLS, // TLS error, see condition ErrAuth, // Auth error, see condition ErrSecurityLayer, // broken SASL security layer ErrBind // Resource binding error }; enum Warning { WarnOldVersion, // server uses older XMPP/Jabber "0.9" protocol WarnNoTLS // there is no chance for TLS at this point }; enum NegCond { HostGone, // host no longer hosted HostUnknown, // unknown host RemoteConnectionFailed, // unable to connect to a required remote resource SeeOtherHost, // a 'redirect', see errorText() for other host UnsupportedVersion // unsupported XMPP version }; enum TLSCond { TLSStart, // server rejected STARTTLS TLSFail // TLS failed, ask TLSHandler-subclass what's up }; enum SecurityLayer { LayerTLS, LayerSASL }; enum AuthCond { GenericAuthError, // all-purpose "can't login" error NoMech, // No appropriate auth mech available BadProto, // Bad SASL auth protocol BadServ, // Server failed mutual auth EncryptionRequired, // can't use mech without TLS InvalidAuthzid, // bad input JID InvalidMech, // bad mechanism InvalidRealm, // bad realm MechTooWeak, // can't use mech with this authzid NotAuthorized, // bad user, bad password, bad creditials TemporaryAuthFailure // please try again later! }; enum BindCond { BindNotAllowed, // not allowed to bind a resource BindConflict // resource in-use }; enum AllowPlainType { NoAllowPlain, AllowPlain, AllowPlainOverTLS }; ClientStream(Connector *conn, TLSHandler *tlsHandler=0, QObject *parent=0); ClientStream(const QString &host, const QString &defRealm, ByteStream *bs, QCA::TLS *tls=0, QObject *parent=0); // server ~ClientStream(); Jid jid() const; void connectToServer(const Jid &jid, bool auth=true); void accept(); // server bool isActive() const; bool isAuthenticated() const; // login params void setUsername(const QString &s); void setPassword(const QString &s); void setRealm(const QString &s); void setAuthzid(const QString &s); void continueAfterParams(); // SASL information QString saslMechanism() const; int saslSSF() const; // binding void setResourceBinding(bool); // Language void setLang(const QString&); // security options (old protocol only uses the first !) void setAllowPlain(AllowPlainType); void setRequireMutualAuth(bool); void setSSFRange(int low, int high); void setOldOnly(bool); void setSASLMechanism(const QString &s); void setLocalAddr(const QHostAddress &addr, quint16 port); // Compression void setCompress(bool); // reimplemented QDomDocument & doc() const; QString baseNS() const; bool old() const; void close(); bool stanzaAvailable() const; Stanza read(); void write(const Stanza &s); int errorCondition() const; QString errorText() const; QDomElement errorAppSpec() const; // extra void writeDirect(const QString &s); void setNoopTime(int mills); // barracuda extension QStringList hosts() const; signals: void connected(); void securityLayerActivated(int); void needAuthParams(bool user, bool pass, bool realm); void authenticated(); void warning(int); void incomingXml(const QString &s); void outgoingXml(const QString &s); public slots: void continueAfterWarning(); private slots: void cr_connected(); void cr_error(); void bs_connectionClosed(); void bs_delayedCloseFinished(); void bs_error(int); // server only void ss_readyRead(); void ss_bytesWritten(int); void ss_tlsHandshaken(); void ss_tlsClosed(); void ss_error(int); void sasl_clientFirstStep(bool, const QByteArray&); void sasl_nextStep(const QByteArray &stepData); void sasl_needParams(const QCA::SASL::Params&); void sasl_authCheck(const QString &user, const QString &authzid); void sasl_authenticated(); void sasl_error(); void doNoop(); void doReadyRead(); private: class Private; Private *d; void reset(bool all=false); void processNext(); int convertedSASLCond() const; bool handleNeed(); void handleError(); void srvProcessNext(); }; } #endif psi-0.14/iris/src/xmpp/xmpp-core/compressionhandler.cpp0000644000175000017500000000326011305557616021403 0ustar janjan#include #include #include "compressionhandler.h" #include "xmpp/zlib/zlibcompressor.h" #include "xmpp/zlib/zlibdecompressor.h" CompressionHandler::CompressionHandler() : errorCode_(0) { outgoing_buffer_.open(QIODevice::ReadWrite); compressor_ = new ZLibCompressor(&outgoing_buffer_); incoming_buffer_.open(QIODevice::ReadWrite); decompressor_ = new ZLibDecompressor(&incoming_buffer_); } CompressionHandler::~CompressionHandler() { delete compressor_; delete decompressor_; } void CompressionHandler::writeIncoming(const QByteArray& a) { //qDebug("CompressionHandler::writeIncoming"); //qDebug() << QString("Incoming %1 bytes").arg(a.size()); errorCode_ = decompressor_->write(a); if (!errorCode_) QTimer::singleShot(0, this, SIGNAL(readyRead())); else QTimer::singleShot(0, this, SIGNAL(error())); } void CompressionHandler::write(const QByteArray& a) { //qDebug() << QString("CompressionHandler::write(%1)").arg(a.size()); errorCode_ = compressor_->write(a); if (!errorCode_) QTimer::singleShot(0, this, SIGNAL(readyReadOutgoing())); else QTimer::singleShot(0, this, SIGNAL(error())); } QByteArray CompressionHandler::read() { //qDebug("CompressionHandler::read"); QByteArray b = incoming_buffer_.buffer(); incoming_buffer_.buffer().clear(); incoming_buffer_.reset(); return b; } QByteArray CompressionHandler::readOutgoing(int* i) { //qDebug("CompressionHandler::readOutgoing"); //qDebug() << QString("Outgoing %1 bytes").arg(outgoing_buffer_.size()); QByteArray b = outgoing_buffer_.buffer(); outgoing_buffer_.buffer().clear(); outgoing_buffer_.reset(); *i = b.size(); return b; } int CompressionHandler::errorCode() { return errorCode_; } psi-0.14/iris/src/xmpp/xmpp-core/parser.cpp0000644000175000017500000004005211305557616017000 0ustar janjan/* * parser.cpp - parse an XMPP "document" * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* TODO: For XMPP::Parser to be "perfect", some things must be solved/changed in the Qt library: - Fix weird QDomElement::haveAttributeNS() bug (patch submitted to Trolltech on Aug 31st, 2003). - Fix weird behavior in QXmlSimpleReader of reporting endElement() when the '/' character of a self-closing tag is reached, instead of when the final '>' is reached. - Fix incremental parsing bugs in QXmlSimpleReader. At the moment, the only bug I've found is related to attribute parsing, but there might be more (search for '###' in $QTDIR/src/xml/qxml.cpp). We have workarounds for all of the above problems in the code below. - Deal with the processing instruction as an event type, so that we can feed it back to the application properly. Right now it is completely untrackable and is simply tacked into the first event's actualString. We can't easily do this because QXmlSimpleReader eats an extra byte beyond the processing instruction before reporting it. - Make QXmlInputSource capable of accepting data incrementally, to ensure proper text encoding detection and processing over a network. This is technically not a bug, as we have our own subclass below to do it, but it would be nice if Qt had this already. */ #include "parser.h" #include #include using namespace XMPP; static bool qt_bug_check = false; static bool qt_bug_have; //---------------------------------------------------------------------------- // StreamInput //---------------------------------------------------------------------------- class StreamInput : public QXmlInputSource { public: StreamInput() { dec = 0; reset(); } ~StreamInput() { delete dec; } void reset() { delete dec; dec = 0; in.resize(0); out = ""; at = 0; paused = false; mightChangeEncoding = true; checkBad = true; last = QChar(); v_encoding = ""; resetLastData(); } void resetLastData() { last_string = ""; } QString lastString() const { return last_string; } void appendData(const QByteArray &a) { int oldsize = in.size(); in.resize(oldsize + a.size()); memcpy(in.data() + oldsize, a.data(), a.size()); processBuf(); } QChar lastRead() { return last; } QChar next() { if(paused) return EndOfData; else return readNext(); } // NOTE: setting 'peek' to true allows the same char to be read again, // however this still advances the internal byte processing. QChar readNext(bool peek=false) { QChar c; if(mightChangeEncoding) c = EndOfData; else { if(out.isEmpty()) { QString s; if(!tryExtractPart(&s)) c = EndOfData; else { out = s; c = out[0]; } } else c = out[0]; if(!peek) out.remove(0, 1); } if(c == EndOfData) { #ifdef XMPP_PARSER_DEBUG printf("next() = EOD\n"); #endif } else { #ifdef XMPP_PARSER_DEBUG printf("next() = [%c]\n", c.latin1()); #endif last = c; } return c; } QByteArray unprocessed() const { QByteArray a; a.resize(in.size() - at); memcpy(a.data(), in.data() + at, a.size()); return a; } void pause(bool b) { paused = b; } bool isPaused() { return paused; } QString encoding() const { return v_encoding; } private: QTextDecoder *dec; QByteArray in; QString out; int at; bool paused; bool mightChangeEncoding; QChar last; QString v_encoding; QString last_string; bool checkBad; void processBuf() { #ifdef XMPP_PARSER_DEBUG printf("processing. size=%d, at=%d\n", in.size(), at); #endif if(!dec) { QTextCodec *codec = 0; uchar *p = (uchar *)in.data() + at; int size = in.size() - at; // do we have enough information to determine the encoding? if(size == 0) return; bool utf16 = false; if(p[0] == 0xfe || p[0] == 0xff) { // probably going to be a UTF-16 byte order mark if(size < 2) return; if((p[0] == 0xfe && p[1] == 0xff) || (p[0] == 0xff && p[1] == 0xfe)) { // ok it is UTF-16 utf16 = true; } } if(utf16) codec = QTextCodec::codecForMib(1000); // UTF-16 else codec = QTextCodec::codecForMib(106); // UTF-8 v_encoding = codec->name(); dec = codec->makeDecoder(); // for utf16, put in the byte order mark if(utf16) { out += dec->toUnicode((const char *)p, 2); at += 2; } } if(mightChangeEncoding) { while(1) { int n = out.indexOf('<'); if(n != -1) { // we need a closing bracket int n2 = out.indexOf('>', n); if(n2 != -1) { ++n2; QString h = out.mid(n, n2-n); QString enc = processXmlHeader(h); QTextCodec *codec = 0; if(!enc.isEmpty()) codec = QTextCodec::codecForName(enc.toLatin1()); // changing codecs if(codec) { v_encoding = codec->name(); delete dec; dec = codec->makeDecoder(); } mightChangeEncoding = false; out.truncate(0); at = 0; resetLastData(); break; } } QString s; if(!tryExtractPart(&s)) break; if(checkBad && checkForBadChars(s)) { // go to the parser mightChangeEncoding = false; out.truncate(0); at = 0; resetLastData(); break; } out += s; } } } QString processXmlHeader(const QString &h) { if(h.left(5) != ""); int startPos = h.indexOf("encoding"); if(startPos < endPos && startPos != -1) { QString encoding; do { startPos++; if(startPos > endPos) { return ""; } } while(h[startPos] != '"' && h[startPos] != '\''); startPos++; while(h[startPos] != '"' && h[startPos] != '\'') { encoding += h[startPos]; startPos++; if(startPos > endPos) { return ""; } } return encoding; } else return ""; } bool tryExtractPart(QString *s) { int size = in.size() - at; if(size == 0) return false; uchar *p = (uchar *)in.data() + at; QString nextChars; while(1) { nextChars = dec->toUnicode((const char *)p, 1); ++p; ++at; if(!nextChars.isEmpty()) break; if(at == (int)in.size()) return false; } last_string += nextChars; *s = nextChars; // free processed data? if(at >= 1024) { char *p = in.data(); int size = in.size() - at; memmove(p, p + at, size); in.resize(size); at = 0; } return true; } bool checkForBadChars(const QString &s) { int len = s.indexOf('<'); if(len == -1) len = s.length(); else checkBad = false; for(int n = 0; n < len; ++n) { if(!s.at(n).isSpace()) return true; } return false; } }; //---------------------------------------------------------------------------- // ParserHandler //---------------------------------------------------------------------------- namespace XMPP { class ParserHandler : public QXmlDefaultHandler { public: ParserHandler(StreamInput *_in, QDomDocument *_doc) { in = _in; doc = _doc; needMore = false; } ~ParserHandler() { while (!eventList.isEmpty()) { delete eventList.takeFirst(); } } bool startDocument() { depth = 0; return true; } bool endDocument() { return true; } bool startPrefixMapping(const QString &prefix, const QString &uri) { if(depth == 0) { nsnames += prefix; nsvalues += uri; } return true; } bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts) { if(depth == 0) { Parser::Event *e = new Parser::Event; QXmlAttributes a; for(int n = 0; n < atts.length(); ++n) { QString uri = atts.uri(n); QString ln = atts.localName(n); if(a.index(uri, ln) == -1) a.append(atts.qName(n), uri, ln, atts.value(n)); } e->setDocumentOpen(namespaceURI, localName, qName, a, nsnames, nsvalues); nsnames.clear(); nsvalues.clear(); e->setActualString(in->lastString()); in->resetLastData(); eventList.append(e); in->pause(true); } else { QDomElement e = doc->createElementNS(namespaceURI, qName); for(int n = 0; n < atts.length(); ++n) { QString uri = atts.uri(n); QString ln = atts.localName(n); bool have; if(!uri.isEmpty()) { have = e.hasAttributeNS(uri, ln); if(qt_bug_have) have = !have; } else have = e.hasAttribute(ln); if(!have) e.setAttributeNS(uri, atts.qName(n), atts.value(n)); } if(depth == 1) { elem = e; current = e; } else { current.appendChild(e); current = e; } } ++depth; return true; } bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName) { --depth; if(depth == 0) { Parser::Event *e = new Parser::Event; e->setDocumentClose(namespaceURI, localName, qName); e->setActualString(in->lastString()); in->resetLastData(); eventList.append(e); in->pause(true); } else { // done with a depth 1 element? if(depth == 1) { Parser::Event *e = new Parser::Event; e->setElement(elem); e->setActualString(in->lastString()); in->resetLastData(); eventList.append(e); in->pause(true); elem = QDomElement(); current = QDomElement(); } else current = current.parentNode().toElement(); } if(in->lastRead() == '/') checkNeedMore(); return true; } bool characters(const QString &str) { if(depth >= 1) { QString content = str; if(content.isEmpty()) return true; if(!current.isNull()) { QDomText text = doc->createTextNode(content); current.appendChild(text); } } return true; } /*bool processingInstruction(const QString &target, const QString &data) { printf("Processing: [%s], [%s]\n", target.latin1(), data.latin1()); in->resetLastData(); return true; }*/ void checkNeedMore() { // Here we will work around QXmlSimpleReader strangeness and self-closing tags. // The problem is that endElement() is called when the '/' is read, not when // the final '>' is read. This is a potential problem when obtaining unprocessed // bytes from StreamInput after this event, as the '>' character will end up // in the unprocessed chunk. To work around this, we need to advance StreamInput's // internal byte processing, but not the xml character data. This way, the '>' // will get processed and will no longer be in the unprocessed return, but // QXmlSimpleReader can still read it. To do this, we call StreamInput::readNext // with 'peek' mode. QChar c = in->readNext(true); // peek if(c == QXmlInputSource::EndOfData) { needMore = true; } else { // We'll assume the next char is a '>'. If it isn't, then // QXmlSimpleReader will deal with that problem on the next // parse. We don't need to take any action here. needMore = false; // there should have been a pending event if (!eventList.isEmpty()) { Parser::Event *e = eventList.first(); e->setActualString(e->actualString() + '>'); in->resetLastData(); } } } Parser::Event *takeEvent() { if(needMore) return 0; if(eventList.isEmpty()) return 0; Parser::Event *e = eventList.takeFirst(); in->pause(false); return e; } StreamInput *in; QDomDocument *doc; int depth; QStringList nsnames, nsvalues; QDomElement elem, current; QList eventList; bool needMore; }; }; //---------------------------------------------------------------------------- // Event //---------------------------------------------------------------------------- class Parser::Event::Private { public: int type; QString ns, ln, qn; QXmlAttributes a; QDomElement e; QString str; QStringList nsnames, nsvalues; }; Parser::Event::Event() { d = 0; } Parser::Event::Event(const Event &from) { d = 0; *this = from; } Parser::Event & Parser::Event::operator=(const Event &from) { delete d; d = 0; if(from.d) d = new Private(*from.d); return *this; } Parser::Event::~Event() { delete d; } bool Parser::Event::isNull() const { return (d ? false: true); } int Parser::Event::type() const { if(isNull()) return -1; return d->type; } QString Parser::Event::nsprefix(const QString &s) const { QStringList::ConstIterator it = d->nsnames.begin(); QStringList::ConstIterator it2 = d->nsvalues.begin(); for(; it != d->nsnames.end(); ++it) { if((*it) == s) return (*it2); ++it2; } return QString::null; } QString Parser::Event::namespaceURI() const { return d->ns; } QString Parser::Event::localName() const { return d->ln; } QString Parser::Event::qName() const { return d->qn; } QXmlAttributes Parser::Event::atts() const { return d->a; } QString Parser::Event::actualString() const { return d->str; } QDomElement Parser::Event::element() const { return d->e; } void Parser::Event::setDocumentOpen(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts, const QStringList &nsnames, const QStringList &nsvalues) { if(!d) d = new Private; d->type = DocumentOpen; d->ns = namespaceURI; d->ln = localName; d->qn = qName; d->a = atts; d->nsnames = nsnames; d->nsvalues = nsvalues; } void Parser::Event::setDocumentClose(const QString &namespaceURI, const QString &localName, const QString &qName) { if(!d) d = new Private; d->type = DocumentClose; d->ns = namespaceURI; d->ln = localName; d->qn = qName; } void Parser::Event::setElement(const QDomElement &elem) { if(!d) d = new Private; d->type = Element; d->e = elem; } void Parser::Event::setError() { if(!d) d = new Private; d->type = Error; } void Parser::Event::setActualString(const QString &str) { d->str = str; } //---------------------------------------------------------------------------- // Parser //---------------------------------------------------------------------------- class Parser::Private { public: Private() { doc = 0; in = 0; handler = 0; reader = 0; reset(); } ~Private() { reset(false); } void reset(bool create=true) { delete reader; delete handler; delete in; delete doc; if(create) { doc = new QDomDocument; in = new StreamInput; handler = new ParserHandler(in, doc); reader = new QXmlSimpleReader; reader->setContentHandler(handler); // initialize the reader in->pause(true); reader->parse(in, true); in->pause(false); } } QDomDocument *doc; StreamInput *in; ParserHandler *handler; QXmlSimpleReader *reader; }; Parser::Parser() { d = new Private; // check for evil bug in Qt <= 3.2.1 if(!qt_bug_check) { qt_bug_check = true; QDomElement e = d->doc->createElementNS("someuri", "somename"); if(e.hasAttributeNS("someuri", "somename")) qt_bug_have = true; else qt_bug_have = false; } } Parser::~Parser() { delete d; } void Parser::reset() { d->reset(); } void Parser::appendData(const QByteArray &a) { d->in->appendData(a); // if handler was waiting for more, give it a kick if(d->handler->needMore) d->handler->checkNeedMore(); } Parser::Event Parser::readNext() { Event e; if(d->handler->needMore) return e; Event *ep = d->handler->takeEvent(); if(!ep) { if(!d->reader->parseContinue()) { e.setError(); return e; } ep = d->handler->takeEvent(); if(!ep) return e; } e = *ep; delete ep; return e; } QByteArray Parser::unprocessed() const { return d->in->unprocessed(); } QString Parser::encoding() const { return d->in->encoding(); } psi-0.14/iris/src/xmpp/xmpp-core/securestream.h0000644000175000017500000000436711305557616017664 0ustar janjan/* * securestream.h - combines a ByteStream with TLS and SASL * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SECURESTREAM_H #define SECURESTREAM_H #include #include "bytestream.h" #define USE_TLSHANDLER #ifdef USE_TLSHANDLER namespace XMPP { class TLSHandler; } #endif class CompressionHandler; class SecureStream : public ByteStream { Q_OBJECT public: enum Error { ErrTLS = ErrCustom, ErrSASL }; SecureStream(ByteStream *s); ~SecureStream(); void startTLSClient(QCA::TLS *t, const QByteArray &spare=QByteArray()); void startTLSServer(QCA::TLS *t, const QByteArray &spare=QByteArray()); void setLayerCompress(const QByteArray &spare=QByteArray()); void setLayerSASL(QCA::SASL *s, const QByteArray &spare=QByteArray()); #ifdef USE_TLSHANDLER void startTLSClient(XMPP::TLSHandler *t, const QString &server, const QByteArray &spare=QByteArray()); #endif void closeTLS(); int errorCode() const; // reimplemented bool isOpen() const; void write(const QByteArray &); int bytesToWrite() const; signals: void tlsHandshaken(); void tlsClosed(); private slots: void bs_readyRead(); void bs_bytesWritten(int); void layer_tlsHandshaken(); void layer_tlsClosed(const QByteArray &); void layer_readyRead(const QByteArray &); void layer_needWrite(const QByteArray &); void layer_error(int); private: void linkLayer(QObject *); int calcPrebytes() const; void insertData(const QByteArray &a); void writeRawData(const QByteArray &a); void incomingData(const QByteArray &a); class Private; Private *d; }; #endif psi-0.14/iris/src/xmpp/xmpp-core/connector.cpp0000644000175000017500000003501511305557616017501 0ustar janjan/* * connector.cpp - establish a connection to an XMPP server * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* TODO: - Test and analyze all possible branches XMPP::AdvancedConnector is "good for now." The only real issue is that most of what it provides is just to work around the old Jabber/XMPP 0.9 connection behavior. When XMPP 1.0 has taken over the world, we can greatly simplify this class. - Sep 3rd, 2003. */ #include "xmpp.h" #include #include #include #include #include #include "safedelete.h" #include #include "ndns.h" #include "bsocket.h" #include "httpconnect.h" #include "httppoll.h" #include "socks.h" #include "srvresolver.h" //#define XMPP_DEBUG using namespace XMPP; //---------------------------------------------------------------------------- // Connector //---------------------------------------------------------------------------- Connector::Connector(QObject *parent) :QObject(parent) { setUseSSL(false); setPeerAddressNone(); } Connector::~Connector() { } bool Connector::useSSL() const { return ssl; } bool Connector::havePeerAddress() const { return haveaddr; } QHostAddress Connector::peerAddress() const { return addr; } quint16 Connector::peerPort() const { return port; } void Connector::setUseSSL(bool b) { ssl = b; } void Connector::setPeerAddressNone() { haveaddr = false; addr = QHostAddress(); port = 0; } void Connector::setPeerAddress(const QHostAddress &_addr, quint16 _port) { haveaddr = true; addr = _addr; port = _port; } QString Connector::host() const { return QString(); } //---------------------------------------------------------------------------- // AdvancedConnector::Proxy //---------------------------------------------------------------------------- AdvancedConnector::Proxy::Proxy() { t = None; v_poll = 30; } AdvancedConnector::Proxy::~Proxy() { } int AdvancedConnector::Proxy::type() const { return t; } QString AdvancedConnector::Proxy::host() const { return v_host; } quint16 AdvancedConnector::Proxy::port() const { return v_port; } QString AdvancedConnector::Proxy::url() const { return v_url; } QString AdvancedConnector::Proxy::user() const { return v_user; } QString AdvancedConnector::Proxy::pass() const { return v_pass; } int AdvancedConnector::Proxy::pollInterval() const { return v_poll; } void AdvancedConnector::Proxy::setHttpConnect(const QString &host, quint16 port) { t = HttpConnect; v_host = host; v_port = port; } void AdvancedConnector::Proxy::setHttpPoll(const QString &host, quint16 port, const QString &url) { t = HttpPoll; v_host = host; v_port = port; v_url = url; } void AdvancedConnector::Proxy::setSocks(const QString &host, quint16 port) { t = Socks; v_host = host; v_port = port; } void AdvancedConnector::Proxy::setUserPass(const QString &user, const QString &pass) { v_user = user; v_pass = pass; } void AdvancedConnector::Proxy::setPollInterval(int secs) { v_poll = secs; } //---------------------------------------------------------------------------- // AdvancedConnector //---------------------------------------------------------------------------- enum { Idle, Connecting, Connected }; class AdvancedConnector::Private { public: int mode; ByteStream *bs; NDns dns; SrvResolver srv; QString server; QStringList opt_hosts; int opt_port; bool opt_probe, opt_ssl; Proxy proxy; QStringList hostsToTry; QString host; int port; QList servers; int errorCode; QString connectHost; bool multi, using_srv; bool will_be_ssl; int probe_mode; bool aaaa; SafeDelete sd; QTimer connectTimeout; }; AdvancedConnector::AdvancedConnector(QObject *parent) :Connector(parent) { d = new Private; d->bs = 0; connect(&d->dns, SIGNAL(resultsReady()), SLOT(dns_done())); connect(&d->srv, SIGNAL(resultsReady()), SLOT(srv_done())); connect(&d->connectTimeout, SIGNAL(timeout()), SLOT(t_timeout())); d->connectTimeout.setSingleShot(true); d->opt_probe = false; d->opt_ssl = false; cleanup(); d->errorCode = 0; } AdvancedConnector::~AdvancedConnector() { cleanup(); delete d; } void AdvancedConnector::cleanup() { d->mode = Idle; // stop any dns if(d->dns.isBusy()) d->dns.stop(); if(d->srv.isBusy()) d->srv.stop(); // destroy the bytestream, if there is one delete d->bs; d->bs = 0; d->multi = false; d->using_srv = false; d->will_be_ssl = false; d->probe_mode = -1; setUseSSL(false); setPeerAddressNone(); } void AdvancedConnector::setProxy(const Proxy &proxy) { if(d->mode != Idle) return; d->proxy = proxy; } void AdvancedConnector::setOptHostPort(const QString &host, quint16 _port) { if(d->mode != Idle) return; // empty host means disable explicit host support if(host.isEmpty()) { d->opt_hosts.clear(); return; } d->opt_hosts = QStringList() << host; d->opt_port = _port; } void AdvancedConnector::setOptHostsPort(const QStringList &_hosts, quint16 _port) { if(d->mode != Idle) return; d->opt_hosts = _hosts; d->opt_port = _port; } void AdvancedConnector::setOptProbe(bool b) { if(d->mode != Idle) return; d->opt_probe = b; } void AdvancedConnector::setOptSSL(bool b) { if(d->mode != Idle) return; d->opt_ssl = b; } void AdvancedConnector::connectToServer(const QString &server) { if(d->mode != Idle) return; if(server.isEmpty()) return; d->hostsToTry.clear(); d->errorCode = 0; d->mode = Connecting; d->aaaa = true; d->connectHost.clear(); // Encode the servername d->server = QUrl::toAce(server); //char* server_encoded; //if (!idna_to_ascii_8z(server.utf8().data(), &server_encoded, 0)) { // d->server = QString(server_encoded); // free(server_encoded); //} //else { // d->server = server; //} if(d->proxy.type() == Proxy::HttpPoll) { // need SHA1 here //if(!QCA::isSupported(QCA::CAP_SHA1)) // QCA::insertProvider(createProviderHash()); HttpPoll *s = new HttpPoll; d->bs = s; connect(s, SIGNAL(connected()), SLOT(bs_connected())); connect(s, SIGNAL(syncStarted()), SLOT(http_syncStarted())); connect(s, SIGNAL(syncFinished()), SLOT(http_syncFinished())); connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); if(!d->proxy.user().isEmpty()) s->setAuth(d->proxy.user(), d->proxy.pass()); s->setPollInterval(d->proxy.pollInterval()); if(d->proxy.host().isEmpty()) s->connectToUrl(d->proxy.url()); else s->connectToHost(d->proxy.host(), d->proxy.port(), d->proxy.url()); } else if (d->proxy.type() == Proxy::HttpConnect) { if(!d->opt_hosts.isEmpty()) { d->hostsToTry = d->opt_hosts; d->host = d->hostsToTry.takeFirst(); d->port = d->opt_port; } else { d->host = server; d->port = 5222; } do_connect(); } else { if(!d->opt_hosts.isEmpty()) { d->hostsToTry = d->opt_hosts; d->host = d->hostsToTry.takeFirst(); d->port = d->opt_port; do_resolve(); } else { d->multi = true; QPointer self = this; srvLookup(d->server); if(!self) return; d->srv.resolveSrvOnly(d->server, "xmpp-client", "tcp"); } } } void AdvancedConnector::changePollInterval(int secs) { if(d->bs && (d->bs->inherits("XMPP::HttpPoll") || d->bs->inherits("HttpPoll"))) { HttpPoll *s = static_cast(d->bs); s->setPollInterval(secs); } } ByteStream *AdvancedConnector::stream() const { if(d->mode == Connected) return d->bs; else return 0; } void AdvancedConnector::done() { cleanup(); } int AdvancedConnector::errorCode() const { return d->errorCode; } void AdvancedConnector::do_resolve() { d->dns.resolve(d->host); } void AdvancedConnector::dns_done() { bool failed = false; QHostAddress addr; if(d->dns.result().isNull ()) failed = true; else addr = QHostAddress(d->dns.result()); if(failed) { #ifdef XMPP_DEBUG printf("dns1\n"); #endif // using proxy? then try the unresolved host through the proxy if(d->proxy.type() != Proxy::None) { #ifdef XMPP_DEBUG printf("dns1.1\n"); #endif do_connect(); } else if(d->using_srv) { #ifdef XMPP_DEBUG printf("dns1.2\n"); #endif if(d->servers.isEmpty()) { #ifdef XMPP_DEBUG printf("dns1.2.1\n"); #endif cleanup(); d->errorCode = ErrConnectionRefused; error(); } else { #ifdef XMPP_DEBUG printf("dns1.2.2\n"); #endif tryNextSrv(); return; } } else { #ifdef XMPP_DEBUG printf("dns1.3\n"); #endif if(!d->hostsToTry.isEmpty()) { d->aaaa = true; d->host = d->hostsToTry.takeFirst(); do_resolve(); return; } cleanup(); d->errorCode = ErrHostNotFound; error(); } } else { #ifdef XMPP_DEBUG printf("dns2\n"); #endif d->connectHost = d->host; d->host = addr.toString(); do_connect(); } } void AdvancedConnector::do_connect() { // 5 seconds to connect d->connectTimeout.start(5000); #ifdef XMPP_DEBUG printf("trying %s:%d\n", d->host.latin1(), d->port); #endif int t = d->proxy.type(); if(t == Proxy::None) { #ifdef XMPP_DEBUG printf("do_connect1\n"); #endif BSocket *s = new BSocket; d->bs = s; connect(s, SIGNAL(connected()), SLOT(bs_connected())); connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); s->connectToHost(d->host, d->port); } else if(t == Proxy::HttpConnect) { #ifdef XMPP_DEBUG printf("do_connect2\n"); #endif HttpConnect *s = new HttpConnect; d->bs = s; connect(s, SIGNAL(connected()), SLOT(bs_connected())); connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); if(!d->proxy.user().isEmpty()) s->setAuth(d->proxy.user(), d->proxy.pass()); s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port); } else if(t == Proxy::Socks) { #ifdef XMPP_DEBUG printf("do_connect3\n"); #endif SocksClient *s = new SocksClient; d->bs = s; connect(s, SIGNAL(connected()), SLOT(bs_connected())); connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); if(!d->proxy.user().isEmpty()) s->setAuth(d->proxy.user(), d->proxy.pass()); s->connectToHost(d->proxy.host(), d->proxy.port(), d->host, d->port); } } void AdvancedConnector::tryNextSrv() { #ifdef XMPP_DEBUG printf("trying next srv\n"); #endif Q_ASSERT(!d->servers.isEmpty()); d->host = d->servers.first().name; d->port = d->servers.first().port; d->servers.takeFirst(); do_resolve(); } void AdvancedConnector::srv_done() { QPointer self = this; #ifdef XMPP_DEBUG printf("srv_done1\n"); #endif d->servers = d->srv.servers(); if(d->servers.isEmpty()) { srvResult(false); if(!self) return; #ifdef XMPP_DEBUG printf("srv_done1.1\n"); #endif // fall back to A record d->using_srv = false; d->host = d->server; if(d->opt_probe) { #ifdef XMPP_DEBUG printf("srv_done1.1.1\n"); #endif d->probe_mode = 0; d->port = 5223; d->will_be_ssl = true; } else { #ifdef XMPP_DEBUG printf("srv_done1.1.2\n"); #endif d->probe_mode = 1; d->port = 5222; } do_resolve(); return; } srvResult(true); if(!self) return; d->using_srv = true; tryNextSrv(); } void AdvancedConnector::bs_connected() { d->connectTimeout.stop(); if(d->proxy.type() == Proxy::None) { QHostAddress h = (static_cast(d->bs))->peerAddress(); int p = (static_cast(d->bs))->peerPort(); setPeerAddress(h, p); } // only allow ssl override if proxy==poll or host:port if((d->proxy.type() == Proxy::HttpPoll || !d->opt_hosts.isEmpty()) && d->opt_ssl) setUseSSL(true); else if(d->will_be_ssl) setUseSSL(true); d->mode = Connected; connected(); } void AdvancedConnector::bs_error(int x) { if(d->mode == Connected) { d->errorCode = ErrStream; error(); return; } bool proxyError = false; int err = ErrConnectionRefused; int t = d->proxy.type(); #ifdef XMPP_DEBUG printf("bse1\n"); #endif // figure out the error if(t == Proxy::None) { if(x == BSocket::ErrHostNotFound) err = ErrHostNotFound; else err = ErrConnectionRefused; } else if(t == Proxy::HttpConnect) { if(x == HttpConnect::ErrConnectionRefused) err = ErrConnectionRefused; else if(x == HttpConnect::ErrHostNotFound) err = ErrHostNotFound; else { proxyError = true; if(x == HttpConnect::ErrProxyAuth) err = ErrProxyAuth; else if(x == HttpConnect::ErrProxyNeg) err = ErrProxyNeg; else err = ErrProxyConnect; } } else if(t == Proxy::HttpPoll) { if(x == HttpPoll::ErrConnectionRefused) err = ErrConnectionRefused; else if(x == HttpPoll::ErrHostNotFound) err = ErrHostNotFound; else { proxyError = true; if(x == HttpPoll::ErrProxyAuth) err = ErrProxyAuth; else if(x == HttpPoll::ErrProxyNeg) err = ErrProxyNeg; else err = ErrProxyConnect; } } else if(t == Proxy::Socks) { if(x == SocksClient::ErrConnectionRefused) err = ErrConnectionRefused; else if(x == SocksClient::ErrHostNotFound) err = ErrHostNotFound; else { proxyError = true; if(x == SocksClient::ErrProxyAuth) err = ErrProxyAuth; else if(x == SocksClient::ErrProxyNeg) err = ErrProxyNeg; else err = ErrProxyConnect; } } // try next host, if any if(!d->hostsToTry.isEmpty()) { d->aaaa = true; d->host = d->hostsToTry.takeFirst(); do_resolve(); return; } // no-multi or proxy error means we quit if(!d->multi || proxyError) { cleanup(); d->errorCode = err; error(); return; } if(d->using_srv && !d->servers.isEmpty()) { #ifdef XMPP_DEBUG printf("bse1.1\n"); #endif tryNextSrv(); } else if(!d->using_srv && d->opt_probe && d->probe_mode == 0) { #ifdef XMPP_DEBUG printf("bse1.2\n"); #endif d->probe_mode = 1; d->port = 5222; d->will_be_ssl = false; do_connect(); } else { #ifdef XMPP_DEBUG printf("bse1.3\n"); #endif cleanup(); d->errorCode = ErrConnectionRefused; error(); } } void AdvancedConnector::http_syncStarted() { httpSyncStarted(); } void AdvancedConnector::http_syncFinished() { httpSyncFinished(); } void AdvancedConnector::t_timeout() { // skip to next host, if there is one if(!d->hostsToTry.isEmpty()) { delete d->bs; d->bs = 0; d->aaaa = true; d->host = d->hostsToTry.takeFirst(); do_resolve(); } } QString AdvancedConnector::host() const { return d->connectHost; } psi-0.14/iris/src/xmpp/xmpp-core/simplesasl.cpp0000644000175000017500000002051611305557616017663 0ustar janjan/* * simplesasl.cpp - Simple SASL implementation * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "simplesasl.h" #include #include #include #include #include #include #include #include #include "xmpp/sasl/plainmessage.h" #include "xmpp/sasl/digestmd5response.h" #include "xmpp/base/randrandomnumbergenerator.h" namespace XMPP { class SimpleSASLContext : public QCA::SASLContext { public: class ParamsMutable { public: /** User is held */ bool user; /** Authorization ID is held */ bool authzid; /** Password is held */ bool pass; /** Realm is held */ bool realm; }; // core props QString service, host; // state int step; bool capable; bool allow_plain; QByteArray out_buf, in_buf; QString mechanism_; QString out_mech; ParamsMutable need; ParamsMutable have; QString user, authz, realm; QCA::SecureArray pass; Result result_; QCA::SASL::AuthCondition authCondition_; QByteArray result_to_net_, result_to_app_; int encoded_; SimpleSASLContext(QCA::Provider* p) : QCA::SASLContext(p) { reset(); } ~SimpleSASLContext() { reset(); } void reset() { resetState(); capable = true; allow_plain = false; need.user = false; need.authzid = false; need.pass = false; need.realm = false; have.user = false; have.authzid = false; have.pass = false; have.realm = false; user = QString(); authz = QString(); pass = QCA::SecureArray(); realm = QString(); } void resetState() { out_mech = QString(); out_buf.resize(0); authCondition_ = QCA::SASL::AuthFail; } virtual void setConstraints(QCA::SASL::AuthFlags flags, int ssfMin, int) { if(flags & (QCA::SASL::RequireForwardSecrecy | QCA::SASL::RequirePassCredentials | QCA::SASL::RequireMutualAuth) || ssfMin > 0) capable = false; else capable = true; allow_plain = flags & QCA::SASL::AllowPlain; } virtual void setup(const QString& _service, const QString& _host, const QCA::SASLContext::HostPort*, const QCA::SASLContext::HostPort*, const QString&, int) { service = _service; host = _host; } virtual void startClient(const QStringList &mechlist, bool allowClientSendFirst) { Q_UNUSED(allowClientSendFirst); mechanism_ = QString(); foreach(QString mech, mechlist) { if (mech == "DIGEST-MD5") { mechanism_ = "DIGEST-MD5"; break; } if (mech == "PLAIN" && allow_plain) mechanism_ = "PLAIN"; } if(!capable || mechanism_.isEmpty()) { result_ = Error; authCondition_ = QCA::SASL::NoMechanism; if (!capable) qWarning("simplesasl.cpp: Not enough capabilities"); if (mechanism_.isEmpty()) qWarning("simplesasl.cpp: No mechanism available"); QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); return; } resetState(); result_ = Continue; step = 0; tryAgain(); } virtual void nextStep(const QByteArray &from_net) { in_buf = from_net; tryAgain(); } virtual void tryAgain() { // All exits of the method must emit the ready signal // so all exits go through a goto ready; if(step == 0) { out_mech = mechanism_; // PLAIN if (out_mech == "PLAIN") { // First, check if we have everything if(need.user || need.pass) { qWarning("simplesasl.cpp: Did not receive necessary auth parameters"); result_ = Error; goto ready; } if(!have.user) need.user = true; if(!have.pass) need.pass = true; if(need.user || need.pass) { result_ = Params; goto ready; } out_buf = PLAINMessage(authz, user, pass.toByteArray()).getValue(); } ++step; if (out_mech == "PLAIN") result_ = Success; else result_ = Continue; } else if(step == 1) { Q_ASSERT(out_mech != "PLAIN"); // if we still need params, then the app has failed us! if(need.user || need.authzid || need.pass || need.realm) { qWarning("simplesasl.cpp: Did not receive necessary auth parameters"); result_ = Error; goto ready; } // see if some params are needed if(!have.user) need.user = true; //if(!have.authzid) // need.authzid = true; if(!have.pass) need.pass = true; if(need.user || need.authzid || need.pass) { result_ = Params; goto ready; } DIGESTMD5Response response(in_buf, service, host, realm, user, authz, pass.toByteArray(), RandRandomNumberGenerator()); if (!response.isValid()) { authCondition_ = QCA::SASL::BadProtocol; result_ = Error; goto ready; } out_buf = response.getValue(); ++step; result_ = Continue; } /*else if (step == 2) { //Commenting this out is Justin's fix for updated QCA. out_buf.resize(0); result_ = Continue; ++step; }*/ else { out_buf.resize(0); result_ = Success; } ready: QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); } virtual void update(const QByteArray &from_net, const QByteArray &from_app) { result_to_app_ = from_net; result_to_net_ = from_app; encoded_ = from_app.size(); result_ = Success; QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); } virtual bool waitForResultsReady(int msecs) { // TODO: for now, all operations block anyway Q_UNUSED(msecs); return true; } virtual Result result() const { return result_; } virtual QStringList mechlist() const { return QStringList(); } virtual QString mech() const { return out_mech; } virtual bool haveClientInit() const { return out_mech == "PLAIN"; } virtual QByteArray stepData() const { return out_buf; } virtual QByteArray to_net() { return result_to_net_; } virtual int encoded() const { return encoded_; } virtual QByteArray to_app() { return result_to_app_; } virtual int ssf() const { return 0; } virtual QCA::SASL::AuthCondition authCondition() const { return authCondition_; } virtual QCA::SASL::Params clientParams() const { return QCA::SASL::Params(need.user, need.authzid, need.pass, need.realm); } virtual void setClientParams(const QString *_user, const QString *_authzid, const QCA::SecureArray *_pass, const QString *_realm) { if(_user) { user = *_user; need.user = false; have.user = true; } if(_authzid) { authz = *_authzid; need.authzid = false; have.authzid = true; } if(_pass) { pass = *_pass; need.pass = false; have.pass = true; } if(_realm) { realm = *_realm; need.realm = false; have.realm = true; } } virtual QStringList realmlist() const { // TODO return QStringList(); } virtual QString username() const { return QString(); } virtual QString authzid() const { return QString(); } virtual QCA::Provider::Context* clone() const { SimpleSASLContext* s = new SimpleSASLContext(provider()); // TODO: Copy all the members return s; } virtual void startServer(const QString &, bool) { result_ = QCA::SASLContext::Error; QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); } virtual void serverFirstStep(const QString &, const QByteArray *) { result_ = QCA::SASLContext::Error; QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); } }; class QCASimpleSASL : public QCA::Provider { public: QCASimpleSASL() {} ~QCASimpleSASL() {} void init() { } QString name() const { return "simplesasl"; } QStringList features() const { return QStringList("sasl"); } QCA::Provider::Context* createContext(const QString& cap) { if(cap == "sasl") return new SimpleSASLContext(this); return 0; } int qcaVersion() const { return QCA_VERSION; } }; QCA::Provider *createProviderSimpleSASL() { return (new QCASimpleSASL); } } psi-0.14/iris/src/xmpp/xmpp-core/compressionhandler.h0000644000175000017500000000115411305557616021050 0ustar janjan#ifndef COMPRESSIONHANDLER_H #define COMPRESSIONHANDLER_H #include #include class ZLibCompressor; class ZLibDecompressor; class CompressionHandler : public QObject { Q_OBJECT public: CompressionHandler(); ~CompressionHandler(); void writeIncoming(const QByteArray& a); void write(const QByteArray& a); QByteArray read(); QByteArray readOutgoing(int*); int errorCode(); signals: void readyRead(); void readyReadOutgoing(); void error(); private: ZLibCompressor* compressor_; ZLibDecompressor* decompressor_; QBuffer outgoing_buffer_, incoming_buffer_; int errorCode_; }; #endif psi-0.14/iris/src/xmpp/xmpp-core/parser.h0000644000175000017500000000421011305557616016441 0ustar janjan/* * parser.h - parse an XMPP "document" * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef PARSER_H #define PARSER_H #include #include namespace XMPP { class Parser { public: Parser(); ~Parser(); class Event { public: enum Type { DocumentOpen, DocumentClose, Element, Error }; Event(); Event(const Event &); Event & operator=(const Event &); ~Event(); bool isNull() const; int type() const; // for document open QString nsprefix(const QString &s=QString::null) const; // for document open / close QString namespaceURI() const; QString localName() const; QString qName() const; QXmlAttributes atts() const; // for element QDomElement element() const; // for any QString actualString() const; // setup void setDocumentOpen(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts, const QStringList &nsnames, const QStringList &nsvalues); void setDocumentClose(const QString &namespaceURI, const QString &localName, const QString &qName); void setElement(const QDomElement &elem); void setError(); void setActualString(const QString &); private: class Private; Private *d; }; void reset(); void appendData(const QByteArray &a); Event readNext(); QByteArray unprocessed() const; QString encoding() const; private: class Private; Private *d; }; } #endif psi-0.14/iris/src/xmpp/xmpp-core/stream.cpp0000644000175000017500000007574311305557616017016 0ustar janjan/* * stream.cpp - handles a client stream * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* Notes: - For Non-SASL auth (JEP-0078), username and resource fields are required. TODO: - sasl needParams is totally jacked? PLAIN requires authzid, etc - server error handling - reply with protocol errors if the client send something wrong - don't necessarily disconnect on protocol error. prepare for more. - server function - deal with stream 'to' attribute dynamically - flag tls/sasl/binding support dynamically (have the ability to specify extra stream:features) - inform the caller about the user authentication information - sasl security settings - resource-binding interaction - timeouts - allow exchanges of non-standard stanzas - send even if we close prematurely? - ensure ClientStream and child classes are fully deletable after signals - xml:lang in root () element - sasl external - sasl anonymous */ #include "xmpp.h" #include #include #include #include #include #include #include "bytestream.h" #include #include #include "simplesasl.h" #include "securestream.h" #include "protocol.h" #ifdef XMPP_TEST #include "td.h" #endif //#define XMPP_DEBUG using namespace XMPP; static Debug *debug_ptr = 0; void XMPP::setDebug(Debug *p) { debug_ptr = p; } static QByteArray randomArray(int size) { QByteArray a; a.resize(size); for(int n = 0; n < size; ++n) a[n] = (char)(256.0*rand()/(RAND_MAX+1.0)); return a; } static QString genId() { // need SHA1 here //if(!QCA::isSupported(QCA::CAP_SHA1)) // QCA::insertProvider(createProviderHash()); return QCA::Hash("sha1").hashToString(randomArray(128)); } //---------------------------------------------------------------------------- // Stream //---------------------------------------------------------------------------- static XmlProtocol *foo = 0; Stream::Stream(QObject *parent) :QObject(parent) { } Stream::~Stream() { } Stanza Stream::createStanza(Stanza::Kind k, const Jid &to, const QString &type, const QString &id) { return Stanza(this, k, to, type, id); } Stanza Stream::createStanza(const QDomElement &e) { return Stanza(this, e); } QString Stream::xmlToString(const QDomElement &e, bool clip) { if(!foo) foo = new CoreProtocol; return foo->elementToString(e, clip); } //---------------------------------------------------------------------------- // ClientStream //---------------------------------------------------------------------------- enum { Idle, Connecting, WaitVersion, WaitTLS, NeedParams, Active, Closing }; enum { Client, Server }; class ClientStream::Private { public: Private() { conn = 0; bs = 0; ss = 0; tlsHandler = 0; tls = 0; sasl = 0; oldOnly = false; allowPlain = NoAllowPlain; mutualAuth = false; haveLocalAddr = false; minimumSSF = 0; maximumSSF = 0; doBinding = true; lang = ""; in_rrsig = false; reset(); } void reset() { state = Idle; notify = 0; newStanzas = false; sasl_ssf = 0; tls_warned = false; using_tls = false; } Jid jid; QString server; bool oldOnly; bool mutualAuth; AllowPlainType allowPlain; bool haveLocalAddr; QHostAddress localAddr; quint16 localPort; QString connectHost; int minimumSSF, maximumSSF; QString sasl_mech; bool doBinding; bool in_rrsig; Connector *conn; ByteStream *bs; TLSHandler *tlsHandler; QCA::TLS *tls; QCA::SASL *sasl; SecureStream *ss; CoreProtocol client; CoreProtocol srv; QString lang; QString defRealm; int mode; int state; int notify; bool newStanzas; int sasl_ssf; bool tls_warned, using_tls; bool doAuth; bool doCompress; QStringList sasl_mechlist; int errCond; QString errText; QDomElement errAppSpec; QList in; QTimer noopTimer; int noop_time; }; ClientStream::ClientStream(Connector *conn, TLSHandler *tlsHandler, QObject *parent) :Stream(parent) { d = new Private; d->mode = Client; d->conn = conn; connect(d->conn, SIGNAL(connected()), SLOT(cr_connected())); connect(d->conn, SIGNAL(error()), SLOT(cr_error())); d->noop_time = 0; connect(&d->noopTimer, SIGNAL(timeout()), SLOT(doNoop())); d->tlsHandler = tlsHandler; } ClientStream::ClientStream(const QString &host, const QString &defRealm, ByteStream *bs, QCA::TLS *tls, QObject *parent) :Stream(parent) { d = new Private; d->mode = Server; d->bs = bs; connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed())); connect(d->bs, SIGNAL(delayedCloseFinished()), SLOT(bs_delayedCloseFinished())); connect(d->bs, SIGNAL(error(int)), SLOT(bs_error(int))); QByteArray spare = d->bs->read(); d->ss = new SecureStream(d->bs); connect(d->ss, SIGNAL(readyRead()), SLOT(ss_readyRead())); connect(d->ss, SIGNAL(bytesWritten(int)), SLOT(ss_bytesWritten(int))); connect(d->ss, SIGNAL(tlsHandshaken()), SLOT(ss_tlsHandshaken())); connect(d->ss, SIGNAL(tlsClosed()), SLOT(ss_tlsClosed())); connect(d->ss, SIGNAL(error(int)), SLOT(ss_error(int))); d->server = host; d->defRealm = defRealm; d->tls = tls; d->srv.startClientIn(genId()); //d->srv.startServerIn(genId()); //d->state = Connecting; //d->jid = Jid(); //d->server = QString(); } ClientStream::~ClientStream() { reset(); delete d; } void ClientStream::reset(bool all) { d->reset(); d->noopTimer.stop(); // delete securestream delete d->ss; d->ss = 0; // reset sasl delete d->sasl; d->sasl = 0; // client if(d->mode == Client) { // reset tls // FIXME: Temporarily disabled //if(d->tlsHandler) // d->tlsHandler->reset(); // reset connector if(d->bs) { d->bs->close(); d->bs = 0; } d->conn->done(); // reset state machine d->client.reset(); } // server else { if(d->tls) d->tls->reset(); if(d->bs) { d->bs->close(); d->bs = 0; } d->srv.reset(); } if(all) { while (!d->in.isEmpty()) { delete d->in.takeFirst(); } } } Jid ClientStream::jid() const { return d->jid; } void ClientStream::connectToServer(const Jid &jid, bool auth) { reset(true); d->state = Connecting; d->jid = jid; d->doAuth = auth; d->server = d->jid.domain(); d->conn->connectToServer(d->server); } void ClientStream::continueAfterWarning() { if(d->state == WaitVersion) { // if we don't have TLS yet, then we're never going to get it if(!d->tls_warned && !d->using_tls) { d->tls_warned = true; d->state = WaitTLS; warning(WarnNoTLS); return; } d->state = Connecting; processNext(); } else if(d->state == WaitTLS) { d->state = Connecting; processNext(); } } void ClientStream::accept() { d->srv.host = d->server; processNext(); } bool ClientStream::isActive() const { return (d->state != Idle) ? true: false; } bool ClientStream::isAuthenticated() const { return (d->state == Active) ? true: false; } void ClientStream::setUsername(const QString &s) { if(d->sasl) d->sasl->setUsername(s); } void ClientStream::setPassword(const QString &s) { if(d->client.old) { d->client.setPassword(s); } else { if(d->sasl) d->sasl->setPassword(QCA::SecureArray(s.toUtf8())); } } void ClientStream::setRealm(const QString &s) { if(d->sasl) d->sasl->setRealm(s); } void ClientStream::setAuthzid(const QString &s) { if(d->sasl) d->sasl->setAuthzid(s); } void ClientStream::continueAfterParams() { if(d->state == NeedParams) { d->state = Connecting; if(d->client.old) { processNext(); } else { if(d->sasl) d->sasl->continueAfterParams(); } } } void ClientStream::setResourceBinding(bool b) { d->doBinding = b; } void ClientStream::setLang(const QString& lang) { d->lang = lang; } void ClientStream::setNoopTime(int mills) { d->noop_time = mills; if(d->state != Active) return; if(d->noop_time == 0) { d->noopTimer.stop(); return; } d->noopTimer.start(d->noop_time); } QString ClientStream::saslMechanism() const { return d->client.saslMech(); } int ClientStream::saslSSF() const { return d->sasl_ssf; } void ClientStream::setSASLMechanism(const QString &s) { d->sasl_mech = s; } void ClientStream::setLocalAddr(const QHostAddress &addr, quint16 port) { d->haveLocalAddr = true; d->localAddr = addr; d->localPort = port; } void ClientStream::setCompress(bool compress) { d->doCompress = compress; } int ClientStream::errorCondition() const { return d->errCond; } QString ClientStream::errorText() const { return d->errText; } QDomElement ClientStream::errorAppSpec() const { return d->errAppSpec; } bool ClientStream::old() const { return d->client.old; } void ClientStream::close() { if(d->state == Active) { d->state = Closing; d->client.shutdown(); processNext(); } else if(d->state != Idle && d->state != Closing) { reset(); } } QDomDocument & ClientStream::doc() const { return d->client.doc; } QString ClientStream::baseNS() const { return NS_CLIENT; } void ClientStream::setAllowPlain(AllowPlainType a) { d->allowPlain = a; } void ClientStream::setRequireMutualAuth(bool b) { d->mutualAuth = b; } void ClientStream::setSSFRange(int low, int high) { d->minimumSSF = low; d->maximumSSF = high; } void ClientStream::setOldOnly(bool b) { d->oldOnly = b; } bool ClientStream::stanzaAvailable() const { return (!d->in.isEmpty()); } Stanza ClientStream::read() { if(d->in.isEmpty()) return Stanza(); else { Stanza *sp = d->in.takeFirst(); Stanza s = *sp; delete sp; return s; } } void ClientStream::write(const Stanza &s) { if(d->state == Active) { d->client.sendStanza(s.element()); processNext(); } } void ClientStream::cr_connected() { d->connectHost = d->conn->host(); d->bs = d->conn->stream(); connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed())); connect(d->bs, SIGNAL(delayedCloseFinished()), SLOT(bs_delayedCloseFinished())); QByteArray spare = d->bs->read(); d->ss = new SecureStream(d->bs); connect(d->ss, SIGNAL(readyRead()), SLOT(ss_readyRead())); connect(d->ss, SIGNAL(bytesWritten(int)), SLOT(ss_bytesWritten(int))); connect(d->ss, SIGNAL(tlsHandshaken()), SLOT(ss_tlsHandshaken())); connect(d->ss, SIGNAL(tlsClosed()), SLOT(ss_tlsClosed())); connect(d->ss, SIGNAL(error(int)), SLOT(ss_error(int))); //d->client.startDialbackOut("andbit.net", "im.pyxa.org"); //d->client.startServerOut(d->server); d->client.startClientOut(d->jid, d->oldOnly, d->conn->useSSL(), d->doAuth, d->doCompress); d->client.setAllowTLS(d->tlsHandler ? true: false); d->client.setAllowBind(d->doBinding); d->client.setAllowPlain(d->allowPlain == AllowPlain || (d->allowPlain == AllowPlainOverTLS && d->conn->useSSL())); d->client.setLang(d->lang); /*d->client.jid = d->jid; d->client.server = d->server; d->client.allowPlain = d->allowPlain; d->client.oldOnly = d->oldOnly; d->client.sasl_mech = d->sasl_mech; d->client.doTLS = d->tlsHandler ? true: false; d->client.doBinding = d->doBinding;*/ QPointer self = this; connected(); if(!self) return; // immediate SSL? if(d->conn->useSSL()) { d->using_tls = true; d->ss->startTLSClient(d->tlsHandler, d->server, spare); } else { d->client.addIncomingData(spare); processNext(); } } void ClientStream::cr_error() { reset(); error(ErrConnection); } void ClientStream::bs_connectionClosed() { reset(); connectionClosed(); } void ClientStream::bs_delayedCloseFinished() { // we don't care about this (we track all important data ourself) } void ClientStream::bs_error(int) { // TODO } void ClientStream::ss_readyRead() { QByteArray a = d->ss->read(); #ifdef XMPP_DEBUG fprintf(stderr, "ClientStream: recv: %d [%s]\n", a.size(), a.data()); #endif if(d->mode == Client) d->client.addIncomingData(a); else d->srv.addIncomingData(a); if(d->notify & CoreProtocol::NRecv) { #ifdef XMPP_DEBUG printf("We needed data, so let's process it\n"); #endif processNext(); } } void ClientStream::ss_bytesWritten(int bytes) { if(d->mode == Client) d->client.outgoingDataWritten(bytes); else d->srv.outgoingDataWritten(bytes); if(d->notify & CoreProtocol::NSend) { #ifdef XMPP_DEBUG printf("We were waiting for data to be written, so let's process\n"); #endif processNext(); } } void ClientStream::ss_tlsHandshaken() { QPointer self = this; securityLayerActivated(LayerTLS); if(!self) return; d->client.setAllowPlain(d->allowPlain == AllowPlain || d->allowPlain == AllowPlainOverTLS); processNext(); } void ClientStream::ss_tlsClosed() { reset(); connectionClosed(); } void ClientStream::ss_error(int x) { if(x == SecureStream::ErrTLS) { reset(); d->errCond = TLSFail; error(ErrTLS); } else { reset(); error(ErrSecurityLayer); } } void ClientStream::sasl_clientFirstStep(bool, const QByteArray& ba) { d->client.setSASLFirst(d->sasl->mechanism(), ba); //d->client.sasl_mech = mech; //d->client.sasl_firstStep = stepData ? true : false; //d->client.sasl_step = stepData ? *stepData : QByteArray(); processNext(); } void ClientStream::sasl_nextStep(const QByteArray &stepData) { if(d->mode == Client) d->client.setSASLNext(stepData); //d->client.sasl_step = stepData; else d->srv.setSASLNext(stepData); //d->srv.sasl_step = stepData; processNext(); } void ClientStream::sasl_needParams(const QCA::SASL::Params& p) { #ifdef XMPP_DEBUG printf("need params: %d,%d,%d,%d\n", p.user, p.authzid, p.pass, p.realm); #endif /*if(p.authzid && !p.user) { d->sasl->setAuthzid(d->jid.bare()); //d->sasl->setAuthzid("infiniti.homelesshackers.org"); }*/ if(p.needUsername() || p.needPassword() || p.canSendRealm()) { d->state = NeedParams; needAuthParams(p.needUsername(), p.needPassword(), p.canSendRealm()); } else d->sasl->continueAfterParams(); } void ClientStream::sasl_authCheck(const QString &user, const QString &) { //#ifdef XMPP_DEBUG // printf("authcheck: [%s], [%s]\n", user.latin1(), authzid.latin1()); //#endif QString u = user; int n = u.indexOf('@'); if(n != -1) u.truncate(n); d->srv.user = u; d->sasl->continueAfterAuthCheck(); } void ClientStream::sasl_authenticated() { #ifdef XMPP_DEBUG printf("sasl authed!!\n"); #endif d->sasl_ssf = d->sasl->ssf(); if(d->mode == Server) { d->srv.setSASLAuthed(); processNext(); } } void ClientStream::sasl_error() { #ifdef XMPP_DEBUG printf("sasl error: %d\n", d->sasl->authCondition()); #endif // has to be auth error int x = convertedSASLCond(); d->errText = tr("Offered mechanisms: ") + d->client.features.sasl_mechs.join(", "); reset(); d->errCond = x; error(ErrAuth); } void ClientStream::srvProcessNext() { while(1) { printf("Processing step...\n"); if(!d->srv.processStep()) { int need = d->srv.need; if(need == CoreProtocol::NNotify) { d->notify = d->srv.notify; if(d->notify & CoreProtocol::NSend) printf("More data needs to be written to process next step\n"); if(d->notify & CoreProtocol::NRecv) printf("More data is needed to process next step\n"); } else if(need == CoreProtocol::NSASLMechs) { if(!d->sasl) { d->sasl = new QCA::SASL; connect(d->sasl, SIGNAL(authCheck(const QString &, const QString &)), SLOT(sasl_authCheck(const QString &, const QString &))); connect(d->sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &))); connect(d->sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated())); connect(d->sasl, SIGNAL(error()), SLOT(sasl_error())); //d->sasl->setAllowAnonymous(false); //d->sasl->setRequirePassCredentials(true); //d->sasl->setExternalAuthID("localhost"); QCA::SASL::AuthFlags auth_flags = (QCA::SASL::AuthFlags) 0; d->sasl->setConstraints(auth_flags,0,256); QStringList list; // TODO: d->server is probably wrong here d->sasl->startServer("xmpp", d->server, d->defRealm, QCA::SASL::AllowServerSendLast); d->sasl_mechlist = list; } d->srv.setSASLMechList(d->sasl_mechlist); continue; } else if(need == CoreProtocol::NStartTLS) { printf("Need StartTLS\n"); //if(!d->tls->startServer()) { d->tls->startServer(); QByteArray a = d->srv.spare; d->ss->startTLSServer(d->tls, a); } else if(need == CoreProtocol::NSASLFirst) { printf("Need SASL First Step\n"); QByteArray a = d->srv.saslStep(); d->sasl->putServerFirstStep(d->srv.saslMech(), a); } else if(need == CoreProtocol::NSASLNext) { printf("Need SASL Next Step\n"); QByteArray a = d->srv.saslStep(); printf("[%s]\n", a.data()); d->sasl->putStep(a); } else if(need == CoreProtocol::NSASLLayer) { } // now we can announce stanzas //if(!d->in.isEmpty()) // readyRead(); return; } d->notify = 0; int event = d->srv.event; printf("event: %d\n", event); switch(event) { case CoreProtocol::EError: { printf("Error! Code=%d\n", d->srv.errorCode); reset(); error(ErrProtocol); //handleError(); return; } case CoreProtocol::ESend: { QByteArray a = d->srv.takeOutgoingData(); printf("Need Send: {%s}\n", a.data()); d->ss->write(a); break; } case CoreProtocol::ERecvOpen: { printf("Break (RecvOpen)\n"); // calculate key QByteArray str = QCA::Hash("sha1").hashToString("secret").toUtf8(); str = QCA::Hash("sha1").hashToString(str + "im.pyxa.org").toUtf8(); str = QCA::Hash("sha1").hashToString(str + d->srv.id.toUtf8()).toUtf8(); d->srv.setDialbackKey(str); //d->srv.setDialbackKey("3c5d721ea2fcc45b163a11420e4e358f87e3142a"); if(d->srv.to != d->server) { // host-gone, host-unknown, see-other-host d->srv.shutdownWithError(CoreProtocol::HostUnknown); } else d->srv.setFrom(d->server); break; } case CoreProtocol::ESASLSuccess: { printf("Break SASL Success\n"); disconnect(d->sasl, SIGNAL(error()), this, SLOT(sasl_error())); QByteArray a = d->srv.spare; d->ss->setLayerSASL(d->sasl, a); break; } case CoreProtocol::EPeerClosed: { // TODO: this isn' an error printf("peer closed\n"); reset(); error(ErrProtocol); return; } } } } void ClientStream::doReadyRead() { //QGuardedPtr self = this; readyRead(); //if(!self) // return; //d->in_rrsig = false; } void ClientStream::processNext() { if(d->mode == Server) { srvProcessNext(); return; } QPointer self = this; while(1) { #ifdef XMPP_DEBUG printf("Processing step...\n"); #endif bool ok = d->client.processStep(); // deal with send/received items for(QList::ConstIterator it = d->client.transferItemList.begin(); it != d->client.transferItemList.end(); ++it) { const XmlProtocol::TransferItem &i = *it; if(i.isExternal) continue; QString str; if(i.isString) { // skip whitespace pings if(i.str.trimmed().isEmpty()) continue; str = i.str; } else str = d->client.elementToString(i.elem); if(i.isSent) outgoingXml(str); else incomingXml(str); } if(!ok) { bool cont = handleNeed(); // now we can announce stanzas //if(!d->in_rrsig && !d->in.isEmpty()) { if(!d->in.isEmpty()) { //d->in_rrsig = true; QTimer::singleShot(0, this, SLOT(doReadyRead())); } if(cont) continue; return; } int event = d->client.event; d->notify = 0; switch(event) { case CoreProtocol::EError: { #ifdef XMPP_DEBUG printf("Error! Code=%d\n", d->client.errorCode); #endif handleError(); return; } case CoreProtocol::ESend: { QByteArray a = d->client.takeOutgoingData(); #ifdef XMPP_DEBUG printf("Need Send: {%s}\n", a.data()); #endif d->ss->write(a); break; } case CoreProtocol::ERecvOpen: { #ifdef XMPP_DEBUG printf("Break (RecvOpen)\n"); #endif #ifdef XMPP_TEST QString s = QString("handshake success (lang=[%1]").arg(d->client.lang); if(!d->client.from.isEmpty()) s += QString(", from=[%1]").arg(d->client.from); s += ')'; TD::msg(s); #endif if(d->client.old) { d->state = WaitVersion; warning(WarnOldVersion); return; } break; } case CoreProtocol::EFeatures: { #ifdef XMPP_DEBUG printf("Break (Features)\n"); #endif if(!d->tls_warned && !d->using_tls && !d->client.features.tls_supported) { d->tls_warned = true; d->state = WaitTLS; warning(WarnNoTLS); return; } break; } case CoreProtocol::ESASLSuccess: { #ifdef XMPP_DEBUG printf("Break SASL Success\n"); #endif break; } case CoreProtocol::EReady: { #ifdef XMPP_DEBUG printf("Done!\n"); #endif // grab the JID, in case it changed d->jid = d->client.jid(); d->state = Active; setNoopTime(d->noop_time); authenticated(); if(!self) return; break; } case CoreProtocol::EPeerClosed: { #ifdef XMPP_DEBUG printf("DocumentClosed\n"); #endif reset(); connectionClosed(); return; } case CoreProtocol::EStanzaReady: { #ifdef XMPP_DEBUG printf("StanzaReady\n"); #endif // store the stanza for now, announce after processing all events Stanza s = createStanza(d->client.recvStanza()); if(s.isNull()) break; d->in.append(new Stanza(s)); break; } case CoreProtocol::EStanzaSent: { #ifdef XMPP_DEBUG printf("StanzasSent\n"); #endif stanzaWritten(); if(!self) return; break; } case CoreProtocol::EClosed: { #ifdef XMPP_DEBUG printf("Closed\n"); #endif reset(); delayedCloseFinished(); return; } } } } bool ClientStream::handleNeed() { int need = d->client.need; if(need == CoreProtocol::NNotify) { d->notify = d->client.notify; #ifdef XMPP_DEBUG if(d->notify & CoreProtocol::NSend) printf("More data needs to be written to process next step\n"); if(d->notify & CoreProtocol::NRecv) printf("More data is needed to process next step\n"); #endif return false; } d->notify = 0; switch(need) { case CoreProtocol::NStartTLS: { #ifdef XMPP_DEBUG printf("Need StartTLS\n"); #endif d->using_tls = true; d->ss->startTLSClient(d->tlsHandler, d->server, d->client.spare); return false; } case CoreProtocol::NCompress: { #ifdef XMPP_DEBUG printf("Need compress\n"); #endif d->ss->setLayerCompress(d->client.spare); return true; } case CoreProtocol::NSASLFirst: { #ifdef XMPP_DEBUG printf("Need SASL First Step\n"); #endif // ensure simplesasl provider is installed bool found = false; foreach(QCA::Provider *p, QCA::providers()) { if(p->name() == "simplesasl") { found = true; break; } } if(!found) { // install with low-priority QCA::insertProvider(createProviderSimpleSASL()); QCA::setProviderPriority("simplesasl", 10); } d->sasl = new QCA::SASL(); connect(d->sasl, SIGNAL(clientStarted(bool,const QByteArray&)), SLOT(sasl_clientFirstStep(bool, const QByteArray&))); connect(d->sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &))); connect(d->sasl, SIGNAL(needParams(const QCA::SASL::Params&)), SLOT(sasl_needParams(const QCA::SASL::Params&))); connect(d->sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated())); connect(d->sasl, SIGNAL(error()), SLOT(sasl_error())); if(d->haveLocalAddr) d->sasl->setLocalAddress(d->localAddr.toString(), d->localPort); if(d->conn->havePeerAddress()) d->sasl->setRemoteAddress(d->conn->peerAddress().toString(), d->conn->peerPort()); //d->sasl_mech = "ANONYMOUS"; //d->sasl->setRequirePassCredentials(true); //d->sasl->setExternalAuthID("localhost"); //d->sasl->setExternalSSF(64); //d->sasl_mech = "EXTERNAL"; QCA::SASL::AuthFlags auth_flags = (QCA::SASL::AuthFlags) 0; if (d->allowPlain == AllowPlain || (d->allowPlain == AllowPlainOverTLS && d->using_tls)) auth_flags = (QCA::SASL::AuthFlags) (auth_flags | QCA::SASL::AllowPlain); if (d->mutualAuth) auth_flags = (QCA::SASL::AuthFlags) (auth_flags | QCA::SASL::RequireMutualAuth); d->sasl->setConstraints(auth_flags,d->minimumSSF,d->maximumSSF); QStringList ml; if(!d->sasl_mech.isEmpty()) ml += d->sasl_mech; else ml = d->client.features.sasl_mechs; #ifdef IRIS_SASLCONNECTHOST d->sasl->startClient("xmpp", QUrl::toAce(d->connectHost), ml, QCA::SASL::AllowClientSendFirst); #else d->sasl->startClient("xmpp", QUrl::toAce(d->server), ml, QCA::SASL::AllowClientSendFirst); #endif return false; } case CoreProtocol::NSASLNext: { #ifdef XMPP_DEBUG printf("Need SASL Next Step\n"); #endif QByteArray a = d->client.saslStep(); d->sasl->putStep(a); return false; } case CoreProtocol::NSASLLayer: { // SecureStream will handle the errors from this point disconnect(d->sasl, SIGNAL(error()), this, SLOT(sasl_error())); d->ss->setLayerSASL(d->sasl, d->client.spare); if(d->sasl_ssf > 0) { QPointer self = this; securityLayerActivated(LayerSASL); if(!self) return false; } break; } case CoreProtocol::NPassword: { #ifdef XMPP_DEBUG printf("Need Password\n"); #endif d->state = NeedParams; needAuthParams(false, true, false); return false; } } return true; } int ClientStream::convertedSASLCond() const { int x = d->sasl->authCondition(); if(x == QCA::SASL::NoMechanism) return NoMech; else if(x == QCA::SASL::BadProtocol) return BadProto; else if(x == QCA::SASL::BadServer) return BadServ; else if(x == QCA::SASL::TooWeak) return MechTooWeak; else return GenericAuthError; return 0; } void ClientStream::doNoop() { if(d->state == Active) { #ifdef XMPP_DEBUG printf("doPing\n"); #endif d->client.sendWhitespace(); processNext(); } } void ClientStream::writeDirect(const QString &s) { if(d->state == Active) { #ifdef XMPP_DEBUG printf("writeDirect\n"); #endif d->client.sendDirect(s); processNext(); } } void ClientStream::handleError() { int c = d->client.errorCode; if(c == CoreProtocol::ErrParse) { reset(); error(ErrParse); } else if(c == CoreProtocol::ErrProtocol) { reset(); error(ErrProtocol); } else if(c == CoreProtocol::ErrStream) { int x = d->client.errCond; QString text = d->client.errText; QDomElement appSpec = d->client.errAppSpec; int connErr = -1; int strErr = -1; switch(x) { case CoreProtocol::BadFormat: { break; } // should NOT happen (we send the right format) case CoreProtocol::BadNamespacePrefix: { break; } // should NOT happen (we send prefixes) case CoreProtocol::Conflict: { strErr = Conflict; break; } case CoreProtocol::ConnectionTimeout: { strErr = ConnectionTimeout; break; } case CoreProtocol::HostGone: { connErr = HostGone; break; } case CoreProtocol::HostUnknown: { connErr = HostUnknown; break; } case CoreProtocol::ImproperAddressing: { break; } // should NOT happen (we aren't a server) case CoreProtocol::InternalServerError: { strErr = InternalServerError; break; } case CoreProtocol::InvalidFrom: { strErr = InvalidFrom; break; } case CoreProtocol::InvalidId: { break; } // should NOT happen (clients don't specify id) case CoreProtocol::InvalidNamespace: { break; } // should NOT happen (we set the right ns) case CoreProtocol::InvalidXml: { strErr = InvalidXml; break; } // shouldn't happen either, but just in case ... case CoreProtocol::StreamNotAuthorized: { break; } // should NOT happen (we're not stupid) case CoreProtocol::PolicyViolation: { strErr = PolicyViolation; break; } case CoreProtocol::RemoteConnectionFailed: { connErr = RemoteConnectionFailed; break; } case CoreProtocol::ResourceConstraint: { strErr = ResourceConstraint; break; } case CoreProtocol::RestrictedXml: { strErr = InvalidXml; break; } // group with this one case CoreProtocol::SeeOtherHost: { connErr = SeeOtherHost; break; } case CoreProtocol::SystemShutdown: { strErr = SystemShutdown; break; } case CoreProtocol::UndefinedCondition: { break; } // leave as null error case CoreProtocol::UnsupportedEncoding: { break; } // should NOT happen (we send good encoding) case CoreProtocol::UnsupportedStanzaType: { break; } // should NOT happen (we're not stupid) case CoreProtocol::UnsupportedVersion: { connErr = UnsupportedVersion; break; } case CoreProtocol::XmlNotWellFormed: { strErr = InvalidXml; break; } // group with this one default: { break; } } reset(); d->errText = text; d->errAppSpec = appSpec; if(connErr != -1) { d->errCond = connErr; error(ErrNeg); } else { if(strErr != -1) d->errCond = strErr; else d->errCond = GenericStreamError; error(ErrStream); } } else if(c == CoreProtocol::ErrStartTLS) { reset(); d->errCond = TLSStart; error(ErrTLS); } else if(c == CoreProtocol::ErrAuth) { int x = d->client.errCond; int r = GenericAuthError; if(d->client.old) { if(x == 401) // not authorized r = NotAuthorized; else if(x == 409) // conflict r = GenericAuthError; else if(x == 406) // not acceptable (this should NOT happen) r = GenericAuthError; } else { switch(x) { case CoreProtocol::Aborted: { r = GenericAuthError; break; } // should NOT happen (we never send ) case CoreProtocol::IncorrectEncoding: { r = GenericAuthError; break; } // should NOT happen case CoreProtocol::InvalidAuthzid: { r = InvalidAuthzid; break; } case CoreProtocol::InvalidMech: { r = InvalidMech; break; } case CoreProtocol::MechTooWeak: { r = MechTooWeak; break; } case CoreProtocol::NotAuthorized: { r = NotAuthorized; break; } case CoreProtocol::TemporaryAuthFailure: { r = TemporaryAuthFailure; break; } } } reset(); d->errCond = r; error(ErrAuth); } else if(c == CoreProtocol::ErrPlain) { reset(); d->errCond = NoMech; error(ErrAuth); } else if(c == CoreProtocol::ErrBind) { int r = -1; if(d->client.errCond == CoreProtocol::BindBadRequest) { // should NOT happen } else if(d->client.errCond == CoreProtocol::BindNotAllowed) { r = BindNotAllowed; } else if(d->client.errCond == CoreProtocol::BindConflict) { r = BindConflict; } if(r != -1) { reset(); d->errCond = r; error(ErrBind); } else { reset(); error(ErrProtocol); } } } QStringList ClientStream::hosts() const { return d->client.hosts; } //---------------------------------------------------------------------------- // Debug //---------------------------------------------------------------------------- Debug::~Debug() { } #ifdef XMPP_TEST TD::TD() { } TD::~TD() { } void TD::msg(const QString &s) { if(debug_ptr) debug_ptr->msg(s); } void TD::outgoingTag(const QString &s) { if(debug_ptr) debug_ptr->outgoingTag(s); } void TD::incomingTag(const QString &s) { if(debug_ptr) debug_ptr->incomingTag(s); } void TD::outgoingXml(const QDomElement &e) { if(debug_ptr) debug_ptr->outgoingXml(e); } void TD::incomingXml(const QDomElement &e) { if(debug_ptr) debug_ptr->incomingXml(e); } #endif psi-0.14/iris/src/xmpp/xmpp-core/securestream.cpp0000644000175000017500000003241011305557616020205 0ustar janjan/* * securestream.cpp - combines a ByteStream with TLS and SASL * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* Note: SecureStream depends on the underlying security layers to signal plain-to-encrypted results immediately (as opposed to waiting for the event loop) so that the user cannot add/remove security layers during this conversion moment. QCA::TLS and QCA::SASL behave as expected, but future layers might not. */ #include "securestream.h" #include #include #include #ifdef USE_TLSHANDLER #include "xmpp.h" #endif #include "compressionhandler.h" //---------------------------------------------------------------------------- // LayerTracker //---------------------------------------------------------------------------- class LayerTracker { public: struct Item { int plain; int encoded; }; LayerTracker(); void reset(); void addPlain(int plain); void specifyEncoded(int encoded, int plain); int finished(int encoded); int p; QList list; }; LayerTracker::LayerTracker() { p = 0; } void LayerTracker::reset() { p = 0; list.clear(); } void LayerTracker::addPlain(int plain) { p += plain; } void LayerTracker::specifyEncoded(int encoded, int plain) { // can't specify more bytes than we have if(plain > p) plain = p; p -= plain; Item i; i.plain = plain; i.encoded = encoded; list += i; } int LayerTracker::finished(int encoded) { int plain = 0; for(QList::Iterator it = list.begin(); it != list.end();) { Item &i = *it; // not enough? if(encoded < i.encoded) { i.encoded -= encoded; break; } encoded -= i.encoded; plain += i.plain; it = list.erase(it); } return plain; } //---------------------------------------------------------------------------- // SecureStream //---------------------------------------------------------------------------- class SecureLayer : public QObject { Q_OBJECT public: enum { TLS, SASL, TLSH, Compression }; int type; union { QCA::TLS *tls; QCA::SASL *sasl; #ifdef USE_TLSHANDLER XMPP::TLSHandler *tlsHandler; #endif CompressionHandler *compressionHandler; } p; LayerTracker layer; bool tls_done; int prebytes; SecureLayer(QCA::TLS *t) { type = TLS; p.tls = t; init(); connect(p.tls, SIGNAL(handshaken()), SLOT(tls_handshaken())); connect(p.tls, SIGNAL(readyRead()), SLOT(tls_readyRead())); connect(p.tls, SIGNAL(readyReadOutgoing(int)), SLOT(tls_readyReadOutgoing(int))); connect(p.tls, SIGNAL(closed()), SLOT(tls_closed())); connect(p.tls, SIGNAL(error(int)), SLOT(tls_error(int))); } SecureLayer(QCA::SASL *s) { type = SASL; p.sasl = s; init(); connect(p.sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead())); connect(p.sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing())); connect(p.sasl, SIGNAL(error()), SLOT(sasl_error())); } SecureLayer(CompressionHandler *t) { t->setParent(this); // automatically clean up CompressionHandler when SecureLayer is destroyed type = Compression; p.compressionHandler = t; init(); connect(p.compressionHandler, SIGNAL(readyRead()), SLOT(compressionHandler_readyRead())); connect(p.compressionHandler, SIGNAL(readyReadOutgoing()), SLOT(compressionHandler_readyReadOutgoing())); connect(p.compressionHandler, SIGNAL(error()), SLOT(compressionHandler_error())); } #ifdef USE_TLSHANDLER SecureLayer(XMPP::TLSHandler *t) { type = TLSH; p.tlsHandler = t; init(); connect(p.tlsHandler, SIGNAL(success()), SLOT(tlsHandler_success())); connect(p.tlsHandler, SIGNAL(fail()), SLOT(tlsHandler_fail())); connect(p.tlsHandler, SIGNAL(closed()), SLOT(tlsHandler_closed())); connect(p.tlsHandler, SIGNAL(readyRead(const QByteArray &)), SLOT(tlsHandler_readyRead(const QByteArray &))); connect(p.tlsHandler, SIGNAL(readyReadOutgoing(const QByteArray &, int)), SLOT(tlsHandler_readyReadOutgoing(const QByteArray &, int))); } #endif void init() { tls_done = false; prebytes = 0; } void write(const QByteArray &a) { layer.addPlain(a.size()); switch(type) { case TLS: { p.tls->write(a); break; } case SASL: { p.sasl->write(a); break; } #ifdef USE_TLSHANDLER case TLSH: { p.tlsHandler->write(a); break; } #endif case Compression: { p.compressionHandler->write(a); break; } } } void writeIncoming(const QByteArray &a) { switch(type) { case TLS: { p.tls->writeIncoming(a); break; } case SASL: { p.sasl->writeIncoming(a); break; } #ifdef USE_TLSHANDLER case TLSH: { p.tlsHandler->writeIncoming(a); break; } #endif case Compression: { p.compressionHandler->writeIncoming(a); break; } } } int finished(int plain) { int written = 0; // deal with prebytes (bytes sent prior to this security layer) if(prebytes > 0) { if(prebytes >= plain) { written += plain; prebytes -= plain; plain = 0; } else { written += prebytes; plain -= prebytes; prebytes = 0; } } // put remainder into the layer tracker if(type == SASL || tls_done) written += layer.finished(plain); return written; } signals: void tlsHandshaken(); void tlsClosed(const QByteArray &); void readyRead(const QByteArray &); void needWrite(const QByteArray &); void error(int); private slots: void tls_handshaken() { tls_done = true; tlsHandshaken(); } void tls_readyRead() { QByteArray a = p.tls->read(); readyRead(a); } void tls_readyReadOutgoing(int plainBytes) { QByteArray a = p.tls->readOutgoing(); if(tls_done) layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } void tls_closed() { QByteArray a = p.tls->readUnprocessed(); tlsClosed(a); } void tls_error(int x) { error(x); } void sasl_readyRead() { QByteArray a = p.sasl->read(); readyRead(a); } void sasl_readyReadOutgoing() { int plainBytes; QByteArray a = p.sasl->readOutgoing(&plainBytes); layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } void sasl_error() { error(p.sasl->errorCode()); } void compressionHandler_readyRead() { QByteArray a = p.compressionHandler->read(); readyRead(a); } void compressionHandler_readyReadOutgoing() { int plainBytes; QByteArray a = p.compressionHandler->readOutgoing(&plainBytes); layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } void compressionHandler_error() { error(p.compressionHandler->errorCode()); } #ifdef USE_TLSHANDLER void tlsHandler_success() { tls_done = true; tlsHandshaken(); } void tlsHandler_fail() { error(0); } void tlsHandler_closed() { tlsClosed(QByteArray()); } void tlsHandler_readyRead(const QByteArray &a) { readyRead(a); } void tlsHandler_readyReadOutgoing(const QByteArray &a, int plainBytes) { if(tls_done) layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } #endif }; #include "securestream.moc" class SecureStream::Private { public: ByteStream *bs; QList layers; int pending; int errorCode; bool active; bool topInProgress; bool haveTLS() const { foreach(SecureLayer *s, layers) { if(s->type == SecureLayer::TLS #ifdef USE_TLSHANDLER || s->type == SecureLayer::TLSH #endif ) { return true; } } return false; } bool haveSASL() const { foreach(SecureLayer *s, layers) { if(s->type == SecureLayer::SASL) return true; } return false; } bool haveCompress() const { foreach(SecureLayer *s, layers) { if(s->type == SecureLayer::Compression) return true; } return false; } }; SecureStream::SecureStream(ByteStream *s) :ByteStream(0) { d = new Private; d->bs = s; connect(d->bs, SIGNAL(readyRead()), SLOT(bs_readyRead())); connect(d->bs, SIGNAL(bytesWritten(int)), SLOT(bs_bytesWritten(int))); d->pending = 0; d->active = true; d->topInProgress = false; } SecureStream::~SecureStream() { delete d; } void SecureStream::linkLayer(QObject *s) { connect(s, SIGNAL(tlsHandshaken()), SLOT(layer_tlsHandshaken())); connect(s, SIGNAL(tlsClosed(const QByteArray &)), SLOT(layer_tlsClosed(const QByteArray &))); connect(s, SIGNAL(readyRead(const QByteArray &)), SLOT(layer_readyRead(const QByteArray &))); connect(s, SIGNAL(needWrite(const QByteArray &)), SLOT(layer_needWrite(const QByteArray &))); connect(s, SIGNAL(error(int)), SLOT(layer_error(int))); } int SecureStream::calcPrebytes() const { int x = 0; foreach(SecureLayer *s, d->layers) { x += s->prebytes; } return (d->pending - x); } void SecureStream::startTLSClient(QCA::TLS *t, const QByteArray &spare) { if(!d->active || d->topInProgress || d->haveTLS()) return; SecureLayer *s = new SecureLayer(t); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); d->topInProgress = true; insertData(spare); } void SecureStream::startTLSServer(QCA::TLS *t, const QByteArray &spare) { if(!d->active || d->topInProgress || d->haveTLS()) return; SecureLayer *s = new SecureLayer(t); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); d->topInProgress = true; insertData(spare); } void SecureStream::setLayerCompress(const QByteArray& spare) { if(!d->active || d->topInProgress || d->haveCompress()) return; SecureLayer *s = new SecureLayer(new CompressionHandler()); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); insertData(spare); } void SecureStream::setLayerSASL(QCA::SASL *sasl, const QByteArray &spare) { if(!d->active || d->topInProgress || d->haveSASL()) return; SecureLayer *s = new SecureLayer(sasl); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); insertData(spare); } #ifdef USE_TLSHANDLER void SecureStream::startTLSClient(XMPP::TLSHandler *t, const QString &server, const QByteArray &spare) { if(!d->active || d->topInProgress || d->haveTLS()) return; SecureLayer *s = new SecureLayer(t); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); d->topInProgress = true; // unlike QCA::TLS, XMPP::TLSHandler has no return value s->p.tlsHandler->startClient(server); insertData(spare); } #endif void SecureStream::closeTLS() { if (!d->layers.isEmpty()) { SecureLayer *s = d->layers.last(); if(s->type == SecureLayer::TLS) { s->p.tls->close(); } } } int SecureStream::errorCode() const { return d->errorCode; } bool SecureStream::isOpen() const { return d->active; } void SecureStream::write(const QByteArray &a) { if(!isOpen()) return; d->pending += a.size(); // send to the last layer if (!d->layers.isEmpty()) { SecureLayer *s = d->layers.last(); s->write(a); } else { writeRawData(a); } } int SecureStream::bytesToWrite() const { return d->pending; } void SecureStream::bs_readyRead() { QByteArray a = d->bs->read(); // send to the first layer if (!d->layers.isEmpty()) { SecureLayer *s = d->layers.first(); s->writeIncoming(a); } else { incomingData(a); } } void SecureStream::bs_bytesWritten(int bytes) { foreach(SecureLayer *s, d->layers) { bytes = s->finished(bytes); } if(bytes > 0) { d->pending -= bytes; bytesWritten(bytes); } } void SecureStream::layer_tlsHandshaken() { d->topInProgress = false; tlsHandshaken(); } void SecureStream::layer_tlsClosed(const QByteArray &) { d->active = false; while (!d->layers.isEmpty()) { delete d->layers.takeFirst(); } tlsClosed(); } void SecureStream::layer_readyRead(const QByteArray &a) { SecureLayer *s = (SecureLayer *)sender(); QList::Iterator it(d->layers.begin()); while((*it) != s) { Q_ASSERT(it != d->layers.end()); ++it; } Q_ASSERT(it != d->layers.end()); // pass upwards ++it; if (it != d->layers.end()) { s = (*it); s->writeIncoming(a); } else { incomingData(a); } } void SecureStream::layer_needWrite(const QByteArray &a) { SecureLayer *s = (SecureLayer *)sender(); QList::Iterator it(d->layers.begin()); while((*it) != s) { Q_ASSERT(it != d->layers.end()); ++it; } Q_ASSERT(it != d->layers.end()); // pass downwards if (it != d->layers.begin()) { --it; s = (*it); s->write(a); } else { writeRawData(a); } } void SecureStream::layer_error(int x) { SecureLayer *s = (SecureLayer *)sender(); int type = s->type; d->errorCode = x; d->active = false; while (!d->layers.isEmpty()) { delete d->layers.takeFirst(); } if(type == SecureLayer::TLS) error(ErrTLS); else if(type == SecureLayer::SASL) error(ErrSASL); #ifdef USE_TLSHANDLER else if(type == SecureLayer::TLSH) error(ErrTLS); #endif } void SecureStream::insertData(const QByteArray &a) { if(!a.isEmpty()) { if (!d->layers.isEmpty()) { SecureLayer *s = d->layers.last(); s->writeIncoming(a); } else { incomingData(a); } } } void SecureStream::writeRawData(const QByteArray &a) { d->bs->write(a); } void SecureStream::incomingData(const QByteArray &a) { appendRead(a); if(bytesAvailable()) readyRead(); } psi-0.14/iris/src/xmpp/xmpp-core/simplesasl.h0000644000175000017500000000173011305557616017325 0ustar janjan/* * simplesasl.h - Simple SASL implementation * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef SIMPLESASL_H #define SIMPLESASL_H namespace QCA { class Provider; } namespace XMPP { QCA::Provider* createProviderSimpleSASL(); } #endif psi-0.14/iris/src/xmpp/xmpp-core/xmlprotocol.h0000644000175000017500000000776111305557616017545 0ustar janjan/* * xmlprotocol.h - state machine for 'jabber-like' protocols * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMLPROTOCOL_H #define XMLPROTOCOL_H #include #include #include #include "parser.h" #define NS_XML "http://www.w3.org/XML/1998/namespace" namespace XMPP { class XmlProtocol : public QObject { public: enum Need { NNotify, // need a data send and/or recv update NCustom = 10 }; enum Event { EError, // unrecoverable error, see errorCode for details ESend, // data needs to be sent, use takeOutgoingData() ERecvOpen, // breakpoint after root element open tag is received EPeerClosed, // root element close tag received EClosed, // finished closing ECustom = 10 }; enum Error { ErrParse, // there was an error parsing the xml ErrCustom = 10 }; enum Notify { NSend = 0x01, // need to know if data has been written NRecv = 0x02 // need incoming data }; XmlProtocol(); virtual ~XmlProtocol(); virtual void reset(); // byte I/O for the stream void addIncomingData(const QByteArray &); QByteArray takeOutgoingData(); void outgoingDataWritten(int); // advance the state machine bool processStep(); // set these before returning from a step int need, event, errorCode, notify; inline bool isIncoming() const { return incoming; } QString xmlEncoding() const; QString elementToString(const QDomElement &e, bool clip=false); class TransferItem { public: TransferItem(); TransferItem(const QString &str, bool sent, bool external=false); TransferItem(const QDomElement &elem, bool sent, bool external=false); bool isSent; // else, received bool isString; // else, is element bool isExternal; // not owned by protocol QString str; QDomElement elem; }; QList transferItemList; void setIncomingAsExternal(); protected: virtual QDomElement docElement()=0; virtual void handleDocOpen(const Parser::Event &pe)=0; virtual bool handleError()=0; virtual bool handleCloseFinished()=0; virtual bool stepAdvancesParser() const=0; virtual bool stepRequiresElement() const; virtual bool doStep(const QDomElement &e)=0; virtual void itemWritten(int id, int size); // 'debug' virtual void stringSend(const QString &s); virtual void stringRecv(const QString &s); virtual void elementSend(const QDomElement &e); virtual void elementRecv(const QDomElement &e); void startConnect(); void startAccept(); bool close(); int writeString(const QString &s, int id, bool external); int writeElement(const QDomElement &e, int id, bool external, bool clip=false); QByteArray resetStream(); private: enum { SendOpen, RecvOpen, Open, Closing }; class TrackItem { public: enum Type { Raw, Close, Custom }; int type, id, size; }; bool incoming; QDomDocument elemDoc; QDomElement elem; QString tagOpen, tagClose; int state; bool peerClosed; bool closeWritten; Parser xml; QByteArray outData; QList trackQueue; void init(); int internalWriteData(const QByteArray &a, TrackItem::Type t, int id=-1); int internalWriteString(const QString &s, TrackItem::Type t, int id=-1); void sendTagOpen(); void sendTagClose(); bool baseStep(const Parser::Event &pe); }; } #endif psi-0.14/iris/src/xmpp/xmpp-core/xmlprotocol.cpp0000644000175000017500000003434211305557616020073 0ustar janjan/* * xmlprotocol.cpp - state machine for 'jabber-like' protocols * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmlprotocol.h" #include "bytestream.h" //Added by qt3to4: #include #include #include #include using namespace XMPP; // stripExtraNS // // This function removes namespace information from various nodes for // display purposes only (the element is pretty much useless for processing // after this). We do this because QXml is a bit overzealous about outputting // redundant namespaces. static QDomElement stripExtraNS(const QDomElement &e) { // find closest parent with a namespace QDomNode par = e.parentNode(); while(!par.isNull() && par.namespaceURI().isNull()) par = par.parentNode(); bool noShowNS = false; if(!par.isNull() && par.namespaceURI() == e.namespaceURI()) noShowNS = true; // build qName (prefix:localName) QString qName; if(!e.prefix().isEmpty()) qName = e.prefix() + ':' + e.localName(); else qName = e.tagName(); QDomElement i; int x; if(noShowNS) i = e.ownerDocument().createElement(qName); else i = e.ownerDocument().createElementNS(e.namespaceURI(), qName); // copy attributes QDomNamedNodeMap al = e.attributes(); for(x = 0; x < al.count(); ++x) { QDomAttr a = al.item(x).cloneNode().toAttr(); // don't show xml namespace if(a.namespaceURI() == NS_XML) i.setAttribute(QString("xml:") + a.name(), a.value()); else i.setAttributeNodeNS(a); } // copy children QDomNodeList nl = e.childNodes(); for(x = 0; x < nl.count(); ++x) { QDomNode n = nl.item(x); if(n.isElement()) i.appendChild(stripExtraNS(n.toElement())); else i.appendChild(n.cloneNode()); } return i; } // xmlToString // // This function converts a QDomElement into a QString, using stripExtraNS // to make it pretty. static QString xmlToString(const QDomElement &e, const QString &fakeNS, const QString &fakeQName, bool clip) { QDomElement i = e.cloneNode().toElement(); // It seems QDom can only have one namespace attribute at a time (see docElement 'HACK'). // Fortunately we only need one kind depending on the input, so it is specified here. QDomElement fake = e.ownerDocument().createElementNS(fakeNS, fakeQName); fake.appendChild(i); fake = stripExtraNS(fake); QString out; { QTextStream ts(&out, QIODevice::WriteOnly); fake.firstChild().save(ts, 0); } // 'clip' means to remove any unwanted (and unneeded) characters, such as a trailing newline if(clip) { int n = out.lastIndexOf('>'); out.truncate(n+1); } return out; } // createRootXmlTags // // This function creates three QStrings, one being an processing // instruction, and the others being the opening and closing tags of an // element, and . This basically allows us to get the raw XML // text needed to open/close an XML stream, without resorting to generating // the XML ourselves. This function uses QDom to do the generation, which // ensures proper encoding and entity output. static void createRootXmlTags(const QDomElement &root, QString *xmlHeader, QString *tagOpen, QString *tagClose) { QDomElement e = root.cloneNode(false).toElement(); // insert a dummy element to ensure open and closing tags are generated QDomElement dummy = e.ownerDocument().createElement("dummy"); e.appendChild(dummy); // convert to xml->text QString str; { QTextStream ts(&str, QIODevice::WriteOnly); e.save(ts, 0); } // parse the tags out int n = str.indexOf('<'); int n2 = str.indexOf('>', n); ++n2; *tagOpen = str.mid(n, n2-n); n2 = str.lastIndexOf('>'); n = str.lastIndexOf('<'); ++n2; *tagClose = str.mid(n, n2-n); // generate a nice xml processing header *xmlHeader = ""; } // w3c xml spec: // [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] static inline bool validChar(const quint32 ch) { return ch == 0x9 || ch == 0xA || ch == 0xD || ch >= 0x20 && ch <= 0xD7FF || ch >= 0xE000 && ch <= 0xFFFD || ch >= 0x10000 && ch <= 0x10FFFF; } static inline bool lowSurrogate(const quint32 ch) { return ch >= 0xDC00 && ch <= 0xDFFF; } static inline bool highSurrogate(const quint32 ch) { return ch >= 0xD800 && ch <= 0xDBFF; } // force encoding of '>'. this function is needed for XMPP-Core, which // requires the '>' character to be encoded as ">" even though this is // not required by the XML spec. // Also remove chars that are ouside the allowed range for XML (see validChar) // and invalid surrogate pairs static QString sanitizeForStream(const QString &in) { QString out; bool intag = false; bool inquote = false; QChar quotechar; int inlength = in.length(); for(int n = 0; n < inlength; ++n) { QChar c = in[n]; bool escape = false; if(c == '<') { intag = true; } else if(c == '>') { if(inquote) { escape = true; } else if(!intag) { escape = true; } else { intag = false; } } else if(c == '\'' || c == '\"') { if(intag) { if(!inquote) { inquote = true; quotechar = c; } else { if(quotechar == c) { inquote = false; } } } } if(escape) { out += ">"; } else { // don't silently drop invalid chars in element or attribute names, // because that's something that should not happen. if (intag && (!inquote)) { out += c; } else if (validChar(c.unicode())) { out += c; } else if (highSurrogate(c.unicode()) && (n+1 < inlength) && lowSurrogate(in[n+1].unicode())) { //uint unicode = (c.unicode() & 0x3FF) << 10 | in[n+1].unicode() & 0x3FF + 0x10000; // we don't need to recheck this, because 0x10000 <= unicode <= 0x100000 is always true out += c; out += in[n+1]; ++n; } else { qDebug("Dropping invalid XML char U+%04x",c.unicode()); } } } return out; } //---------------------------------------------------------------------------- // Protocol //---------------------------------------------------------------------------- XmlProtocol::TransferItem::TransferItem() { } XmlProtocol::TransferItem::TransferItem(const QString &_str, bool sent, bool external) { isString = true; isSent = sent; isExternal = external; str = _str; } XmlProtocol::TransferItem::TransferItem(const QDomElement &_elem, bool sent, bool external) { isString = false; isSent = sent; isExternal = external; elem = _elem; } XmlProtocol::XmlProtocol() : QObject(qApp) { init(); } XmlProtocol::~XmlProtocol() { } void XmlProtocol::init() { incoming = false; peerClosed = false; closeWritten = false; } void XmlProtocol::reset() { init(); elem = QDomElement(); elemDoc = QDomDocument(); tagOpen = QString(); tagClose = QString(); xml.reset(); outData.resize(0); trackQueue.clear(); transferItemList.clear(); } void XmlProtocol::addIncomingData(const QByteArray &a) { xml.appendData(a); } QByteArray XmlProtocol::takeOutgoingData() { QByteArray a = outData; outData.resize(0); return a; } void XmlProtocol::outgoingDataWritten(int bytes) { for(QList::Iterator it = trackQueue.begin(); it != trackQueue.end();) { TrackItem &i = *it; // enough bytes? if(bytes < i.size) { i.size -= bytes; break; } int type = i.type; int id = i.id; int size = i.size; bytes -= i.size; it = trackQueue.erase(it); if(type == TrackItem::Raw) { // do nothing } else if(type == TrackItem::Close) { closeWritten = true; } else if(type == TrackItem::Custom) { itemWritten(id, size); } } } bool XmlProtocol::processStep() { Parser::Event pe; notify = 0; transferItemList.clear(); if(state != Closing && (state == RecvOpen || stepAdvancesParser())) { // if we get here, then it's because we're in some step that advances the parser pe = xml.readNext(); if(!pe.isNull()) { // note: error/close events should be handled for ALL steps, so do them here switch(pe.type()) { case Parser::Event::DocumentOpen: { transferItemList += TransferItem(pe.actualString(), false); //stringRecv(pe.actualString()); break; } case Parser::Event::DocumentClose: { transferItemList += TransferItem(pe.actualString(), false); //stringRecv(pe.actualString()); if(incoming) { sendTagClose(); event = ESend; peerClosed = true; state = Closing; } else { event = EPeerClosed; } return true; } case Parser::Event::Element: { QDomElement e = elemDoc.importNode(pe.element(),true).toElement(); transferItemList += TransferItem(e, false); //elementRecv(pe.element()); break; } case Parser::Event::Error: { if(incoming) { // If we get a parse error during the initial element exchange, // flip immediately into 'open' mode so that we can report an error. if(state == RecvOpen) { sendTagOpen(); state = Open; } return handleError(); } else { event = EError; errorCode = ErrParse; return true; } } } } else { if(state == RecvOpen || stepRequiresElement()) { need = NNotify; notify |= NRecv; return false; } } } return baseStep(pe); } QString XmlProtocol::xmlEncoding() const { return xml.encoding(); } QString XmlProtocol::elementToString(const QDomElement &e, bool clip) { if(elem.isNull()) elem = elemDoc.importNode(docElement(), true).toElement(); // Determine the appropriate 'fakeNS' to use QString ns; // first, check root namespace QString pre = e.prefix(); if(pre.isNull()) pre = ""; if(pre == elem.prefix()) { ns = elem.namespaceURI(); } else { // scan the root attributes for 'xmlns' (oh joyous hacks) QDomNamedNodeMap al = elem.attributes(); int n; for(n = 0; n < al.count(); ++n) { QDomAttr a = al.item(n).toAttr(); QString s = a.name(); int x = s.indexOf(':'); if(x != -1) s = s.mid(x+1); else s = ""; if(pre == s) { ns = a.value(); break; } } if(n >= al.count()) { // if we get here, then no appropriate ns was found. use root then.. ns = elem.namespaceURI(); } } // build qName QString qn; if(!elem.prefix().isEmpty()) qn = elem.prefix() + ':'; qn += elem.localName(); // make the string return sanitizeForStream(xmlToString(e, ns, qn, clip)); } bool XmlProtocol::stepRequiresElement() const { // default returns false return false; } void XmlProtocol::itemWritten(int, int) { // default does nothing } void XmlProtocol::stringSend(const QString &) { // default does nothing } void XmlProtocol::stringRecv(const QString &) { // default does nothing } void XmlProtocol::elementSend(const QDomElement &) { // default does nothing } void XmlProtocol::elementRecv(const QDomElement &) { // default does nothing } void XmlProtocol::startConnect() { incoming = false; state = SendOpen; } void XmlProtocol::startAccept() { incoming = true; state = RecvOpen; } bool XmlProtocol::close() { sendTagClose(); event = ESend; state = Closing; return true; } int XmlProtocol::writeString(const QString &s, int id, bool external) { transferItemList += TransferItem(s, true, external); return internalWriteString(s, TrackItem::Custom, id); } int XmlProtocol::writeElement(const QDomElement &e, int id, bool external, bool clip) { if(e.isNull()) return 0; transferItemList += TransferItem(e, true, external); //elementSend(e); QString out = sanitizeForStream(elementToString(e, clip)); return internalWriteString(out, TrackItem::Custom, id); } QByteArray XmlProtocol::resetStream() { // reset the state if(incoming) state = RecvOpen; else state = SendOpen; // grab unprocessed data before resetting QByteArray spare = xml.unprocessed(); xml.reset(); return spare; } int XmlProtocol::internalWriteData(const QByteArray &a, TrackItem::Type t, int id) { TrackItem i; i.type = t; i.id = id; i.size = a.size(); trackQueue += i; ByteStream::appendArray(&outData, a); return a.size(); } int XmlProtocol::internalWriteString(const QString &s, TrackItem::Type t, int id) { QString out=sanitizeForStream(s); return internalWriteData(s.toUtf8(), t, id); } void XmlProtocol::sendTagOpen() { if(elem.isNull()) elem = elemDoc.importNode(docElement(), true).toElement(); QString xmlHeader; createRootXmlTags(elem, &xmlHeader, &tagOpen, &tagClose); QString s; s += xmlHeader + '\n'; s += sanitizeForStream(tagOpen) + '\n'; transferItemList += TransferItem(xmlHeader, true); transferItemList += TransferItem(tagOpen, true); //stringSend(xmlHeader); //stringSend(tagOpen); internalWriteString(s, TrackItem::Raw); } void XmlProtocol::sendTagClose() { transferItemList += TransferItem(tagClose, true); //stringSend(tagClose); internalWriteString(tagClose, TrackItem::Close); } bool XmlProtocol::baseStep(const Parser::Event &pe) { // Basic if(state == SendOpen) { sendTagOpen(); event = ESend; if(incoming) state = Open; else state = RecvOpen; return true; } else if(state == RecvOpen) { if(incoming) state = SendOpen; else state = Open; // note: event will always be DocumentOpen here handleDocOpen(pe); event = ERecvOpen; return true; } else if(state == Open) { QDomElement e; if(pe.type() == Parser::Event::Element) e = pe.element(); return doStep(e); } // Closing else { if(closeWritten) { if(peerClosed) { event = EPeerClosed; return true; } else return handleCloseFinished(); } need = NNotify; notify = NSend; return false; } } void XmlProtocol::setIncomingAsExternal() { for(QList::Iterator it = transferItemList.begin(); it != transferItemList.end(); ++it) { TransferItem &i = *it; // look for elements received if(!i.isString && !i.isSent) i.isExternal = true; } } psi-0.14/iris/src/xmpp/common.pri0000644000175000017500000000005711305557616015073 0ustar janjanOBJECTS_DIR = .obj MOC_DIR = .moc UI_DIR = .ui psi-0.14/iris/src/xmpp/base/0000755000175000017500000000000011305557616013777 5ustar janjanpsi-0.14/iris/src/xmpp/base/base.pri0000644000175000017500000000026711305557616015432 0ustar janjanINCLUDEPATH += $$PWD/../.. DEPENDPATH += $$PWD/../.. HEADERS += \ $$PWD/randomnumbergenerator.h \ $$PWD/randrandomnumbergenerator.h SOURCES += \ $$PWD/randomnumbergenerator.cpp psi-0.14/iris/src/xmpp/base/randomnumbergenerator.h0000644000175000017500000000066111305557616020553 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef RANDOMNUMBERGENERATOR_H #define RANDOMNUMBERGENERATOR_H namespace XMPP { class RandomNumberGenerator { public: virtual ~RandomNumberGenerator(); double generateNumberBetween(double a, double b) const; protected: virtual double generateNumber() const = 0; virtual double getMaximumGeneratedNumber() const = 0; }; } #endif psi-0.14/iris/src/xmpp/base/unittest/0000755000175000017500000000000011305557616015656 5ustar janjanpsi-0.14/iris/src/xmpp/base/unittest/unittest.pri0000644000175000017500000000013511305557616020250 0ustar janjanSOURCES += \ $$PWD/randrandomnumbergeneratortest.cpp \ $$PWD/randomnumbergeneratortest.cpp psi-0.14/iris/src/xmpp/base/unittest/unittest.pro0000644000175000017500000000017211305557616020257 0ustar janjaninclude(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$IRIS_XMPP_BASE_MODULE) include(unittest.pri) psi-0.14/iris/src/xmpp/base/unittest/randrandomnumbergeneratortest.cpp0000644000175000017500000000117111305557616024527 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include #include #include "qttestutil/qttestutil.h" #include "xmpp/base/randrandomnumbergenerator.h" using namespace XMPP; class RandRandomNumberGeneratorTest : public QObject { Q_OBJECT private slots: void testGenerateNumber() { RandRandomNumberGenerator testling; double a = testling.generateNumberBetween(0.0,100.0); double b = testling.generateNumberBetween(0.0,100.0); QVERIFY(a != b); } }; QTTESTUTIL_REGISTER_TEST(RandRandomNumberGeneratorTest); #include "randrandomnumbergeneratortest.moc" psi-0.14/iris/src/xmpp/base/unittest/randomnumbergeneratortest.cpp0000644000175000017500000000234211305557616023663 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include #include #include "qttestutil/qttestutil.h" #include "xmpp/base/randomnumbergenerator.h" using namespace XMPP; class RandomNumberGeneratorTest : public QObject { Q_OBJECT private: class DummyRandomNumberGenerator : public RandomNumberGenerator { public: DummyRandomNumberGenerator(double value, double maximum) : value_(value), maximum_(maximum) {} double generateNumber() const { return value_; } double getMaximumGeneratedNumber() const { return maximum_; } private: double value_; double maximum_; }; private slots: void testGenerateNumberBetween() { DummyRandomNumberGenerator testling(5,10); QCOMPARE(75.0, testling.generateNumberBetween(50.0, 100.0)); } void testGenerateNumberBetween_Minimum() { DummyRandomNumberGenerator testling(0,10); QCOMPARE(0.0, testling.generateNumberBetween(0.0, 100.0)); } void testGenerateNumberBetween_Maximum() { DummyRandomNumberGenerator testling(10,10); QCOMPARE(100.0, testling.generateNumberBetween(0.0, 100.0)); } }; QTTESTUTIL_REGISTER_TEST(RandomNumberGeneratorTest); #include "randomnumbergeneratortest.moc" psi-0.14/iris/src/xmpp/base/unittest/incrementingrandomnumbergenerator.h0000644000175000017500000000141411305557616025032 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef INCREMENTINGRANDOMNUMBERGENERATOR_H #define INCREMENTINGRANDOMNUMBERGENERATOR_H #include #include "xmpp/base/randomnumbergenerator.h" namespace XMPP { class IncrementingRandomNumberGenerator : public RandomNumberGenerator { public: IncrementingRandomNumberGenerator(int maximumNumber = 10) : maximumNumber_(maximumNumber), currentNumber_(maximumNumber_) {} virtual double generateNumber() const { currentNumber_ = (currentNumber_ + 1) % (maximumNumber_ + 1); return currentNumber_; } virtual double getMaximumGeneratedNumber() const { return maximumNumber_; } private: int maximumNumber_; mutable int currentNumber_; }; } #endif psi-0.14/iris/src/xmpp/base/randomnumbergenerator.cpp0000644000175000017500000000060111305557616021100 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include "xmpp/base/randomnumbergenerator.h" #include namespace XMPP { RandomNumberGenerator::~RandomNumberGenerator() { } double RandomNumberGenerator::generateNumberBetween(double a, double b) const { assert(b > a); return a + (generateNumber()/getMaximumGeneratedNumber())*(b-a); } } psi-0.14/iris/src/xmpp/base/randrandomnumbergenerator.h0000644000175000017500000000075311305557616021422 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef RANDRANDOMNUMBERGENERATOR_H #define RANDRANDOMNUMBERGENERATOR_H #include "xmpp/base/randomnumbergenerator.h" namespace XMPP { class RandRandomNumberGenerator : public RandomNumberGenerator { public: RandRandomNumberGenerator() {} virtual double generateNumber() const { return rand(); } virtual double getMaximumGeneratedNumber() const { return RAND_MAX; } }; } #endif psi-0.14/iris/src/xmpp/zlib/0000755000175000017500000000000011305557616014025 5ustar janjanpsi-0.14/iris/src/xmpp/zlib/zlibcompressor.h0000644000175000017500000000072311305557616017255 0ustar janjan#ifndef ZLIBCOMPRESSOR_H #define ZLIBCOMPRESSOR_H #include #include "zlib.h" class QIODevice; class ZLibCompressor : public QObject { Q_OBJECT public: ZLibCompressor(QIODevice* device, int compression = Z_DEFAULT_COMPRESSION); ~ZLibCompressor(); int write(const QByteArray&); protected slots: void flush(); protected: int write(const QByteArray&, bool flush); private: QIODevice* device_; z_stream* zlib_stream_; bool flushed_; }; #endif psi-0.14/iris/src/xmpp/zlib/common.h0000644000175000017500000000060511305557616015467 0ustar janjan#ifndef ZLIB_COMMON_H #define ZLIB_COMMON_H #define CHUNK_SIZE 1024 static void initZStream(z_stream* z) { z->next_in = NULL; z->avail_in = 0; z->total_in = 0; z->next_out = NULL; z->avail_out = 0; z->total_out = 0; z->msg = NULL; z->state = NULL; z->zalloc = Z_NULL; z->zfree = Z_NULL; z->opaque = Z_NULL; z->data_type = Z_BINARY; z->adler = 0; z->reserved = 0; } #endif psi-0.14/iris/src/xmpp/zlib/zlib.pri0000644000175000017500000000027511305557616015505 0ustar janjanINCLUDEPATH *= $$PWD/../.. DEPENDPATH *= $$PWD/../.. HEADERS += \ $$PWD/zlibcompressor.h \ $$PWD/zlibdecompressor.h SOURCES += \ $$PWD/zlibcompressor.cpp \ $$PWD/zlibdecompressor.cpp psi-0.14/iris/src/xmpp/zlib/zlibcompressor.cpp0000644000175000017500000000442711305557616017615 0ustar janjan#include "xmpp/zlib/zlibcompressor.h" #include #include #include #include #include "common.h" ZLibCompressor::ZLibCompressor(QIODevice* device, int compression) : device_(device) { zlib_stream_ = (z_stream*) malloc(sizeof(z_stream)); initZStream(zlib_stream_); int result = deflateInit(zlib_stream_, compression); Q_ASSERT(result == Z_OK); Q_UNUSED(result); connect(device, SIGNAL(aboutToClose()), this, SLOT(flush())); flushed_ = false; } ZLibCompressor::~ZLibCompressor() { flush(); free(zlib_stream_); } void ZLibCompressor::flush() { if (flushed_) return; // Flush write(QByteArray(),true); int result = deflateEnd(zlib_stream_); if (result != Z_OK) qWarning() << QString("compressor.c: deflateEnd failed (%1)").arg(result); flushed_ = true; } int ZLibCompressor::write(const QByteArray& input) { return write(input,false); } int ZLibCompressor::write(const QByteArray& input, bool flush) { int result; zlib_stream_->avail_in = input.size(); zlib_stream_->next_in = (Bytef*) input.data(); QByteArray output; // Write the data int output_position = 0; do { output.resize(output_position + CHUNK_SIZE); zlib_stream_->avail_out = CHUNK_SIZE; zlib_stream_->next_out = (Bytef*) (output.data() + output_position); result = deflate(zlib_stream_,(flush ? Z_FINISH : Z_NO_FLUSH)); if (result == Z_STREAM_ERROR) { qWarning() << QString("compressor.cpp: Error ('%1')").arg(zlib_stream_->msg); return result; } output_position += CHUNK_SIZE; } while (zlib_stream_->avail_out == 0); if (zlib_stream_->avail_in != 0) { qWarning("ZLibCompressor: avail_in != 0"); } output_position -= zlib_stream_->avail_out; // Flush the data if (!flush) { do { output.resize(output_position + CHUNK_SIZE); zlib_stream_->avail_out = CHUNK_SIZE; zlib_stream_->next_out = (Bytef*) (output.data() + output_position); result = deflate(zlib_stream_,Z_SYNC_FLUSH); if (result == Z_STREAM_ERROR) { qWarning() << QString("compressor.cpp: Error ('%1')").arg(zlib_stream_->msg); return result; } output_position += CHUNK_SIZE; } while (zlib_stream_->avail_out == 0); output_position -= zlib_stream_->avail_out; } output.resize(output_position); // Write the compressed data device_->write(output); return 0; } psi-0.14/iris/src/xmpp/zlib/zlibdecompressor.h0000644000175000017500000000066411305557616017572 0ustar janjan#ifndef ZLIBDECOMPRESSOR_H #define ZLIBDECOMPRESSOR_H #include #include "zlib.h" class QIODevice; class ZLibDecompressor : public QObject { Q_OBJECT public: ZLibDecompressor(QIODevice* device); ~ZLibDecompressor(); int write(const QByteArray&); protected slots: void flush(); protected: int write(const QByteArray&, bool flush); private: QIODevice* device_; z_stream* zlib_stream_; bool flushed_; }; #endif psi-0.14/iris/src/xmpp/zlib/zlibdecompressor.cpp0000644000175000017500000000476211305557616020130 0ustar janjan#include "xmpp/zlib/zlibdecompressor.h" #include #include #include #include #include "xmpp/zlib/common.h" ZLibDecompressor::ZLibDecompressor(QIODevice* device) : device_(device) { zlib_stream_ = (z_stream*) malloc(sizeof(z_stream)); initZStream(zlib_stream_); int result = inflateInit(zlib_stream_); Q_ASSERT(result == Z_OK); Q_UNUSED(result); connect(device, SIGNAL(aboutToClose()), this, SLOT(flush())); flushed_ = false; } ZLibDecompressor::~ZLibDecompressor() { flush(); free(zlib_stream_); } void ZLibDecompressor::flush() { if (flushed_) return; // Flush write(QByteArray(),true); int result = inflateEnd(zlib_stream_); if (result != Z_OK) qWarning() << QString("compressor.c: inflateEnd failed (%1)").arg(result); flushed_ = true; } int ZLibDecompressor::write(const QByteArray& input) { return write(input,false); } int ZLibDecompressor::write(const QByteArray& input, bool flush) { int result; zlib_stream_->avail_in = input.size(); zlib_stream_->next_in = (Bytef*) input.data(); QByteArray output; // Write the data int output_position = 0; do { output.resize(output_position + CHUNK_SIZE); zlib_stream_->avail_out = CHUNK_SIZE; zlib_stream_->next_out = (Bytef*) (output.data() + output_position); result = inflate(zlib_stream_,(flush ? Z_FINISH : Z_NO_FLUSH)); if (result == Z_STREAM_ERROR) { qWarning() << QString("compressor.cpp: Error ('%1')").arg(zlib_stream_->msg); return result; } output_position += CHUNK_SIZE; } while (zlib_stream_->avail_out == 0); //Q_ASSERT(zlib_stream_->avail_in == 0); if (zlib_stream_->avail_in != 0) { qWarning() << "ZLibDecompressor: Unexpected state: avail_in=" << zlib_stream_->avail_in << ",avail_out=" << zlib_stream_->avail_out << ",result=" << result; return Z_STREAM_ERROR; // FIXME: Should probably return 'result' } output_position -= zlib_stream_->avail_out; // Flush the data if (!flush) { do { output.resize(output_position + CHUNK_SIZE); zlib_stream_->avail_out = CHUNK_SIZE; zlib_stream_->next_out = (Bytef*) (output.data() + output_position); result = inflate(zlib_stream_,Z_SYNC_FLUSH); if (result == Z_STREAM_ERROR) { qWarning() << QString("compressor.cpp: Error ('%1')").arg(zlib_stream_->msg); return result; } output_position += CHUNK_SIZE; } while (zlib_stream_->avail_out == 0); output_position -= zlib_stream_->avail_out; } output.resize(output_position); // Write the compressed data device_->write(output); return 0; } psi-0.14/iris/src/xmpp/sasl/0000755000175000017500000000000011305557616014027 5ustar janjanpsi-0.14/iris/src/xmpp/sasl/unittest/0000755000175000017500000000000011305557616015706 5ustar janjanpsi-0.14/iris/src/xmpp/sasl/unittest/unittest.pri0000644000175000017500000000011411305557616020275 0ustar janjanSOURCES += \ $$PWD/plainmessagetest.cpp \ $$PWD/digestmd5responsetest.cpp psi-0.14/iris/src/xmpp/sasl/unittest/unittest.pro0000644000175000017500000000046211305557616020311 0ustar janjaninclude(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$IRIS_XMPP_SASL_MODULE) include($$IRIS_XMPP_BASE_MODULE) include($$IRIS_XMPP_BASE64_MODULE) include(unittest.pri) # QCA stuff. # TODO: Remove the dependency on QCA from this module include(../../../../../third-party/qca/qca.pri) psi-0.14/iris/src/xmpp/sasl/unittest/digestmd5responsetest.cpp0000644000175000017500000000406211305557616022760 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include #include #include #include "qttestutil/qttestutil.h" #include "xmpp/sasl/digestmd5response.h" #include "xmpp/base/unittest/incrementingrandomnumbergenerator.h" using namespace XMPP; class DIGESTMD5ResponseTest : public QObject { Q_OBJECT private slots: void testConstructor_WithAuthzid() { DIGESTMD5Response response( "realm=\"example.com\"," "nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\"," "qop=\"auth\",charset=\"utf-8\",algorithm=\"md5-sess\"", "xmpp", "jabber.example.com", "example.com", "myuser", "myuser_authz", "mypass", IncrementingRandomNumberGenerator(255)); QByteArray expectedValue( "username=\"myuser\",realm=\"example.com\"," "nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\"," "cnonce=\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=\"," "nc=00000001," "digest-uri=\"xmpp/jabber.example.com\"," "qop=auth,response=8fe15bc2aa31956b62d9de831b21a5d4," "charset=utf-8,authzid=\"myuser_authz\""); QVERIFY(response.isValid()); QCOMPARE(response.getValue(), expectedValue); } void testConstructor_WithoutAuthzid() { DIGESTMD5Response response( "realm=\"example.com\"," "nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\"," "qop=\"auth\",charset=\"utf-8\",algorithm=\"md5-sess\"", "xmpp", "jabber.example.com", "example.com", "myuser", "", "mypass", IncrementingRandomNumberGenerator(255)); QByteArray expectedValue( "username=\"myuser\",realm=\"example.com\"," "nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\"," "cnonce=\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=\"," "nc=00000001," "digest-uri=\"xmpp/jabber.example.com\"," "qop=auth,response=564b1c1cc16d97b019f18b14c979964b,charset=utf-8"); QVERIFY(response.isValid()); QCOMPARE(response.getValue(), expectedValue); } private: QCA::Initializer initializer; }; QTTESTUTIL_REGISTER_TEST(DIGESTMD5ResponseTest); #include "digestmd5responsetest.moc" psi-0.14/iris/src/xmpp/sasl/unittest/plainmessagetest.cpp0000644000175000017500000000172311305557616021765 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include #include #include "xmpp/sasl/plainmessage.h" #include "qttestutil/qttestutil.h" using namespace XMPP; class PlainMessageTest : public QObject { Q_OBJECT private slots: void testConstructor_WithoutAuthzID() { PLAINMessage message("", QString("user"), "pass"); QCOMPARE(message.getValue(), QByteArray("\0user\0pass", 10)); } void testConstructor_WithAuthzID() { PLAINMessage message(QString("authz"), QString("user"), "pass"); QCOMPARE(message.getValue(), QByteArray("authz\0user\0pass", 15)); } void testConstructor_WithNonASCIICharacters() { PLAINMessage message(QString("authz") + QChar(0x03A8) /* psi */, QString("user") + QChar(0x03A8) /* psi */, "pass"); QCOMPARE(message.getValue(), QByteArray("authz\xCE\xA8\0user\xCE\xA8\0pass", 19)); } }; QTTESTUTIL_REGISTER_TEST(PlainMessageTest); #include "plainmessagetest.moc" psi-0.14/iris/src/xmpp/sasl/digestmd5proplist.h0000644000175000017500000000241511305557616017664 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef DIGESTMD5PROPLIST_H #define DIGESTMD5PROPLIST_H #include #include namespace XMPP { struct DIGESTMD5Prop { QByteArray var, val; }; class DIGESTMD5PropList : public QList { public: DIGESTMD5PropList(); void set(const QByteArray &var, const QByteArray &val); QByteArray get(const QByteArray &var); QByteArray toString() const; bool fromString(const QByteArray &str); private: int varCount(const QByteArray &var); }; } #endif psi-0.14/iris/src/xmpp/sasl/digestmd5proplist.cpp0000644000175000017500000000623611305557616020224 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp/sasl/digestmd5proplist.h" namespace XMPP { DIGESTMD5PropList::DIGESTMD5PropList() : QList() { } void DIGESTMD5PropList::set(const QByteArray &var, const QByteArray &val) { DIGESTMD5Prop p; p.var = var; p.val = val; append(p); } QByteArray DIGESTMD5PropList::get(const QByteArray &var) { for(ConstIterator it = begin(); it != end(); ++it) { if((*it).var == var) return (*it).val; } return QByteArray(); } QByteArray DIGESTMD5PropList::toString() const { QByteArray str; bool first = true; for(ConstIterator it = begin(); it != end(); ++it) { if(!first) str += ','; if ((*it).var == "realm" || (*it).var == "nonce" || (*it).var == "username" || (*it).var == "cnonce" || (*it).var == "digest-uri" || (*it).var == "authzid") str += (*it).var + "=\"" + (*it).val + '\"'; else str += (*it).var + "=" + (*it).val; first = false; } return str; } bool DIGESTMD5PropList::fromString(const QByteArray &str) { DIGESTMD5PropList list; int at = 0; while(1) { while (at < str.length() && (str[at] == ',' || str[at] == ' ' || str[at] == '\t')) ++at; int n = str.indexOf('=', at); if(n == -1) break; QByteArray var, val; var = str.mid(at, n-at); at = n + 1; if(str[at] == '\"') { ++at; n = str.indexOf('\"', at); if(n == -1) break; val = str.mid(at, n-at); at = n + 1; } else { n = at; while (n < str.length() && str[n] != ',' && str[n] != ' ' && str[n] != '\t') ++n; val = str.mid(at, n-at); at = n; } DIGESTMD5Prop prop; prop.var = var; if (var == "qop" || var == "cipher") { int a = 0; while (a < val.length()) { while (a < val.length() && (val[a] == ',' || val[a] == ' ' || val[a] == '\t')) ++a; if (a == val.length()) break; n = a+1; while (n < val.length() && val[n] != ',' && val[n] != ' ' && val[n] != '\t') ++n; prop.val = val.mid(a, n-a); list.append(prop); a = n+1; } } else { prop.val = val; list.append(prop); } if(at >= str.size() - 1 || (str[at] != ',' && str[at] != ' ' && str[at] != '\t')) break; } // integrity check if(list.varCount("nonce") != 1) return false; if(list.varCount("algorithm") != 1) return false; *this = list; return true; } int DIGESTMD5PropList::varCount(const QByteArray &var) { int n = 0; for(ConstIterator it = begin(); it != end(); ++it) { if((*it).var == var) ++n; } return n; } } psi-0.14/iris/src/xmpp/sasl/sasl.pri0000644000175000017500000000037011305557616015505 0ustar janjanINCLUDEPATH *= $$PWD/../.. DEPENDPATH *= $$PWD/../.. HEADERS += \ $$PWD/plainmessage.h \ $$PWD/digestmd5proplist.h \ $$PWD/digestmd5response.h SOURCES += \ $$PWD/plainmessage.cpp \ $$PWD/digestmd5proplist.cpp \ $$PWD/digestmd5response.cpp psi-0.14/iris/src/xmpp/sasl/plainmessage.cpp0000644000175000017500000000047611305557616017212 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include "xmpp/sasl/plainmessage.h" namespace XMPP { PLAINMessage::PLAINMessage(const QString& authzid, const QString& authcid, const QByteArray& password) { value_ = authzid.toUtf8() + '\0' + authcid.toUtf8() + '\0' + password; } } psi-0.14/iris/src/xmpp/sasl/digestmd5response.h0000644000175000017500000000132611305557616017646 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef DIGESTMD5RESPONSE_H #define DIGESTMD5RESPONSE_H #include #include namespace XMPP { class RandomNumberGenerator; class DIGESTMD5Response { public: DIGESTMD5Response( const QByteArray& challenge, const QString& service, const QString& host, const QString& realm, const QString& user, const QString& authz, const QByteArray& password, const RandomNumberGenerator& rand); const QByteArray& getValue() const { return value_; } bool isValid() const { return isValid_; } private: bool isValid_; QByteArray value_; }; } #endif psi-0.14/iris/src/xmpp/sasl/digestmd5response.cpp0000644000175000017500000000500611305557616020200 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include "xmpp/sasl/digestmd5response.h" #include #include #include #include "xmpp/sasl/digestmd5proplist.h" #include "xmpp/base/randomnumbergenerator.h" #include "xmpp/base64/base64.h" namespace XMPP { DIGESTMD5Response::DIGESTMD5Response(const QByteArray& challenge, const QString& service, const QString& host, const QString& arealm, const QString& user, const QString& authz, const QByteArray& password, const RandomNumberGenerator& rand) : isValid_(true) { QString realm = arealm; // get props DIGESTMD5PropList in; if(!in.fromString(challenge)) { isValid_ = false; return; } //qDebug() << (QString("simplesasl.cpp: IN: %1").arg(QString(in.toString()))); // make a cnonce QByteArray a; a.resize(32); for(int n = 0; n < (int)a.size(); ++n) { a[n] = (char) rand.generateNumberBetween(0, 255); } QByteArray cnonce = Base64::encode(a).toLatin1(); // make other variables if (realm.isEmpty()) { realm = QString::fromUtf8(in.get("realm")); } QByteArray nonce = in.get("nonce"); QByteArray nc = "00000001"; QByteArray uri = service.toUtf8() + '/' + host.toUtf8(); QByteArray qop = "auth"; // build 'response' QByteArray X = user.toUtf8() + ':' + realm.toUtf8() + ':' + password; QByteArray Y = QCA::Hash("md5").hash(X).toByteArray(); QByteArray tmp = ':' + nonce + ':' + cnonce; if (!authz.isEmpty()) tmp += ':' + authz.toUtf8(); //qDebug() << (QString(tmp)); QByteArray A1(Y + tmp); QByteArray A2 = QByteArray("AUTHENTICATE:") + uri; QByteArray HA1 = QCA::Hash("md5").hashToString(A1).toLatin1(); QByteArray HA2 = QCA::Hash("md5").hashToString(A2).toLatin1(); QByteArray KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + HA2; QByteArray Z = QCA::Hash("md5").hashToString(KD).toLatin1(); //qDebug() << QString("simplesasl.cpp: A1 = %1").arg(QString(A1)); //qDebug() << QString("simplesasl.cpp: A2 = %1").arg(QString(A2)); //qDebug() << QString("simplesasl.cpp: KD = %1").arg(QString(KD)); // build output DIGESTMD5PropList out; out.set("username", user.toUtf8()); if (!realm.isEmpty()) out.set("realm", realm.toUtf8()); out.set("nonce", nonce); out.set("cnonce", cnonce); out.set("nc", nc); //out.set("serv-type", service.toUtf8()); //out.set("host", host.toUtf8()); out.set("digest-uri", uri); out.set("qop", qop); out.set("response", Z); out.set("charset", "utf-8"); if (!authz.isEmpty()) out.set("authzid", authz.toUtf8()); value_ = out.toString(); } } psi-0.14/iris/src/xmpp/sasl/plainmessage.h0000644000175000017500000000064411305557616016654 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef PLAINMESSAGE_H #define PLAINMESSAGE_H #include #include namespace XMPP { class PLAINMessage { public: PLAINMessage(const QString& authzid, const QString& authcid, const QByteArray& password); const QByteArray& getValue() { return value_; } private: QByteArray value_; }; } #endif psi-0.14/iris/src/xmpp/qa/0000755000175000017500000000000011305557616013466 5ustar janjanpsi-0.14/iris/src/xmpp/qa/unittest.pri0000644000175000017500000000077311305557616016070 0ustar janjan# # Declares all common settings/includes for a unittest module. # # Include this file from your module's unittest project file to create a # standalone checker for the module. # include($$PWD/qttestutil/qttestutil.pri) include($$PWD/../common.pri) QT += testlib QT -= gui CONFIG -= app_bundle INCLUDEPATH *= $$PWD DEPENDPATH *= $$PWD TARGET = checker SOURCES += \ $$PWD/qttestutil/simplechecker.cpp QMAKE_EXTRA_TARGETS = check check.commands = \$(MAKE) && ./checker QMAKE_CLEAN += $(QMAKE_TARGET) psi-0.14/iris/src/xmpp/qa/README0000644000175000017500000000227011305557616014347 0ustar janjanHow to add unit tests to a module --------------------------------- - Copy the qa/unittest.template module to the module dir, and rename it to 'unittest'. Be careful not to copy '.svn'. - Create a file test.cpp for every class, and implement the tests for each method.. See 'myclasstest.cpp' for a template. - Add every test.cpp file to 'unittest.pri' - In 'unittest.pro', replace '$$MYMODULE' with the name of the module that you are unit testing. Also include all the modules that are required to compile a standalone checker for the module under test. - Add an 'include' line to the list of unit tests in qa/unittests.pri. This is used to compile the full unit test suite of all modules. - Make sure 'qa/unittests.pro' contains the module under test, and make sure that it compiles and runs fine. How to run the unit tests of a specific module ---------------------------------------------- In the 'unittest' subdir of a module, run 'qmake', and then run 'make check' to build and run the standalone checker for the module. How to run all unit tests ------------------------- First, make sure Iris has been built. Go to qa/unittests, run 'qmake', and run 'make check'. psi-0.14/iris/src/xmpp/qa/unittests/0000755000175000017500000000000011305557616015530 5ustar janjanpsi-0.14/iris/src/xmpp/qa/unittests/unittests.pro0000644000175000017500000000021211305557616020307 0ustar janjaninclude(../../../../iris.pri) include(../unittests.pri) include(../unittest.pri) # FIXME include(../../../../../third-party/qca/qca.pri) psi-0.14/iris/src/xmpp/qa/unittests.pri0000644000175000017500000000016611305557616016247 0ustar janjan# All available unit tests include($$PWD/../base/unittest/unittest.pri) include($$PWD/../sasl/unittest/unittest.pri) psi-0.14/iris/src/xmpp/qa/unittest.template/0000755000175000017500000000000011305557616017157 5ustar janjanpsi-0.14/iris/src/xmpp/qa/unittest.template/unittest.pri0000644000175000017500000000004411305557616021550 0ustar janjanSOURCES += \ $$PWD/myclasstest.cpp psi-0.14/iris/src/xmpp/qa/unittest.template/myclasstest.cpp0000644000175000017500000000066011305557616022240 0ustar janjan/* * Copyright (C) 2008 * See COPYING for license details. */ #include #include #include "qttestutil/qttestutil.h" class MyClassTest : public QObject { Q_OBJECT private slots: void initTestCase() { } void cleanupTestCase() { } void testMyMethod() { //QCOMPARE(foo, bar); //QVERIFY(baz); } }; QTTESTUTIL_REGISTER_TEST(MyClassTest); #include "myclasstest.moc" psi-0.14/iris/src/xmpp/qa/unittest.template/unittest.pro0000644000175000017500000000015511305557616021561 0ustar janjaninclude(../../modules.pri) include($$IRIS_XMPP_QA_UNITTEST_MODULE) include($$MYMODULE) include(unittest.pri) psi-0.14/iris/src/xmpp/qa/qttestutil/0000755000175000017500000000000011305557616015710 5ustar janjanpsi-0.14/iris/src/xmpp/qa/qttestutil/simplechecker.cpp0000644000175000017500000000055611305557616021240 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include #include "qttestutil/testregistry.h" /** * Runs all tests registered with the QtTestUtil registry. */ int main(int argc, char* argv[]) { QCoreApplication application(argc, argv); return QtTestUtil::TestRegistry::getInstance()->runTests(argc, argv); } psi-0.14/iris/src/xmpp/qa/qttestutil/testregistry.cpp0000644000175000017500000000077311305557616021173 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #include "qttestutil/testregistry.h" #include namespace QtTestUtil { TestRegistry* TestRegistry::getInstance() { static TestRegistry registry; return ®istry; } void TestRegistry::registerTest(QObject* test) { tests_ += test; } int TestRegistry::runTests(int argc, char* argv[]) { int result = 0; foreach(QObject* test, tests_) { result |= QTest::qExec(test, argc, argv); } return result; } } psi-0.14/iris/src/xmpp/qa/qttestutil/testregistry.h0000644000175000017500000000166411305557616020640 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef QTTESTUTIL_TESTREGISTRY_H #define QTTESTUTIL_TESTREGISTRY_H #include class QObject; namespace QtTestUtil { /** * A registry of QtTest test classes. * All test classes registered with QTTESTUTIL_REGISTER_TEST add * themselves to this registry. All registered tests can then be run at * once using runTests(). */ class TestRegistry { public: /** * Retrieve the single instance of the registry. */ static TestRegistry* getInstance(); /** * Register a QtTest test. * This method is called by QTTESTUTIL_REGISTER_TEST, and you should * not use this method directly. */ void registerTest(QObject*); /** * Run all registered tests using QTest::qExec() */ int runTests(int argc, char* argv[]); private: TestRegistry() {} private: QList tests_; }; } #endif psi-0.14/iris/src/xmpp/qa/qttestutil/qttestutil.pri0000644000175000017500000000012511305557616020644 0ustar janjanINCLUDEPATH *= $$PWD/.. DEPENDPATH *= $$PWD/.. SOURCES += \ $$PWD/testregistry.cpp psi-0.14/iris/src/xmpp/qa/qttestutil/qttestutil.h0000644000175000017500000000117511305557616020307 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef QTTESTUTIL_H #define QTTESTUTIL_H #include "qttestutil/testregistration.h" /** * A macro to register a test class. * * This macro will create a static variable which registers the * testclass with the TestRegistry, and creates an instance of the * test class. * * Execute this macro in the body of your unit test's .cpp file, e.g. * class MyTest { * ... * }; * * QTTESTUTIL_REGISTER_TEST(MyTest) */ #define QTTESTUTIL_REGISTER_TEST(TestClass) \ static QtTestUtil::TestRegistration TestClass##Registration #endif psi-0.14/iris/src/xmpp/qa/qttestutil/testregistration.h0000644000175000017500000000132711305557616021476 0ustar janjan/* * Copyright (C) 2008 Remko Troncon * See COPYING for license details. */ #ifndef QTTESTUTIL_TESTREGISTRATION_H #define QTTESTUTIL_TESTREGISTRATION_H #include "qttestutil/testregistry.h" namespace QtTestUtil { /** * A wrapper class around a test to manage registration and static * creation of an instance of the test class. * This class is used by QTTESTUTIL_REGISTER_TEST(), and you should not * use this class directly. */ template class TestRegistration { public: TestRegistration() { test_ = new TestClass(); TestRegistry::getInstance()->registerTest(test_); } ~TestRegistration() { delete test_; } private: TestClass* test_; }; } #endif psi-0.14/iris/src/xmpp/qa/qttestutil/example/0000755000175000017500000000000011305557616017343 5ustar janjanpsi-0.14/iris/src/xmpp/qa/qttestutil/example/example.pro0000644000175000017500000000063711305557616021526 0ustar janjan# # Example unit test module with 2 unit test suites. # include(../qttestutil.pri) QT += testlib QT -= gui CONFIG -= app_bundle TARGET = checker SOURCES += \ myfirstclasstest.cpp \ mysecondclasstest.cpp \ ../simplechecker.cpp # Add an extra 'make check' target. QMAKE_EXTRA_TARGETS = check check.commands = \$(MAKE) && ./$(QMAKE_TARGET) # Cleanup the checker on 'make clean' QMAKE_CLEAN += $(QMAKE_TARGET) psi-0.14/iris/src/xmpp/qa/qttestutil/example/mysecondclasstest.cpp0000644000175000017500000000055011305557616023616 0ustar janjan#include #include #include "qttestutil/qttestutil.h" class MySecondClassTest : public QObject { Q_OBJECT private slots: void initTestCase() { } void cleanupTestCase() { } void testMyMethod() { QCOMPARE(1, 0); // Dummy test } }; QTTESTUTIL_REGISTER_TEST(MySecondClassTest); #include "mysecondclasstest.moc" psi-0.14/iris/src/xmpp/qa/qttestutil/example/myfirstclasstest.cpp0000644000175000017500000000054511305557616023476 0ustar janjan#include #include #include "qttestutil/qttestutil.h" class MyFirstClassTest : public QObject { Q_OBJECT private slots: void initTestCase() { } void cleanupTestCase() { } void testMyMethod() { QCOMPARE(1, 1); // Dummy test } }; QTTESTUTIL_REGISTER_TEST(MyFirstClassTest); #include "myfirstclasstest.moc" psi-0.14/iris/src/xmpp/xmpp-im/0000755000175000017500000000000011305557616014454 5ustar janjanpsi-0.14/iris/src/xmpp/xmpp-im/xmpp_resource.h0000644000175000017500000000231211305557616017516 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_RESOURCE_H #define XMPP_RESOURCE_H #include #include "xmpp_status.h" namespace XMPP { class Resource { public: Resource(const QString &name="", const Status &s=Status()); ~Resource(); const QString & name() const; int priority() const; const Status & status() const; void setName(const QString &); void setStatus(const Status &); private: QString v_name; Status v_status; }; } #endif psi-0.14/iris/src/xmpp/xmpp-im/xmpp_roster.h0000644000175000017500000000222011305557616017203 0ustar janjan/* * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_ROSTER_H #define XMPP_ROSTER_H #include #include "xmpp_rosteritem.h" class QDomDocument; class QDomElement; namespace XMPP { class Jid; class Roster : public QList { public: Roster(); ~Roster(); Roster::Iterator find(const Jid &); Roster::ConstIterator find(const Jid &) const; private: class RosterPrivate *d; }; } #endif psi-0.14/iris/src/xmpp/xmpp-im/xmpp_tasks.cpp0000644000175000017500000012372611305557616017364 0ustar janjan/* * tasks.cpp - basic tasks * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_tasks.h" //#include //#include "sha1.h" #include "xmpp_xmlcommon.h" //#include "xmpp_stream.h" //#include "xmpp_types.h" #include "xmpp_vcard.h" #include #include using namespace XMPP; static QString lineEncode(QString str) { str.replace(QRegExp("\\\\"), "\\\\"); // backslash to double-backslash str.replace(QRegExp("\\|"), "\\p"); // pipe to \p str.replace(QRegExp("\n"), "\\n"); // newline to \n return str; } static QString lineDecode(const QString &str) { QString ret; for(int n = 0; n < str.length(); ++n) { if(str.at(n) == '\\') { ++n; if(n >= str.length()) break; if(str.at(n) == 'n') ret.append('\n'); if(str.at(n) == 'p') ret.append('|'); if(str.at(n) == '\\') ret.append('\\'); } else { ret.append(str.at(n)); } } return ret; } static Roster xmlReadRoster(const QDomElement &q, bool push) { Roster r; for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { RosterItem item; item.fromXml(i); if(push) item.setIsPush(true); r += item; } } return r; } //---------------------------------------------------------------------------- // JT_Session //---------------------------------------------------------------------------- // #include "protocol.h" JT_Session::JT_Session(Task *parent) : Task(parent) { } void JT_Session::onGo() { QDomElement iq = createIQ(doc(), "set", "", id()); QDomElement session = doc()->createElement("session"); session.setAttribute("xmlns",NS_SESSION); iq.appendChild(session); send(iq); } bool JT_Session::take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_Register //---------------------------------------------------------------------------- class JT_Register::Private { public: Private() {} Form form; XData xdata; bool hasXData; Jid jid; int type; }; JT_Register::JT_Register(Task *parent) :Task(parent) { d = new Private; d->type = -1; d->hasXData = false; } JT_Register::~JT_Register() { delete d; } void JT_Register::reg(const QString &user, const QString &pass) { d->type = 0; to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); query.appendChild(textTag(doc(), "username", user)); query.appendChild(textTag(doc(), "password", pass)); } void JT_Register::changepw(const QString &pass) { d->type = 1; to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); query.appendChild(textTag(doc(), "username", client()->user())); query.appendChild(textTag(doc(), "password", pass)); } void JT_Register::unreg(const Jid &j) { d->type = 2; to = j.isEmpty() ? client()->host() : j.full(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); // this may be useful if(!d->form.key().isEmpty()) query.appendChild(textTag(doc(), "key", d->form.key())); query.appendChild(doc()->createElement("remove")); } void JT_Register::getForm(const Jid &j) { d->type = 3; to = j; iq = createIQ(doc(), "get", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); } void JT_Register::setForm(const Form &form) { d->type = 4; to = form.jid(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); // key? if(!form.key().isEmpty()) query.appendChild(textTag(doc(), "key", form.key())); // fields for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) { const FormField &f = *it; query.appendChild(textTag(doc(), f.realName(), f.value())); } } void JT_Register::setForm(const Jid& to, const XData& xdata) { d->type = 4; iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); query.appendChild(xdata.toXml(doc(), true)); } const Form & JT_Register::form() const { return d->form; } bool JT_Register::hasXData() const { return d->hasXData; } const XData& JT_Register::xdata() const { return d->xdata; } void JT_Register::onGo() { send(iq); } bool JT_Register::take(const QDomElement &x) { if(!iqVerify(x, to, id())) return false; Jid from(x.attribute("from")); if(x.attribute("type") == "result") { if(d->type == 3) { d->form.clear(); d->form.setJid(from); QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "instructions") d->form.setInstructions(tagContent(i)); else if(i.tagName() == "key") d->form.setKey(tagContent(i)); else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") { d->xdata.fromXml(i); d->hasXData = true; } else { FormField f; if(f.setType(i.tagName())) { f.setValue(tagContent(i)); d->form += f; } } } } setSuccess(); } else setError(x); return true; } //---------------------------------------------------------------------------- // JT_UnRegister //---------------------------------------------------------------------------- class JT_UnRegister::Private { public: Private() { } Jid j; JT_Register *jt_reg; }; JT_UnRegister::JT_UnRegister(Task *parent) : Task(parent) { d = new Private; d->jt_reg = 0; } JT_UnRegister::~JT_UnRegister() { delete d->jt_reg; delete d; } void JT_UnRegister::unreg(const Jid &j) { d->j = j; } void JT_UnRegister::onGo() { delete d->jt_reg; d->jt_reg = new JT_Register(this); d->jt_reg->getForm(d->j); connect(d->jt_reg, SIGNAL(finished()), SLOT(getFormFinished())); d->jt_reg->go(false); } void JT_UnRegister::getFormFinished() { disconnect(d->jt_reg, 0, this, 0); d->jt_reg->unreg(d->j); connect(d->jt_reg, SIGNAL(finished()), SLOT(unregFinished())); d->jt_reg->go(false); } void JT_UnRegister::unregFinished() { if ( d->jt_reg->success() ) setSuccess(); else setError(d->jt_reg->statusCode(), d->jt_reg->statusString()); delete d->jt_reg; d->jt_reg = 0; } //---------------------------------------------------------------------------- // JT_Roster //---------------------------------------------------------------------------- class JT_Roster::Private { public: Private() {} Roster roster; QList itemList; }; JT_Roster::JT_Roster(Task *parent) :Task(parent) { type = -1; d = new Private; } JT_Roster::~JT_Roster() { delete d; } void JT_Roster::get() { type = 0; //to = client()->host(); iq = createIQ(doc(), "get", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:roster"); iq.appendChild(query); } void JT_Roster::set(const Jid &jid, const QString &name, const QStringList &groups) { type = 1; //to = client()->host(); QDomElement item = doc()->createElement("item"); item.setAttribute("jid", jid.full()); if(!name.isEmpty()) item.setAttribute("name", name); for(QStringList::ConstIterator it = groups.begin(); it != groups.end(); ++it) item.appendChild(textTag(doc(), "group", *it)); d->itemList += item; } void JT_Roster::remove(const Jid &jid) { type = 1; //to = client()->host(); QDomElement item = doc()->createElement("item"); item.setAttribute("jid", jid.full()); item.setAttribute("subscription", "remove"); d->itemList += item; } void JT_Roster::onGo() { if(type == 0) send(iq); else if(type == 1) { //to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:roster"); iq.appendChild(query); for(QList::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it) query.appendChild(*it); send(iq); } } const Roster & JT_Roster::roster() const { return d->roster; } QString JT_Roster::toString() const { if(type != 1) return ""; QDomElement i = doc()->createElement("request"); i.setAttribute("type", "JT_Roster"); for(QList::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it) i.appendChild(*it); return lineEncode(Stream::xmlToString(i)); return ""; } bool JT_Roster::fromString(const QString &str) { QDomDocument *dd = new QDomDocument; if(!dd->setContent(lineDecode(str).toUtf8())) return false; QDomElement e = doc()->importNode(dd->documentElement(), true).toElement(); delete dd; if(e.tagName() != "request" || e.attribute("type") != "JT_Roster") return false; type = 1; d->itemList.clear(); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; d->itemList += i; } return true; } bool JT_Roster::take(const QDomElement &x) { if(!iqVerify(x, client()->host(), id())) return false; // get if(type == 0) { if(x.attribute("type") == "result") { QDomElement q = queryTag(x); d->roster = xmlReadRoster(q, false); setSuccess(); } else { setError(x); } return true; } // set else if(type == 1) { if(x.attribute("type") == "result") setSuccess(); else setError(x); return true; } // remove else if(type == 2) { setSuccess(); return true; } return false; } //---------------------------------------------------------------------------- // JT_PushRoster //---------------------------------------------------------------------------- JT_PushRoster::JT_PushRoster(Task *parent) :Task(parent) { } JT_PushRoster::~JT_PushRoster() { } bool JT_PushRoster::take(const QDomElement &e) { // must be an iq-set tag if(e.tagName() != "iq" || e.attribute("type") != "set") return false; if(!iqVerify(e, client()->host(), "", "jabber:iq:roster")) return false; roster(xmlReadRoster(queryTag(e), true)); send(createIQ(doc(), "result", e.attribute("from"), e.attribute("id"))); return true; } //---------------------------------------------------------------------------- // JT_Presence //---------------------------------------------------------------------------- JT_Presence::JT_Presence(Task *parent) :Task(parent) { type = -1; } JT_Presence::~JT_Presence() { } void JT_Presence::pres(const Status &s) { type = 0; tag = doc()->createElement("presence"); if(!s.isAvailable()) { tag.setAttribute("type", "unavailable"); if(!s.status().isEmpty()) tag.appendChild(textTag(doc(), "status", s.status())); } else { if(s.isInvisible()) tag.setAttribute("type", "invisible"); if(!s.show().isEmpty()) tag.appendChild(textTag(doc(), "show", s.show())); if(!s.status().isEmpty()) tag.appendChild(textTag(doc(), "status", s.status())); tag.appendChild( textTag(doc(), "priority", QString("%1").arg(s.priority()) ) ); if(!s.keyID().isEmpty()) { QDomElement x = textTag(doc(), "x", s.keyID()); x.setAttribute("xmlns", "http://jabber.org/protocol/e2e"); tag.appendChild(x); } if(!s.xsigned().isEmpty()) { QDomElement x = textTag(doc(), "x", s.xsigned()); x.setAttribute("xmlns", "jabber:x:signed"); tag.appendChild(x); } if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) { QDomElement c = doc()->createElement("c"); c.setAttribute("xmlns","http://jabber.org/protocol/caps"); c.setAttribute("node",s.capsNode()); c.setAttribute("ver",s.capsVersion()); if (!s.capsExt().isEmpty()) c.setAttribute("ext",s.capsExt()); tag.appendChild(c); } if(s.isMUC()) { QDomElement m = doc()->createElement("x"); m.setAttribute("xmlns","http://jabber.org/protocol/muc"); if (!s.mucPassword().isEmpty()) { m.appendChild(textTag(doc(),"password",s.mucPassword())); } if (s.hasMUCHistory()) { QDomElement h = doc()->createElement("history"); if (s.mucHistoryMaxChars() >= 0) h.setAttribute("maxchars",s.mucHistoryMaxChars()); if (s.mucHistoryMaxStanzas() >= 0) h.setAttribute("maxstanzas",s.mucHistoryMaxStanzas()); if (s.mucHistorySeconds() >= 0) h.setAttribute("seconds",s.mucHistorySeconds()); m.appendChild(h); } tag.appendChild(m); } if(s.hasPhotoHash()) { QDomElement m = doc()->createElement("x"); m.setAttribute("xmlns", "vcard-temp:x:update"); m.appendChild(textTag(doc(), "photo", s.photoHash())); tag.appendChild(m); } } } void JT_Presence::pres(const Jid &to, const Status &s) { pres(s); tag.setAttribute("to", to.full()); } void JT_Presence::sub(const Jid &to, const QString &subType, const QString& nick) { type = 1; tag = doc()->createElement("presence"); tag.setAttribute("to", to.full()); tag.setAttribute("type", subType); if (!nick.isEmpty()) { QDomElement nick_tag = textTag(doc(),"nick",nick); nick_tag.setAttribute("xmlns","http://jabber.org/protocol/nick"); tag.appendChild(nick_tag); } } void JT_Presence::probe(const Jid &to) { type = 2; tag = doc()->createElement("presence"); tag.setAttribute("to", to.full()); tag.setAttribute("type", "probe"); } void JT_Presence::onGo() { send(tag); setSuccess(); } //---------------------------------------------------------------------------- // JT_PushPresence //---------------------------------------------------------------------------- JT_PushPresence::JT_PushPresence(Task *parent) :Task(parent) { } JT_PushPresence::~JT_PushPresence() { } bool JT_PushPresence::take(const QDomElement &e) { if(e.tagName() != "presence") return false; Jid j(e.attribute("from")); Status p; if(e.hasAttribute("type")) { QString type = e.attribute("type"); if(type == "unavailable") { p.setIsAvailable(false); } else if(type == "error") { QString str = ""; int code = 0; getErrorFromElement(e, client()->stream().baseNS(), &code, &str); p.setError(code, str); } else if(type == "subscribe" || type == "subscribed" || type == "unsubscribe" || type == "unsubscribed") { QString nick; bool found; QDomElement tag = findSubTag(e, "nick", &found); if (found && tag.attribute("xmlns") == "http://jabber.org/protocol/nick") { nick = tagContent(tag); } subscription(j, type, nick); return true; } } QDomElement tag; bool found; tag = findSubTag(e, "status", &found); if(found) p.setStatus(tagContent(tag)); tag = findSubTag(e, "show", &found); if(found) p.setShow(tagContent(tag)); tag = findSubTag(e, "priority", &found); if(found) p.setPriority(tagContent(tag).toInt()); QDateTime stamp; for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:delay") { if(i.hasAttribute("stamp") && !stamp.isValid()) { stamp = stamp2TS(i.attribute("stamp")); } } else if(i.tagName() == "delay" && i.attribute("xmlns") == "urn:xmpp:delay") { if(i.hasAttribute("stamp") && !stamp.isValid()) { stamp = QDateTime::fromString(i.attribute("stamp").left(19), Qt::ISODate); } } else if(i.tagName() == "x" && i.attribute("xmlns") == "gabber:x:music:info") { QDomElement t; bool found; QString title, state; t = findSubTag(i, "title", &found); if(found) title = tagContent(t); t = findSubTag(i, "state", &found); if(found) state = tagContent(t); if(!title.isEmpty() && state == "playing") p.setSongTitle(title); } else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:signed") { p.setXSigned(tagContent(i)); } else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/e2e") { p.setKeyID(tagContent(i)); } else if(i.tagName() == "c" && i.attribute("xmlns") == "http://jabber.org/protocol/caps") { p.setCapsNode(i.attribute("node")); p.setCapsVersion(i.attribute("ver")); p.setCapsExt(i.attribute("ext")); } else if(i.tagName() == "x" && i.attribute("xmlns") == "vcard-temp:x:update") { QDomElement t; bool found; t = findSubTag(i, "photo", &found); if (found) p.setPhotoHash(tagContent(t)); else p.setPhotoHash(""); } else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/muc#user") { for(QDomNode muc_n = i.firstChild(); !muc_n.isNull(); muc_n = muc_n.nextSibling()) { QDomElement muc_e = muc_n.toElement(); if(muc_e.isNull()) continue; if (muc_e.tagName() == "item") p.setMUCItem(MUCItem(muc_e)); else if (muc_e.tagName() == "status") p.addMUCStatus(muc_e.attribute("code").toInt()); else if (muc_e.tagName() == "destroy") p.setMUCDestroy(MUCDestroy(muc_e)); } } } if (stamp.isValid()) { if (client()->manualTimeZoneOffset()) { stamp = stamp.addSecs(client()->timeZoneOffset() * 3600); } else { stamp.setTimeSpec(Qt::UTC); stamp = stamp.toLocalTime(); } p.setTimeStamp(stamp); } presence(j, p); return true; } //---------------------------------------------------------------------------- // JT_Message //---------------------------------------------------------------------------- static QDomElement oldStyleNS(const QDomElement &e) { // find closest parent with a namespace QDomNode par = e.parentNode(); while(!par.isNull() && par.namespaceURI().isNull()) par = par.parentNode(); bool noShowNS = false; if(!par.isNull() && par.namespaceURI() == e.namespaceURI()) noShowNS = true; QDomElement i; int x; //if(noShowNS) i = e.ownerDocument().createElement(e.tagName()); //else // i = e.ownerDocument().createElementNS(e.namespaceURI(), e.tagName()); // copy attributes QDomNamedNodeMap al = e.attributes(); for(x = 0; x < al.count(); ++x) i.setAttributeNode(al.item(x).cloneNode().toAttr()); if(!noShowNS) i.setAttribute("xmlns", e.namespaceURI()); // copy children QDomNodeList nl = e.childNodes(); for(x = 0; x < nl.count(); ++x) { QDomNode n = nl.item(x); if(n.isElement()) i.appendChild(oldStyleNS(n.toElement())); else i.appendChild(n.cloneNode()); } return i; } JT_Message::JT_Message(Task *parent, const Message &msg) :Task(parent) { m = msg; if (m.id().isEmpty()) m.setId(id()); } JT_Message::~JT_Message() { } void JT_Message::onGo() { Stanza s = m.toStanza(&(client()->stream())); QDomElement e = oldStyleNS(s.element()); send(e); setSuccess(); } //---------------------------------------------------------------------------- // JT_PushMessage //---------------------------------------------------------------------------- JT_PushMessage::JT_PushMessage(Task *parent) :Task(parent) { } JT_PushMessage::~JT_PushMessage() { } bool JT_PushMessage::take(const QDomElement &e) { if(e.tagName() != "message") return false; Stanza s = client()->stream().createStanza(addCorrectNS(e)); if(s.isNull()) { //printf("take: bad stanza??\n"); return false; } Message m; if(!m.fromStanza(s, client()->manualTimeZoneOffset(), client()->timeZoneOffset())) { //printf("bad message\n"); return false; } message(m); return true; } //---------------------------------------------------------------------------- // JT_GetServices //---------------------------------------------------------------------------- JT_GetServices::JT_GetServices(Task *parent) :Task(parent) { } void JT_GetServices::get(const Jid &j) { agentList.clear(); jid = j; iq = createIQ(doc(), "get", jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:agents"); iq.appendChild(query); } const AgentList & JT_GetServices::agents() const { return agentList; } void JT_GetServices::onGo() { send(iq); } bool JT_GetServices::take(const QDomElement &x) { if(!iqVerify(x, jid, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); // agents for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "agent") { AgentItem a; a.setJid(Jid(i.attribute("jid"))); QDomElement tag; bool found; tag = findSubTag(i, "name", &found); if(found) a.setName(tagContent(tag)); // determine which namespaces does item support QStringList ns; tag = findSubTag(i, "register", &found); if(found) ns << "jabber:iq:register"; tag = findSubTag(i, "search", &found); if(found) ns << "jabber:iq:search"; tag = findSubTag(i, "groupchat", &found); if(found) ns << "jabber:iq:conference"; tag = findSubTag(i, "transport", &found); if(found) ns << "jabber:iq:gateway"; a.setFeatures(ns); agentList += a; } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_VCard //---------------------------------------------------------------------------- class JT_VCard::Private { public: Private() {} QDomElement iq; Jid jid; VCard vcard; }; JT_VCard::JT_VCard(Task *parent) :Task(parent) { type = -1; d = new Private; } JT_VCard::~JT_VCard() { delete d; } void JT_VCard::get(const Jid &_jid) { type = 0; d->jid = _jid; d->iq = createIQ(doc(), "get", type == 1 ? Jid().full() : d->jid.full(), id()); QDomElement v = doc()->createElement("vCard"); v.setAttribute("xmlns", "vcard-temp"); v.setAttribute("version", "2.0"); v.setAttribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); d->iq.appendChild(v); } const Jid & JT_VCard::jid() const { return d->jid; } const VCard & JT_VCard::vcard() const { return d->vcard; } void JT_VCard::set(const VCard &card) { type = 1; d->vcard = card; d->jid = ""; d->iq = createIQ(doc(), "set", d->jid.full(), id()); d->iq.appendChild(card.toXml(doc()) ); } void JT_VCard::set(const Jid &j, const VCard &card) { type = 1; d->vcard = card; d->jid = j; d->iq = createIQ(doc(), "set", "", id()); d->iq.appendChild(card.toXml(doc()) ); } void JT_VCard::onGo() { send(d->iq); } bool JT_VCard::take(const QDomElement &x) { Jid to = d->jid; if (to.bare() == client()->jid().bare()) to = client()->host(); if(!iqVerify(x, to, id())) return false; if(x.attribute("type") == "result") { if(type == 0) { for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement q = n.toElement(); if(q.isNull()) continue; if(q.tagName().toUpper() == "VCARD") { if(d->vcard.fromXml(q)) { setSuccess(); return true; } } } setError(ErrDisc + 1, tr("No VCard available")); return true; } else { setSuccess(); return true; } } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_Search //---------------------------------------------------------------------------- class JT_Search::Private { public: Private() {} Jid jid; Form form; bool hasXData; XData xdata; QList resultList; }; JT_Search::JT_Search(Task *parent) :Task(parent) { d = new Private; type = -1; } JT_Search::~JT_Search() { delete d; } void JT_Search::get(const Jid &jid) { type = 0; d->jid = jid; d->hasXData = false; d->xdata = XData(); iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:search"); iq.appendChild(query); } void JT_Search::set(const Form &form) { type = 1; d->jid = form.jid(); d->hasXData = false; d->xdata = XData(); iq = createIQ(doc(), "set", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:search"); iq.appendChild(query); // key? if(!form.key().isEmpty()) query.appendChild(textTag(doc(), "key", form.key())); // fields for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) { const FormField &f = *it; query.appendChild(textTag(doc(), f.realName(), f.value())); } } void JT_Search::set(const Jid &jid, const XData &form) { type = 1; d->jid = jid; d->hasXData = false; d->xdata = XData(); iq = createIQ(doc(), "set", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:search"); iq.appendChild(query); query.appendChild(form.toXml(doc(), true)); } const Form & JT_Search::form() const { return d->form; } const QList & JT_Search::results() const { return d->resultList; } bool JT_Search::hasXData() const { return d->hasXData; } const XData & JT_Search::xdata() const { return d->xdata; } void JT_Search::onGo() { send(iq); } bool JT_Search::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; Jid from(x.attribute("from")); if(x.attribute("type") == "result") { if(type == 0) { d->form.clear(); d->form.setJid(from); QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "instructions") d->form.setInstructions(tagContent(i)); else if(i.tagName() == "key") d->form.setKey(tagContent(i)); else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") { d->xdata.fromXml(i); d->hasXData = true; } else { FormField f; if(f.setType(i.tagName())) { f.setValue(tagContent(i)); d->form += f; } } } } else { d->resultList.clear(); QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { SearchResult r(Jid(i.attribute("jid"))); QDomElement tag; bool found; tag = findSubTag(i, "nick", &found); if(found) r.setNick(tagContent(tag)); tag = findSubTag(i, "first", &found); if(found) r.setFirst(tagContent(tag)); tag = findSubTag(i, "last", &found); if(found) r.setLast(tagContent(tag)); tag = findSubTag(i, "email", &found); if(found) r.setEmail(tagContent(tag)); d->resultList += r; } else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") { d->xdata.fromXml(i); d->hasXData = true; } } } setSuccess(); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_ClientVersion //---------------------------------------------------------------------------- JT_ClientVersion::JT_ClientVersion(Task *parent) :Task(parent) { } void JT_ClientVersion::get(const Jid &jid) { j = jid; iq = createIQ(doc(), "get", j.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:version"); iq.appendChild(query); } void JT_ClientVersion::onGo() { send(iq); } bool JT_ClientVersion::take(const QDomElement &x) { if(!iqVerify(x, j, id())) return false; if(x.attribute("type") == "result") { bool found; QDomElement q = queryTag(x); QDomElement tag; tag = findSubTag(q, "name", &found); if(found) v_name = tagContent(tag); tag = findSubTag(q, "version", &found); if(found) v_ver = tagContent(tag); tag = findSubTag(q, "os", &found); if(found) v_os = tagContent(tag); setSuccess(); } else { setError(x); } return true; } const Jid & JT_ClientVersion::jid() const { return j; } const QString & JT_ClientVersion::name() const { return v_name; } const QString & JT_ClientVersion::version() const { return v_ver; } const QString & JT_ClientVersion::os() const { return v_os; } //---------------------------------------------------------------------------- // JT_ClientTime //---------------------------------------------------------------------------- /*JT_ClientTime::JT_ClientTime(Task *parent, const Jid &_j) :Task(parent) { j = _j; iq = createIQ("get", j.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:time"); iq.appendChild(query); } void JT_ClientTime::go() { send(iq); } bool JT_ClientTime::take(const QDomElement &x) { if(x.attribute("id") != id()) return FALSE; if(x.attribute("type") == "result") { bool found; QDomElement q = queryTag(x); QDomElement tag; tag = findSubTag(q, "utc", &found); if(found) stamp2TS(tagContent(tag), &utc); tag = findSubTag(q, "tz", &found); if(found) timezone = tagContent(tag); tag = findSubTag(q, "display", &found); if(found) display = tagContent(tag); setSuccess(TRUE); } else { setError(getErrorString(x)); setSuccess(FALSE); } return TRUE; } */ //---------------------------------------------------------------------------- // JT_ServInfo //---------------------------------------------------------------------------- JT_ServInfo::JT_ServInfo(Task *parent) :Task(parent) { } JT_ServInfo::~JT_ServInfo() { } bool JT_ServInfo::take(const QDomElement &e) { if(e.tagName() != "iq" || e.attribute("type") != "get") return false; QString ns = queryNS(e); if(ns == "jabber:iq:version") { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:version"); iq.appendChild(query); query.appendChild(textTag(doc(), "name", client()->clientName())); query.appendChild(textTag(doc(), "version", client()->clientVersion())); query.appendChild(textTag(doc(), "os", client()->OSName())); send(iq); return true; } //else if(ns == "jabber:iq:time") { // QDomElement iq = createIQ("result", e.attribute("from"), e.attribute("id")); // QDomElement query = doc()->createElement("query"); // query.setAttribute("xmlns", "jabber:iq:time"); // iq.appendChild(query); // QDateTime local = QDateTime::currentDateTime(); // QDateTime utc = local.addSecs(-getTZOffset() * 3600); // QString str = getTZString(); // query.appendChild(textTag("utc", TS2stamp(utc))); // query.appendChild(textTag("tz", str)); // query.appendChild(textTag("display", QString("%1 %2").arg(local.toString()).arg(str))); // send(iq); // return TRUE; //} else if(ns == "http://jabber.org/protocol/disco#info") { // Find out the node bool invalid_node = false; QString node; bool found; QDomElement q = findSubTag(e, "query", &found); if(found) // NOTE: Should always be true, since a NS was found above node = q.attribute("node"); QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); if (!node.isEmpty()) query.setAttribute("node", node); iq.appendChild(query); // Identity DiscoItem::Identity identity = client()->identity(); QDomElement id = doc()->createElement("identity"); if (!identity.category.isEmpty() && !identity.type.isEmpty()) { id.setAttribute("category",identity.category); id.setAttribute("type",identity.type); if (!identity.name.isEmpty()) { id.setAttribute("name",identity.name); } } else { // Default values id.setAttribute("category","client"); id.setAttribute("type","pc"); } query.appendChild(id); QDomElement feature; if (node.isEmpty() || node == client()->capsNode() + "#" + client()->capsVersion()) { // Standard features feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/bytestreams"); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/si"); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer"); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/disco#info"); query.appendChild(feature); // Client-specific features QStringList clientFeatures = client()->features().list(); for (QStringList::ConstIterator i = clientFeatures.begin(); i != clientFeatures.end(); ++i) { feature = doc()->createElement("feature"); feature.setAttribute("var", *i); query.appendChild(feature); } if (node.isEmpty()) { // Extended features QStringList exts = client()->extensions(); for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) { const QStringList& l = client()->extension(*i).list(); for ( QStringList::ConstIterator j = l.begin(); j != l.end(); ++j ) { feature = doc()->createElement("feature"); feature.setAttribute("var", *j); query.appendChild(feature); } } } } else if (node.startsWith(client()->capsNode() + "#")) { QString ext = node.right(node.length()-client()->capsNode().length()-1); if (client()->extensions().contains(ext)) { const QStringList& l = client()->extension(ext).list(); for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) { feature = doc()->createElement("feature"); feature.setAttribute("var", *it); query.appendChild(feature); } } else { invalid_node = true; } } else { invalid_node = true; } if (!invalid_node) { send(iq); } else { // Create error reply QDomElement error_reply = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); // Copy children for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { error_reply.appendChild(n.cloneNode()); } // Add error QDomElement error = doc()->createElement("error"); error.setAttribute("type","cancel"); error_reply.appendChild(error); QDomElement error_type = doc()->createElement("item-not-found"); error_type.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-stanzas"); error.appendChild(error_type); send(error_reply); } return true; } return false; } //---------------------------------------------------------------------------- // JT_Gateway //---------------------------------------------------------------------------- JT_Gateway::JT_Gateway(Task *parent) :Task(parent) { type = -1; } void JT_Gateway::get(const Jid &jid) { type = 0; v_jid = jid; iq = createIQ(doc(), "get", v_jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:gateway"); iq.appendChild(query); } void JT_Gateway::set(const Jid &jid, const QString &prompt) { type = 1; v_jid = jid; v_prompt = prompt; iq = createIQ(doc(), "set", v_jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:gateway"); iq.appendChild(query); query.appendChild(textTag(doc(), "prompt", v_prompt)); } void JT_Gateway::onGo() { send(iq); } Jid JT_Gateway::jid() const { return v_jid; } QString JT_Gateway::desc() const { return v_desc; } QString JT_Gateway::prompt() const { return v_prompt; } Jid JT_Gateway::translatedJid() const { return v_translatedJid; } bool JT_Gateway::take(const QDomElement &x) { if(!iqVerify(x, v_jid, id())) return false; if(x.attribute("type") == "result") { if(type == 0) { QDomElement query = queryTag(x); bool found; QDomElement tag; tag = findSubTag(query, "desc", &found); if (found) { v_desc = tagContent(tag); } tag = findSubTag(query, "prompt", &found); if (found) { v_prompt = tagContent(tag); } } else { QDomElement query = queryTag(x); bool found; QDomElement tag; tag = findSubTag(query, "jid", &found); if (found) { v_translatedJid = tagContent(tag); } // we used to read 'prompt' in the past // and some gateways still send it tag = findSubTag(query, "prompt", &found); if (found) { v_prompt = tagContent(tag); } } setSuccess(); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_Browse //---------------------------------------------------------------------------- class JT_Browse::Private { public: QDomElement iq; Jid jid; AgentList agentList; AgentItem root; }; JT_Browse::JT_Browse (Task *parent) :Task (parent) { d = new Private; } JT_Browse::~JT_Browse () { delete d; } void JT_Browse::get (const Jid &j) { d->agentList.clear(); d->jid = j; d->iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("item"); query.setAttribute("xmlns", "jabber:iq:browse"); d->iq.appendChild(query); } const AgentList & JT_Browse::agents() const { return d->agentList; } const AgentItem & JT_Browse::root() const { return d->root; } void JT_Browse::onGo () { send(d->iq); } AgentItem JT_Browse::browseHelper (const QDomElement &i) { AgentItem a; if ( i.tagName() == "ns" ) return a; a.setName ( i.attribute("name") ); a.setJid ( i.attribute("jid") ); // there are two types of category/type specification: // // 1. // 2. if ( i.tagName() == "item" || i.tagName() == "query" ) a.setCategory ( i.attribute("category") ); else a.setCategory ( i.tagName() ); a.setType ( i.attribute("type") ); QStringList ns; for(QDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if ( i.tagName() == "ns" ) ns << i.text(); } // For now, conference.jabber.org returns proper namespace only // when browsing individual rooms. So it's a quick client-side fix. if ( !a.features().canGroupchat() && a.category() == "conference" ) ns << "jabber:iq:conference"; a.setFeatures (ns); return a; } bool JT_Browse::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; d->root = browseHelper (i); for(QDomNode nn = i.firstChild(); !nn.isNull(); nn = nn.nextSibling()) { QDomElement e = nn.toElement(); if ( e.isNull() ) continue; if ( e.tagName() == "ns" ) continue; d->agentList += browseHelper (e); } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_DiscoItems //---------------------------------------------------------------------------- class JT_DiscoItems::Private { public: Private() { } QDomElement iq; Jid jid; DiscoList items; }; JT_DiscoItems::JT_DiscoItems(Task *parent) : Task(parent) { d = new Private; } JT_DiscoItems::~JT_DiscoItems() { delete d; } void JT_DiscoItems::get(const DiscoItem &item) { get(item.jid(), item.node()); } void JT_DiscoItems::get (const Jid &j, const QString &node) { d->items.clear(); d->jid = j; d->iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); if ( !node.isEmpty() ) query.setAttribute("node", node); d->iq.appendChild(query); } const DiscoList &JT_DiscoItems::items() const { return d->items; } void JT_DiscoItems::onGo () { send(d->iq); } bool JT_DiscoItems::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if( e.isNull() ) continue; if ( e.tagName() == "item" ) { DiscoItem item; item.setJid ( e.attribute("jid") ); item.setName( e.attribute("name") ); item.setNode( e.attribute("node") ); item.setAction( DiscoItem::string2action(e.attribute("action")) ); d->items.append( item ); } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_DiscoPublish //---------------------------------------------------------------------------- class JT_DiscoPublish::Private { public: Private() { } QDomElement iq; Jid jid; DiscoList list; }; JT_DiscoPublish::JT_DiscoPublish(Task *parent) : Task(parent) { d = new Private; } JT_DiscoPublish::~JT_DiscoPublish() { delete d; } void JT_DiscoPublish::set(const Jid &j, const DiscoList &list) { d->list = list; d->jid = j; d->iq = createIQ(doc(), "set", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); // FIXME: unsure about this //if ( !node.isEmpty() ) // query.setAttribute("node", node); DiscoList::ConstIterator it = list.begin(); for ( ; it != list.end(); ++it) { QDomElement w = doc()->createElement("item"); w.setAttribute("jid", (*it).jid().full()); if ( !(*it).name().isEmpty() ) w.setAttribute("name", (*it).name()); if ( !(*it).node().isEmpty() ) w.setAttribute("node", (*it).node()); w.setAttribute("action", DiscoItem::action2string((*it).action())); query.appendChild( w ); } d->iq.appendChild(query); } void JT_DiscoPublish::onGo () { send(d->iq); } bool JT_DiscoPublish::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { setSuccess(true); } else { setError(x); } return true; } psi-0.14/iris/src/xmpp/xmpp-im/xmpp_ibb.h0000644000175000017500000000727611305557616016441 0ustar janjan/* * ibb.h - Inband bytestream * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef JABBER_IBB_H #define JABBER_IBB_H #include #include #include #include #include "bytestream.h" #include "im.h" namespace XMPP { class Client; class IBBManager; // this is an IBB connection. use it much like a qsocket class IBBConnection : public ByteStream { Q_OBJECT public: enum { ErrRequest, ErrData }; enum { Idle, Requesting, WaitingForAccept, Active }; IBBConnection(IBBManager *); ~IBBConnection(); void connectToJid(const Jid &peer, const QDomElement &comment); void accept(); void close(); int state() const; Jid peer() const; QString streamid() const; QDomElement comment() const; bool isOpen() const; void write(const QByteArray &); QByteArray read(int bytes=0); int bytesAvailable() const; int bytesToWrite() const; signals: void connected(); private slots: void ibb_finished(); void trySend(); private: class Private; Private *d; void reset(bool clear=false); friend class IBBManager; void waitForAccept(const Jid &peer, const QString &sid, const QDomElement &comment, const QString &iq_id); void takeIncomingData(const QByteArray &, bool close); }; typedef QList IBBConnectionList; class IBBManager : public QObject { Q_OBJECT public: IBBManager(Client *); ~IBBManager(); Client *client() const; IBBConnection *takeIncoming(); signals: void incomingReady(); private slots: void ibb_incomingRequest(const Jid &from, const QString &id, const QDomElement &); void ibb_incomingData(const Jid &from, const QString &streamid, const QString &id, const QByteArray &data, bool close); private: class Private; Private *d; QString genKey() const; friend class IBBConnection; IBBConnection *findConnection(const QString &sid, const Jid &peer="") const; QString genUniqueKey() const; void link(IBBConnection *); void unlink(IBBConnection *); void doAccept(IBBConnection *c, const QString &id); void doReject(IBBConnection *c, const QString &id, int, const QString &); }; class JT_IBB : public Task { Q_OBJECT public: enum { ModeRequest, ModeSendData }; JT_IBB(Task *, bool serve=false); ~JT_IBB(); void request(const Jid &, const QDomElement &comment); void sendData(const Jid &, const QString &streamid, const QByteArray &data, bool close); void respondSuccess(const Jid &, const QString &id, const QString &streamid); void respondError(const Jid &, const QString &id, int code, const QString &str); void respondAck(const Jid &to, const QString &id); void onGo(); bool take(const QDomElement &); QString streamid() const; Jid jid() const; int mode() const; signals: void incomingRequest(const Jid &from, const QString &id, const QDomElement &); void incomingData(const Jid &from, const QString &streamid, const QString &id, const QByteArray &data, bool close); private: class Private; Private *d; }; } #endif psi-0.14/iris/src/xmpp/xmpp-im/filetransfer.h0000644000175000017500000001057711305557616017323 0ustar janjan/* * filetransfer.h - File Transfer * Copyright (C) 2004 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_FILETRANSFER_H #define XMPP_FILETRANSFER_H #include "im.h" namespace XMPP { class S5BConnection; struct FTRequest; /*class AbstractFileTransfer { public: // Receive virtual Jid peer() const = 0; virtual QString fileName() const = 0; virtual qlonglong fileSize() const = 0; virtual QString description() const { return ""; } virtual bool rangeSupported() const { return false; } virtual void accept(qlonglong offset=0, qlonglong length=0) = 0; };*/ class FileTransfer : public QObject /*, public AbstractFileTransfer */ { Q_OBJECT public: enum { ErrReject, ErrNeg, ErrConnect, ErrProxy, ErrStream, Err400 }; enum { Idle, Requesting, Connecting, WaitingForAccept, Active }; ~FileTransfer(); FileTransfer *copy() const; void setProxy(const Jid &proxy); // send void sendFile(const Jid &to, const QString &fname, qlonglong size, const QString &desc); qlonglong offset() const; qlonglong length() const; int dataSizeNeeded() const; void writeFileData(const QByteArray &a); // receive Jid peer() const; QString fileName() const; qlonglong fileSize() const; QString description() const; bool rangeSupported() const; void accept(qlonglong offset=0, qlonglong length=0); // both void close(); // reject, or stop sending/receiving S5BConnection *s5bConnection() const; // active link signals: void accepted(); // indicates S5BConnection has started void connected(); void readyRead(const QByteArray &a); void bytesWritten(int); void error(int); private slots: void ft_finished(); void s5b_connected(); void s5b_connectionClosed(); void s5b_readyRead(); void s5b_bytesWritten(int); void s5b_error(int); void doAccept(); private: class Private; Private *d; void reset(); friend class FileTransferManager; FileTransfer(FileTransferManager *, QObject *parent=0); FileTransfer(const FileTransfer& other); void man_waitForAccept(const FTRequest &req); void takeConnection(S5BConnection *c); }; class FileTransferManager : public QObject { Q_OBJECT public: FileTransferManager(Client *); ~FileTransferManager(); bool isActive(const FileTransfer *ft) const; Client *client() const; FileTransfer *createTransfer(); FileTransfer *takeIncoming(); signals: void incomingReady(); private slots: void pft_incoming(const FTRequest &req); private: class Private; Private *d; friend class Client; void s5b_incomingReady(S5BConnection *); friend class FileTransfer; QString link(FileTransfer *); void con_accept(FileTransfer *); void con_reject(FileTransfer *); void unlink(FileTransfer *); }; class JT_FT : public Task { Q_OBJECT public: JT_FT(Task *parent); ~JT_FT(); void request(const Jid &to, const QString &id, const QString &fname, qlonglong size, const QString &desc, const QStringList &streamTypes); qlonglong rangeOffset() const; qlonglong rangeLength() const; QString streamType() const; void onGo(); bool take(const QDomElement &); private: class Private; Private *d; }; struct FTRequest { Jid from; QString iq_id, id; QString fname; qlonglong size; QString desc; bool rangeSupported; QStringList streamTypes; }; class JT_PushFT : public Task { Q_OBJECT public: JT_PushFT(Task *parent); ~JT_PushFT(); void respondSuccess(const Jid &to, const QString &id, qlonglong rangeOffset, qlonglong rangeLength, const QString &streamType); void respondError(const Jid &to, const QString &id, int code, const QString &str); bool take(const QDomElement &); signals: void incoming(const FTRequest &req); }; } #endif psi-0.14/iris/src/xmpp/xmpp-im/xmpp_htmlelement.h0000644000175000017500000000230211305557616020204 0ustar janjan/* * Copyright (C) 2006 Remko Troncon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_HTMLELEMENT_H #define XMPP_HTMLELEMENT_H #include class QString; namespace XMPP { class HTMLElement { public: HTMLElement(); HTMLElement(const QDomElement &body); void setBody(const QDomElement &body); const QDomElement& body() const; QString toString(const QString &rootTagName = "body") const; QString text() const; private: QDomDocument doc_; QDomElement body_; }; } #endif psi-0.14/iris/src/xmpp/xmpp-im/xmpp_ibb.cpp0000644000175000017500000003246311305557616016770 0ustar janjan/* * ibb.cpp - Inband bytestream * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_ibb.h" #include #include "xmpp_xmlcommon.h" #include #include #define IBB_PACKET_SIZE 4096 #define IBB_PACKET_DELAY 0 using namespace XMPP; static int num_conn = 0; static int id_conn = 0; //---------------------------------------------------------------------------- // IBBConnection //---------------------------------------------------------------------------- class IBBConnection::Private { public: Private() {} int state; Jid peer; QString sid; IBBManager *m; JT_IBB *j; QDomElement comment; QString iq_id; int blockSize; QByteArray recvbuf, sendbuf; bool closePending, closing; int id; }; IBBConnection::IBBConnection(IBBManager *m) :ByteStream(m) { d = new Private; d->m = m; d->j = 0; reset(); ++num_conn; d->id = id_conn++; QString dstr; dstr.sprintf("IBBConnection[%d]: constructing, count=%d\n", d->id, num_conn); d->m->client()->debug(dstr); } void IBBConnection::reset(bool clear) { d->m->unlink(this); d->state = Idle; d->closePending = false; d->closing = false; delete d->j; d->j = 0; d->sendbuf.resize(0); if(clear) d->recvbuf.resize(0); } IBBConnection::~IBBConnection() { reset(true); --num_conn; QString dstr; dstr.sprintf("IBBConnection[%d]: destructing, count=%d\n", d->id, num_conn); d->m->client()->debug(dstr); delete d; } void IBBConnection::connectToJid(const Jid &peer, const QDomElement &comment) { close(); reset(true); d->state = Requesting; d->peer = peer; d->comment = comment; QString dstr; dstr.sprintf("IBBConnection[%d]: initiating request to %s\n", d->id, peer.full().toLatin1().data()); d->m->client()->debug(dstr); d->j = new JT_IBB(d->m->client()->rootTask()); connect(d->j, SIGNAL(finished()), SLOT(ibb_finished())); d->j->request(d->peer, comment); d->j->go(true); } void IBBConnection::accept() { if(d->state != WaitingForAccept) return; QString dstr; dstr.sprintf("IBBConnection[%d]: accepting %s [%s]\n", d->id, d->peer.full().toLatin1().data(), d->sid.toLatin1().data()); d->m->client()->debug(dstr); d->m->doAccept(this, d->iq_id); d->state = Active; d->m->link(this); } void IBBConnection::close() { if(d->state == Idle) return; if(d->state == WaitingForAccept) { d->m->doReject(this, d->iq_id, 403, "Rejected"); reset(); return; } QString dstr; dstr.sprintf("IBBConnection[%d]: closing\n", d->id); d->m->client()->debug(dstr); if(d->state == Active) { // if there is data pending to be written, then pend the closing if(bytesToWrite() > 0) { d->closePending = true; trySend(); return; } // send a close packet JT_IBB *j = new JT_IBB(d->m->client()->rootTask()); j->sendData(d->peer, d->sid, QByteArray(), true); j->go(true); } reset(); } int IBBConnection::state() const { return d->state; } Jid IBBConnection::peer() const { return d->peer; } QString IBBConnection::streamid() const { return d->sid; } QDomElement IBBConnection::comment() const { return d->comment; } bool IBBConnection::isOpen() const { if(d->state == Active) return true; else return false; } void IBBConnection::write(const QByteArray &a) { if(d->state != Active || d->closePending || d->closing) return; // append to the end of our send buffer int oldsize = d->sendbuf.size(); d->sendbuf.resize(oldsize + a.size()); memcpy(d->sendbuf.data() + oldsize, a.data(), a.size()); trySend(); } QByteArray IBBConnection::read(int) { // TODO: obey argument QByteArray a = d->recvbuf; d->recvbuf.resize(0); return a; } int IBBConnection::bytesAvailable() const { return d->recvbuf.size(); } int IBBConnection::bytesToWrite() const { return d->sendbuf.size(); } void IBBConnection::waitForAccept(const Jid &peer, const QString &sid, const QDomElement &comment, const QString &iq_id) { close(); reset(true); d->state = WaitingForAccept; d->peer = peer; d->sid = sid; d->comment = comment; d->iq_id = iq_id; } void IBBConnection::takeIncomingData(const QByteArray &a, bool close) { // append to the end of our recv buffer int oldsize = d->recvbuf.size(); d->recvbuf.resize(oldsize + a.size()); memcpy(d->recvbuf.data() + oldsize, a.data(), a.size()); readyRead(); if(close) { reset(); connectionClosed(); } } void IBBConnection::ibb_finished() { JT_IBB *j = d->j; d->j = 0; if(j->success()) { if(j->mode() == JT_IBB::ModeRequest) { d->sid = j->streamid(); QString dstr; dstr.sprintf("IBBConnection[%d]: %s [%s] accepted.\n", d->id, d->peer.full().toLatin1().data(), d->sid.toLatin1().data()); d->m->client()->debug(dstr); d->state = Active; d->m->link(this); connected(); } else { bytesWritten(d->blockSize); if(d->closing) { reset(); delayedCloseFinished(); } if(!d->sendbuf.isEmpty() || d->closePending) QTimer::singleShot(IBB_PACKET_DELAY, this, SLOT(trySend())); } } else { if(j->mode() == JT_IBB::ModeRequest) { QString dstr; dstr.sprintf("IBBConnection[%d]: %s refused.\n", d->id, d->peer.full().toLatin1().data()); d->m->client()->debug(dstr); reset(true); error(ErrRequest); } else { reset(true); error(ErrData); } } } void IBBConnection::trySend() { // if we already have an active task, then don't do anything if(d->j) return; QByteArray a; if(!d->sendbuf.isEmpty()) { // take a chunk if(d->sendbuf.size() < IBB_PACKET_SIZE) a.resize(d->sendbuf.size()); else a.resize(IBB_PACKET_SIZE); memcpy(a.data(), d->sendbuf.data(), a.size()); d->sendbuf.resize(d->sendbuf.size() - a.size()); } bool doClose = false; if(d->sendbuf.isEmpty() && d->closePending) doClose = true; // null operation? if(a.isEmpty() && !doClose) return; printf("IBBConnection[%d]: sending [%d] bytes ", d->id, a.size()); if(doClose) printf("and closing.\n"); else printf("(%d bytes left)\n", d->sendbuf.size()); if(doClose) { d->closePending = false; d->closing = true; } d->blockSize = a.size(); d->j = new JT_IBB(d->m->client()->rootTask()); connect(d->j, SIGNAL(finished()), SLOT(ibb_finished())); d->j->sendData(d->peer, d->sid, a, doClose); d->j->go(true); } //---------------------------------------------------------------------------- // IBBManager //---------------------------------------------------------------------------- class IBBManager::Private { public: Private() {} Client *client; IBBConnectionList activeConns; IBBConnectionList incomingConns; JT_IBB *ibb; }; IBBManager::IBBManager(Client *parent) :QObject(parent) { d = new Private; d->client = parent; d->ibb = new JT_IBB(d->client->rootTask(), true); connect(d->ibb, SIGNAL(incomingRequest(const Jid &, const QString &, const QDomElement &)), SLOT(ibb_incomingRequest(const Jid &, const QString &, const QDomElement &))); connect(d->ibb, SIGNAL(incomingData(const Jid &, const QString &, const QString &, const QByteArray &, bool)), SLOT(ibb_incomingData(const Jid &, const QString &, const QString &, const QByteArray &, bool))); } IBBManager::~IBBManager() { while (!d->incomingConns.isEmpty()) { delete d->incomingConns.takeFirst(); } delete d->ibb; delete d; } Client *IBBManager::client() const { return d->client; } IBBConnection *IBBManager::takeIncoming() { if(d->incomingConns.isEmpty()) return 0; IBBConnection *c = d->incomingConns.takeFirst(); return c; } void IBBManager::ibb_incomingRequest(const Jid &from, const QString &id, const QDomElement &comment) { QString sid = genUniqueKey(); // create a "waiting" connection IBBConnection *c = new IBBConnection(this); c->waitForAccept(from, sid, comment, id); d->incomingConns.append(c); incomingReady(); } void IBBManager::ibb_incomingData(const Jid &from, const QString &streamid, const QString &id, const QByteArray &data, bool close) { IBBConnection *c = findConnection(streamid, from); if(!c) { d->ibb->respondError(from, id, 404, "No such stream"); } else { d->ibb->respondAck(from, id); c->takeIncomingData(data, close); } } QString IBBManager::genKey() const { QString key = "ibb_"; for(int i = 0; i < 4; ++i) { int word = rand() & 0xffff; for(int n = 0; n < 4; ++n) { QString s; s.sprintf("%x", (word >> (n * 4)) & 0xf); key.append(s); } } return key; } QString IBBManager::genUniqueKey() const { // get unused key QString key; while(1) { key = genKey(); if(!findConnection(key)) break; } return key; } void IBBManager::link(IBBConnection *c) { d->activeConns.append(c); } void IBBManager::unlink(IBBConnection *c) { d->activeConns.removeAll(c); } IBBConnection *IBBManager::findConnection(const QString &sid, const Jid &peer) const { foreach(IBBConnection* c, d->activeConns) { if(c->streamid() == sid && (peer.isEmpty() || c->peer().compare(peer)) ) return c; } return 0; } void IBBManager::doAccept(IBBConnection *c, const QString &id) { d->ibb->respondSuccess(c->peer(), id, c->streamid()); } void IBBManager::doReject(IBBConnection *c, const QString &id, int code, const QString &str) { d->ibb->respondError(c->peer(), id, code, str); } //---------------------------------------------------------------------------- // JT_IBB //---------------------------------------------------------------------------- class JT_IBB::Private { public: Private() {} QDomElement iq; int mode; bool serve; Jid to; QString streamid; }; JT_IBB::JT_IBB(Task *parent, bool serve) :Task(parent) { d = new Private; d->serve = serve; } JT_IBB::~JT_IBB() { delete d; } void JT_IBB::request(const Jid &to, const QDomElement &comment) { d->mode = ModeRequest; QDomElement iq; d->to = to; iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/ibb"); iq.appendChild(query); query.appendChild(comment); d->iq = iq; } void JT_IBB::sendData(const Jid &to, const QString &streamid, const QByteArray &a, bool close) { d->mode = ModeSendData; QDomElement iq; d->to = to; iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/ibb"); iq.appendChild(query); query.appendChild(textTag(doc(), "streamid", streamid)); if(!a.isEmpty()) query.appendChild(textTag(doc(), "data", QCA::Base64().arrayToString(a))); if(close) { QDomElement c = doc()->createElement("close"); query.appendChild(c); } d->iq = iq; } void JT_IBB::respondSuccess(const Jid &to, const QString &id, const QString &streamid) { QDomElement iq = createIQ(doc(), "result", to.full(), id); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/ibb"); iq.appendChild(query); query.appendChild(textTag(doc(), "streamid", streamid)); send(iq); } void JT_IBB::respondError(const Jid &to, const QString &id, int code, const QString &str) { QDomElement iq = createIQ(doc(), "error", to.full(), id); QDomElement err = textTag(doc(), "error", str); err.setAttribute("code", QString::number(code)); iq.appendChild(err); send(iq); } void JT_IBB::respondAck(const Jid &to, const QString &id) { QDomElement iq = createIQ(doc(), "result", to.full(), id); send(iq); } void JT_IBB::onGo() { send(d->iq); } bool JT_IBB::take(const QDomElement &e) { if(d->serve) { // must be an iq-set tag if(e.tagName() != "iq" || e.attribute("type") != "set") return false; if(queryNS(e) != "http://jabber.org/protocol/ibb") return false; Jid from(e.attribute("from")); QString id = e.attribute("id"); QDomElement q = queryTag(e); bool found; QDomElement s = findSubTag(q, "streamid", &found); if(!found) { QDomElement comment = findSubTag(q, "comment", &found); incomingRequest(from, id, comment); } else { QString sid = tagContent(s); QByteArray a; bool close = false; s = findSubTag(q, "data", &found); if(found) a = QCA::Base64().stringToArray(tagContent(s)).toByteArray(); s = findSubTag(q, "close", &found); if(found) close = true; incomingData(from, sid, id, a, close); } return true; } else { Jid from(e.attribute("from")); if(e.attribute("id") != id() || !d->to.compare(from)) return false; if(e.attribute("type") == "result") { QDomElement q = queryTag(e); // request if(d->mode == ModeRequest) { bool found; QDomElement s = findSubTag(q, "streamid", &found); if(found) d->streamid = tagContent(s); else d->streamid = ""; setSuccess(); } // sendData else { // thank you for the ack, kind sir setSuccess(); } } else { setError(e); } return true; } } QString JT_IBB::streamid() const { return d->streamid; } Jid JT_IBB::jid() const { return d->to; } int JT_IBB::mode() const { return d->mode; } psi-0.14/iris/src/xmpp/xmpp-im/xmpp_discoinfotask.cpp0000644000175000017500000000676711305557616021104 0ustar janjan/* * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "xmpp_task.h" #include "xmpp/jid/jid.h" #include "xmpp_discoitem.h" #include "xmpp_discoinfotask.h" #include "xmpp_xmlcommon.h" using namespace XMPP; class DiscoInfoTask::Private { public: Private() { } QDomElement iq; Jid jid; QString node; DiscoItem item; }; DiscoInfoTask::DiscoInfoTask(Task *parent) : Task(parent) { d = new Private; } DiscoInfoTask::~DiscoInfoTask() { delete d; } void DiscoInfoTask::get(const DiscoItem &item) { DiscoItem::Identity id; if ( item.identities().count() == 1 ) id = item.identities().first(); get(item.jid(), item.node(), id); } void DiscoInfoTask::get (const Jid &j, const QString &node, DiscoItem::Identity ident) { d->item = DiscoItem(); // clear item d->jid = j; d->node = node; d->iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); if ( !node.isEmpty() ) query.setAttribute("node", node); if ( !ident.category.isEmpty() && !ident.type.isEmpty() ) { QDomElement i = doc()->createElement("item"); i.setAttribute("category", ident.category); i.setAttribute("type", ident.type); if ( !ident.name.isEmpty() ) i.setAttribute("name", ident.name); query.appendChild( i ); } d->iq.appendChild(query); } /** * Original requested jid. * Is here because sometimes the responder does not include this information * in the reply. */ const Jid& DiscoInfoTask::jid() const { return d->jid; } /** * Original requested node. * Is here because sometimes the responder does not include this information * in the reply. */ const QString& DiscoInfoTask::node() const { return d->node; } const DiscoItem &DiscoInfoTask::item() const { return d->item; } void DiscoInfoTask::onGo () { send(d->iq); } bool DiscoInfoTask::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); DiscoItem item; item.setJid( d->jid ); item.setNode( q.attribute("node") ); QStringList features; DiscoItem::Identities identities; for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if( e.isNull() ) continue; if ( e.tagName() == "feature" ) { features << e.attribute("var"); } else if ( e.tagName() == "identity" ) { DiscoItem::Identity id; id.category = e.attribute("category"); id.name = e.attribute("name"); id.type = e.attribute("type"); identities.append( id ); } } item.setFeatures( features ); item.setIdentities( identities ); d->item = item; setSuccess(true); } else { setError(x); } return true; } psi-0.14/iris/src/xmpp/xmpp-im/xmpp_address.h0000644000175000017500000000324311305557616017320 0ustar janjan/* * Copyright (C) 2006 Remko Troncon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef XMPP_ADDRESS_H #define XMPP_ADDRESS_H #include #include "xmpp/jid/jid.h" class QDomElement; namespace XMPP { class Address { public: typedef enum { Unknown, To, Cc, Bcc, ReplyTo, ReplyRoom, NoReply, OriginalFrom, OriginalTo } Type; Address(Type type = Unknown, const Jid& jid = Jid()); Address(const QDomElement&); const Jid& jid() const; const QString& uri() const; const QString& node() const; const QString& desc() const; bool delivered() const; Type type() const; QDomElement toXml(Stanza&) const; void fromXml(const QDomElement& t); void setJid(const Jid &); void setUri(const QString &); void setNode(const QString &); void setDesc(const QString &); void setDelivered(bool); void setType(Type); private: Jid v_jid; QString v_uri, v_node, v_desc; bool v_delivered; Type v_type; }; typedef QList
AddressList; }; #endif psi-0.14/iris/src/xmpp/xmpp-im/xmpp_xmlcommon.h0000644000175000017500000000750211305557616017706 0ustar janjan/* * xmlcommon.h - helper functions for dealing with XML * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef JABBER_XMLCOMMON_H #define JABBER_XMLCOMMON_H #include #include class QDateTime; class QRect; class QSize; class QColor; class QStringList; class XDomNodeList { public: XDomNodeList(); XDomNodeList(const XDomNodeList &from); XDomNodeList(const QDomNodeList &from); ~XDomNodeList(); XDomNodeList & operator=(const XDomNodeList &from); QDomNode at(int index) const { return item(index); } int count() const { return (int)length(); } bool isEmpty() const; QDomNode item(int index) const; uint length() const; int size() const { return (int)length(); } void append(const QDomNode &i); bool operator==(const XDomNodeList &a) const; bool operator!=(const XDomNodeList &a) const { return !operator==(a); } private: QList list; }; QDateTime stamp2TS(const QString &ts); bool stamp2TS(const QString &ts, QDateTime *d); QString TS2stamp(const QDateTime &d); QDomElement textTag(QDomDocument *doc, const QString &name, const QString &content); QString tagContent(const QDomElement &e); QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found); XDomNodeList childElementsByTagNameNS(const QDomElement &e, const QString &nsURI, const QString &localName); QDomElement createIQ(QDomDocument *doc, const QString &type, const QString &to, const QString &id); QDomElement queryTag(const QDomElement &e); QString queryNS(const QDomElement &e); void getErrorFromElement(const QDomElement &e, const QString &baseNS, int *code, QString *str); QDomElement addCorrectNS(const QDomElement &e); namespace XMLHelper { //QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found); bool hasSubTag(const QDomElement &e, const QString &name); QDomElement emptyTag(QDomDocument *doc, const QString &name); QString subTagText(const QDomElement &e, const QString &name); QDomElement textTag(QDomDocument &doc, const QString &name, const QString &content); QDomElement textTag(QDomDocument &doc, const QString &name, int content); QDomElement textTag(QDomDocument &doc, const QString &name, bool content); QDomElement textTag(QDomDocument &doc, const QString &name, QSize &s); QDomElement textTag(QDomDocument &doc, const QString &name, QRect &r); QDomElement stringListToXml(QDomDocument &doc, const QString &name, const QStringList &l); void readEntry(const QDomElement &e, const QString &name, QString *v); void readNumEntry(const QDomElement &e, const QString &name, int *v); void readBoolEntry(const QDomElement &e, const QString &name, bool *v); void readSizeEntry(const QDomElement &e, const QString &name, QSize *v); void readRectEntry(const QDomElement &e, const QString &name, QRect *v); void readColorEntry(const QDomElement &e, const QString &name, QColor *v); void xmlToStringList(const QDomElement &e, const QString &name, QStringList *v); void setBoolAttribute(QDomElement e, const QString &name, bool b); void readBoolAttribute(QDomElement e, const QString &name, bool *v); //QString tagContent(const QDomElement &e); // obsolete; } #endif psi-0.14/iris/src/xmpp/xmpp-im/xmpp_discoitem.cpp0000644000175000017500000000624011305557616020206 0ustar janjan/* * xmpp_discoitem.cpp * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_discoitem.h" using namespace XMPP; class DiscoItem::Private { public: Private() { action = None; } Jid jid; QString name; QString node; Action action; Features features; Identities identities; }; DiscoItem::DiscoItem() { d = new Private; } DiscoItem::DiscoItem(const DiscoItem &from) { d = new Private; *this = from; } DiscoItem & DiscoItem::operator= (const DiscoItem &from) { d->jid = from.d->jid; d->name = from.d->name; d->node = from.d->node; d->action = from.d->action; d->features = from.d->features; d->identities = from.d->identities; return *this; } DiscoItem::~DiscoItem() { delete d; } AgentItem DiscoItem::toAgentItem() const { AgentItem ai; ai.setJid( jid() ); ai.setName( name() ); Identity id; if ( !identities().isEmpty() ) id = identities().first(); ai.setCategory( id.category ); ai.setType( id.type ); ai.setFeatures( d->features ); return ai; } void DiscoItem::fromAgentItem(const AgentItem &ai) { setJid( ai.jid() ); setName( ai.name() ); Identity id; id.category = ai.category(); id.type = ai.type(); id.name = ai.name(); Identities idList; idList << id; setIdentities( idList ); setFeatures( ai.features() ); } const Jid &DiscoItem::jid() const { return d->jid; } void DiscoItem::setJid(const Jid &j) { d->jid = j; } const QString &DiscoItem::name() const { return d->name; } void DiscoItem::setName(const QString &n) { d->name = n; } const QString &DiscoItem::node() const { return d->node; } void DiscoItem::setNode(const QString &n) { d->node = n; } DiscoItem::Action DiscoItem::action() const { return d->action; } void DiscoItem::setAction(Action a) { d->action = a; } const Features &DiscoItem::features() const { return d->features; } void DiscoItem::setFeatures(const Features &f) { d->features = f; } const DiscoItem::Identities &DiscoItem::identities() const { return d->identities; } void DiscoItem::setIdentities(const Identities &i) { d->identities = i; if ( name().isEmpty() && i.count() ) setName( i.first().name ); } DiscoItem::Action DiscoItem::string2action(QString s) { Action a; if ( s == "update" ) a = Update; else if ( s == "remove" ) a = Remove; else a = None; return a; } QString DiscoItem::action2string(Action a) { QString s; if ( a == Update ) s = "update"; else if ( a == Remove ) s = "remove"; else s = QString::null; return s; } psi-0.14/iris/src/xmpp/xmpp-im/xmpp_xdata.h0000644000175000017500000000660611305557616017002 0ustar janjan/* * xmpp_xdata.h - a class for jabber:x:data forms * Copyright (C) 2003-2004 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef XMPPXDATA_H #define XMPPXDATA_H #include #include #include #include #include class QDomElement; class QDomDocument; namespace XMPP { class XData { public: XData(); QString title() const; void setTitle(const QString &); QString instructions() const; void setInstructions(const QString &); enum Type { Data_Form, Data_Result, Data_Submit, Data_Cancel }; Type type() const; void setType(Type); struct ReportField { ReportField() { } ReportField( QString _label, QString _name ) { label = _label; name = _name; } QString label; QString name; }; const QList &report() const; typedef QMap ReportItem; const QList &reportItems() const; void fromXml(const QDomElement &); QDomElement toXml(QDomDocument *, bool submitForm = true) const; bool isValid() const; public: class Field { public: Field(); ~Field(); QString desc() const; void setDesc(const QString &); struct Option { QString label; QString value; }; typedef QList